We help IT Professionals succeed at work.

Could you point how to refresh data at a Laravel view when data to be presented changes ?

Eduardo Fuerte
on
Hi Experts

Could you point how to refresh data at a Laravel view when data to be presented changes ?

When the page is initially presented it shows all the images.

Then a filter is applied and the collection to be presented is much smaller. The view is called the same way it was for all the images, but the images presented are not actualized.

If the view is started with the data filtered it's correctly presented.

Thanks in advance.
Comment
Watch Question

CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Hey Eduardo,

You have a few choices here, depending on how you've implemented the Filter function.

You could just make another request to the server (effectively re-loading the page). You could make an AJAX call to the server and re-populate the page once you have a response (reduced list of images). You just just use some Javascript to hide the images that don't match the filter.

Will need more info before giving you any specific answers.
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Hi Chris


Still not considering what you posted about relationships at the precedent question.

Here is the data presented when the user opens the view (all the images)

 $vitrinesX = Vitrine
	::with('user_vitrine')
	->ativa()
	->aprovada()
	->global(Auth::user()->tipoparticipante_id)
	->orderBy('id','desc')
	->withCount([
		'user_vitrine as qtdeCurtiu' => function (Builder $query) { $query->where('curtiu', 1); },
	])
	->paginate(6);
	
return view('vitrines.index',compact('vitrinesX', 'vitrine','qtdeCurtiu','qtdeNaoCurtiu','curtiu'));

Open in new window


Then when the user applies the filter, the result of the filtered data showed by info is correct. If I use this right of the start the data presented is OK, indeed just one image.

        $vitrinesX = auth()->user()
            ->vitrines()
            ->with('user_vitrine')
            ->ativa()
            ->aprovada()
            ->global(Auth::user()->tipoparticipante_id)
            ->orderBy('id','desc')
            ->withCount([
                'user_vitrine as qtdeCurtiu' => function(Builder $query) { $query->where('curtiu', 1); },
            ])
            ->paginate(3);

return view('vitrines.index',compact('vitrinesX', 'vitrine','qtdeCurtiu','qtdeNaoCurtiu','curtiu'));

Open in new window


I guess the AJAX code must to run after the Filter button isn't it?

            <div class='col-md-4 pull-right'>
              <div class="btn-group" role="group">
                <button type="button" class="btn btn-primary" onclick="hotsite.vitrine.novo();">
                  <i class="fas fa-video" aria-hidden="true"></i> Todas as Fotos
                </button>
              </div>
            </div>

Open in new window




Vitrine.prototype.minhasfotos = function(){
  $.ajax({
    url: '/vitrine/minhasfotos',
    method: "GET",
    dataType: "html",
    error:function(data){
      hotsite.openModalCustom("Erro", "Erro ao carregar vitrine.", "Entendi", "error");
    },
    success: function(data){
      $('#midiaList').html(data);
    }
  });
}

Open in new window

CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
I can't see a connection between your HTML and you Javascrip. Your HTML is firing a function called novo, but your javascript shows a funcrtion called minhasfotos. What's the connection between the 2.

If you're wanting to update the content after an AJAX call, then your server will need to responsd with only part of the final HTML - not a full page.
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Sorry. I had copyed from the worng place. Here it is:

            <div class='col-md-4 pull-right'>
              <div class="btn-group" role="group">
                <button type="button" class="btn btn-primary" onclick="hotsite.vitrine.minhasfotos();">
                  <i class="fas fa-video" aria-hidden="true"></i> Minhas Fotos
                </button>
              </div>
            </div>

Open in new window



And the controller method that filters the data:

public function minhasFotos(Request $request){

        
        $curtiu = 0;


        $vitrinesX = auth()->user()
            ->vitrines()
            ->with('user_vitrine')
            ->ativa()
            ->aprovada()
            ->global(Auth::user()->tipoparticipante_id)
            ->orderBy('id','desc')
            ->withCount([
                'user_vitrine as qtdeCurtiu' => function(Builder $query) { $query->where('curtiu', 1); },
            ])
            ->paginate(3);
            
                    
        info($vitrinesX);       
        
        return view('vitrines.index',compact('vitrinesX', 'vitrine','qtdeCurtiu','qtdeNaoCurtiu','curtiu'));

    }

Open in new window



And the page part that must to be actualized:
<div class='row'>

    <input type="hidden" id="hdnCurtiu" value="{{$curtiu}}">
    
    <div class="col-md-12 col-sm-12">

            <section class="row">
           
                    @foreach($vitrinesX->chunk(3) as $row)
                    
                        @foreach($row as $vitrine)
      
                      
                           <div class="col-sm-12 col-md-4">
                           
                                @php 
                                
                                    $vitrine->liked_by= $vitrine->user_vitrine->pluck('id');
                                    
                                    $currentUserId = auth()->user()->id;
                                    $hasUserVoted = $vitrine->liked_by->contains($currentUserId); 
                                @endphp
                           
                                <div class="box-noticias">
                                   	<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirVitrine({{$vitrine->id}});' >
                                    <img src="{{ $vitrine->url }}">
            	    			    </a>                    
                                </div> 
                                
                                <p id="like" class="likes" @if (!$hasUserVoted ) onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1, this)" @endif>
                                    <i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu_{{ $vitrine->id }}">{{ $vitrine->qtdeCurtiu }}</span>
                                </p> 
      
                 
                           </div>     
                          
                        @endforeach
                        
                    @endforeach
                      
                                              
            </section>
            
           <div class='col-md-6 pull-right'>
                {{ $vitrinesX->links() }}
            </div> 
            
		</div>

</div>

Open in new window

CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
OK. You will need to make sure that your controller method is only returning the part that you want to update - already rendered. Currently you've got this:

return view('vitrines.index', ...

You need to make sure that that view you return is only the necessary part of the page and that you call render() on it:

return view('partialtemplate',compact('vitrinesX', 'vitrine','qtdeCurtiu','qtdeNaoCurtiu','curtiu'))->render();

Open in new window

Eduardo FuerteDeveloper and Analyst

Author

Commented:
Hi Chris

In my case how to define the partialtemplate (I guess the last code I sent above)?

The data to be shown is correctly retrieved:

 img002
CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Hey Eduardo,

It just a standard blade template, the same as any other, but instead of being a full HTML page, it just contains the HTML that you need (i.e it's just returning a partial bit of HTML)
Eduardo FuerteDeveloper and Analyst

Author

Commented:
If I well understood...

I must to create under \views\layout\

(where the templates remains at my project)

Another layout with the loop part above at the code - and then extend it at the existent view, isn't it?
Eduardo FuerteDeveloper and Analyst

Author

Commented:
I mean

Copy this part of the view:

<div class='row'>

    <input type="hidden" id="hdnCurtiu" value="{{$curtiu}}">
    
    <div class="col-md-12 col-sm-12">

            <section class="row">
           
                    @foreach($vitrinesX->chunk(3) as $row)
                    
                        @foreach($row as $vitrine)
      
                      
                           <div class="col-sm-12 col-md-4">
                           
                                @php 
                                
                                    $vitrine->liked_by= $vitrine->user_vitrine->pluck('id');
                                    
                                    $currentUserId = auth()->user()->id;
                                    $hasUserVoted = $vitrine->liked_by->contains($currentUserId); 
                                @endphp
                           
                                <div class="box-noticias">
                                   	<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirVitrine({{$vitrine->id}});' >
                                    <img src="{{ $vitrine->url }}">
            	    			    </a>                    
                                </div> 
                                
                                <p id="like" class="likes" @if (!$hasUserVoted ) onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1, this)" @endif>
                                    <i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu_{{ $vitrine->id }}">{{ $vitrine->qtdeCurtiu }}</span>
                                </p> 
      
                 
                           </div>     
                          
                        @endforeach
                        
                    @endforeach
                      
                                              
            </section>
            
           <div class='col-md-6 pull-right'>
                {{ $vitrinesX->links() }}
            </div> 
            
		</div>

</div>

Open in new window


to a file   fotos.blade.php  (f.e.)


And then change this code at the actual view with:

@extends('layouts.fotos')

Ans then at the Controller

 return view('fotos',compact('vitrinesX', 'vitrine','qtdeCurtiu','qtdeNaoCurtiu','curtiu'))->render();

Open in new window


Is it correct?
CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Not quite.

You don't need to extend anything - you just need your AJAX request to return only a PART of your HTML view, so just return the fotos template.
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Hard to me to follow what you means...


At Controller

return view('partialview',compact('vitrinesX', 'vitrine','qtdeCurtiu','qtdeNaoCurtiu','curtiu'))->render();

Open in new window


How to define this partialtemplate (where remains the HTML photos) at the code?


The AJAX code:

Vitrine.prototype.minhasfotos = function(){
  $.ajax({
    url: '/vitrine/minhasfotos',
    method: "GET",
    dataType: "html",
    error:function(data){
      hotsite.openModalCustom("Erro", "Erro ao carregar vitrine.", "Entendi", "error");
    },
    success: function(data){
      $('#midiaList').html(data);
    }
  });
}

Open in new window


I couldn't link the parts...
CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019
Commented:
OK.

Create a blade template containing only the HTML that you want to update and give the template a name, such as partialtemplate.blade.php (you can call it whateveryoulike.blade.php). Content would be something like the following:

<div class='row'>

    <input type="hidden" id="hdnCurtiu" value="{{$curtiu}}">
    
    <div class="col-md-12 col-sm-12">

            <section class="row">
           
                    @foreach($vitrinesX->chunk(3) as $row)
                    
                        @foreach($row as $vitrine)
      
                      
                           <div class="col-sm-12 col-md-4">
                           
                                @php 
                                
                                    $vitrine->liked_by= $vitrine->user_vitrine->pluck('id');
                                    
                                    $currentUserId = auth()->user()->id;
                                    $hasUserVoted = $vitrine->liked_by->contains($currentUserId); 
                                @endphp
                           
                                <div class="box-noticias">
                                   	<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirVitrine({{$vitrine->id}});' >
                                    <img src="{{ $vitrine->url }}">
            	    			    </a>                    
                                </div> 
                                
                                <p id="like" class="likes" @if (!$hasUserVoted ) onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1, this)" @endif>
                                    <i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu_{{ $vitrine->id }}">{{ $vitrine->qtdeCurtiu }}</span>
                                </p> 
      
                 
                           </div>     
                          
                        @endforeach
                        
                    @endforeach
                      
                                              
            </section>
            
           <div class='col-md-6 pull-right'>
                {{ $vitrinesX->links() }}
            </div> 
            
		</div>

</div>

Open in new window

Now look at your Javascript:

Vitrine.prototype.minhasfotos = function(){
  $.ajax({
    url: '/vitrine/minhasfotos',
    method: "GET",
    dataType: "html",
    error:function(data){
      hotsite.openModalCustom("Erro", "Erro ao carregar vitrine.", "Entendi", "error");
    },
    success: function(data){
      $('#midiaList').html(data);
    }
  });
}

Open in new window

Whenever the minhasfotos() function is called. your script will make an AJAX request to /vitrine/minhasfotos. Whatever is returned from that URL (controller method) will be passed to the data variable of the success handler, and that content will be placed inside the #midiaList element. So you just need to make sure that what gets returned from your controller to your AJAX success handler is just the bit of html that should go into the #midiaList element - and then your controller method looks like this:

return view('partialtemplate',compact('vitrinesX', 'vitrine','qtdeCurtiu','qtdeNaoCurtiu','curtiu'))->render();

We don't want to send a full HTML page (with headers etc). We only want to send the bit that changes - hence creating a view that just contains a partial page and returning that.

Does that makes sense ?
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Hi Chris


It makes all the sense.

It's just a matter of to use an @include.

I just created another view called:  fotos.blade.php  with the content of the foreach etc. above.

Then changes on the view:

  <div class='row'>
    <div id="midiaList">
      @include('vitrines.fotos')
    </div>
  </div>

Open in new window


And at the Controller:
return view('vitrines.fotos',compact('vitrinesX','curtiu'))->render();

Open in new window


And so... now it's running!
CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Excellent. So now when your page first runs it will include the vitrines.fotos template, and then when your AJAX call is made, it will reload just that template and replace the content on #midiaList.

Good stuff :)
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Chris

Thank you for another very elucidative solution!

My Laravel's knowledge is growing thanks for your help...Sometimes I feel Laravel as "another PHP" inside PHP...
CERTIFIED EXPERT
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Haha - I know what you mean. It certainly has some quirks but when it makes sense, it's much easier to develop applications. It uses fairly modern design patterns to do the jon, and these design patterns are often very different from how many developers are used to writing code.

At it's core, it take an Object Oriented Programming (OOP) approach. If you understand how OOP development works, then using Laravel will make much more sense. OOP is not specific to any language - it's just a concept on how to program, so if you have some spare time, it might help to read up a little about the concepts behind OOP.

Good luck with it

Explore More ContentExplore courses, solutions, and other research materials related to this topic.