We help IT Professionals succeed at work.

Could you point why this Laravel view code doesn't correctly actualize the icons like/ dislike on the correct position after click?

Eduardo Fuerte
on
Hi Experts

Could you point why this Laravel view code doesn't correctly actualize the icons like/ dislike on the correct position after click?

Accordingly with:
 img004
Even clicking on the 2nd or 3rd like/ dislike icons only the count at the icon side of the 1st picture are (incorrectly) actualized.

The views code:
@extends('layouts.appinterno')

@section('content')

	{{ csrf_field() }}
	<input type="hidden" id="hdnCurtiu" value="{{ $curtiu }}">


  	  	<!--div class="col-xs-12 col-sm-4 col-md-4"-->
        <div class="col-md-10 col-sm-12">
		    <p class="titResumoNoticia">Arquivo de Fotos</p>
		   
   
            @foreach($vitrinesX as $vitrine)

                <section class="row">
        
        
                        <div class="col-sm-12 col-md-4">
                            <div class="box-noticias">
                               	<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirNoticia({{$vitrine->id}});' >
        	    				{{$vitrine->titulo}}
        	    			    </a>                    
                            </div>
                            
                            	<p id="like" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)">
				                    <i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu">{{ $qtdeCurtiu }}</span>
				               	</p>   
                                    
           						<p id="dislike" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 0)">
				                    <i class="fa fa-thumbs-down"></i> <span id="qtdeNaoCurtiu">{{ $qtdeNaoCurtiu }}</span>
						       </p>       
                        </div>    
                               
                        @if($loop->last)
                            @break
                        @else
                            @continue 
                        @endif       
                               
                               
                               

                        <div class="col-sm-12 col-md-4">
                            <div class="box-noticias">
                               	<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirNoticia({{$vitrine->id}});' >
        	    				{{$vitrine->titulo}}
        	    			    </a>                    
                            </div>
                            	
                                <p id="like" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)">
				                    <i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu">{{ $qtdeCurtiu }}</span>
				               	</p>    
           						
                                <p id="dislike" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 0)">
				                    <i class="fa fa-thumbs-down"></i> <span id="qtdeNaoCurtiu">{{ $qtdeNaoCurtiu }}</span>
						       </p>
                                
                        </div>    
                     
                     
                        @if($loop->last)
                            @break
                        @else
                            @continue 
                        @endif       
                               
                     
                        <div class="col-sm-12 col-md-4">
                            <div class="box-noticias">
                               	<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirNoticia({{$vitrine->id}});' >
        	    				{{$vitrine->titulo}}
        	    			    </a>                    
                            </div>
                            	
                                <p id="like" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)">
				                    <i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu">{{ $qtdeCurtiu }}</span>
				               	</p>    
                                
               					<p id="dislike" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 0)">
				                    <i class="fa fa-thumbs-down"></i> <span id="qtdeNaoCurtiu">{{ $qtdeNaoCurtiu }}</span>
						       </p>                
      
                        </div>    
     

                </section>
            
  
            @endforeach
			</div>

	</div>
@endsection

@section('scripts')
	<script src="{{ asset('js/hotsite/Hotsite.Formatadores.js').'?v='.md5(uniqid()) }}" ></script>
	<script src="{{ asset('js/hotsite/hotsite.Vitrine.js').'?v='.md5(uniqid()) }}" ></script>

	<script>
		$(document).ready(function() {
			if($('#hdnCurtiu').val() == "1")
				$('#like').addClass('like');
			else if($('#hdnCurtiu').val() == "0")
				$('#dislike').addClass('like');
		})
	</script>
@endsection

Open in new window


The table is correctly actualized after the likes / dislikes, just not to correctly appear.

Thanks in advance.
Comment
Watch Question

Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Hey Eduardo,

Not sure why, but it's probably got something to do with your ID. In HTML, and ID has to be unique - you can't have 2 elements with the same ID. All of your Like buttons have the same ID - 'like'.

You're also passing exactly the same value to each of your Javascript functions:

onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)">

$vitrine->id is the same across all of your calls.
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Hi Chris

That's my doubt.
Since the code is inside a Laravel's loop - doesn't the $vitrine->id  is been automatically actualized?

If not, could you suggest how to deals with?
Eduardo FuerteDeveloper and Analyst

Author

Commented:
One evidence that the loop is taking effect is that
{{$vitrine->titulo}}

It's correspondently the same as {{ $vitrine->id }} are

And the tituulo (titles) are changing, accordingly with the picture
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Hi Eduardo

In your code, you're looping through $vitrines. Inside the loop, you have code for 3 columns, but you also have code that either calls break or continue. This means that the last 2 columns of your code are never executed, so there's no need for them. You just need one, so remove the other 2.

Also, in your jQuery, you have this:

$(document).ready(function() {
    if($('#hdnCurtiu').val() == "1")
        $('#like').addClass('like');
    else if($('#hdnCurtiu').val() == "0")
        $('#dislike').addClass('like');
});

Open in new window

In that code, you're checking the value of an element with an ID of #hdnCurtiu and adding a class to elements with IDs of #like or #dislike.

Like I said above, IDs in HTML need to be unique. You're creating elements with those IDs inside your loop, so you have several elements with the same ID (like / dislike). That jQuery code will only ever find the first element that matches the ID which is why you're only getting the first like/dislike buttons to work.

It might be easier to set you classes directly in code instead of with jQuery. Something like this:

// For the like link
<p class="likes {{ $curtiu == '1' ? 'like' : '' }}" onclick...

// For the dislike link
<p class="likes {{ $curtiu == '0' ? 'like' : '' }}" onclick...

Open in new window

Eduardo FuerteDeveloper and Analyst

Author

Commented:
Hi Chris


Adjusting the way you suggested I don't know if correctly, I get:


@extends('layouts.appinterno')

@section('content')

	<header>
		<br/>
		Vitrines XXX
		<br/><br/>
	</header>
	

	<div class='row'>
	<!--style>
		.noticias-body {
			margin-left: 45px;
		}

		.noticias-body img {
			width: 100%;
		}

		.noticias-visualizacao{
			position: relative;
			display: inline-block;
		}
		.noticias-image{
			/* position: absolute; */
			/* display: inline-block; */
			float: left;
			clear: left;
			margin: 2rem;
		}
	</style-->

	{{ csrf_field() }}
	
	
	
<!--input type="hidden" id="hdnCurtiu" value="{{ $curtiu }}"-->


        <div class="col-md-10 col-sm-12">
		    <p class="titResumoNoticia">Arquivo de Fotos</p>
		   
     
            
            @foreach($vitrinesX as $vitrine)


                <section class="row">
        
        
                        <div class="col-sm-12 col-md-4">
                            <div class="box-noticias">
                               	<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirNoticia({{$vitrine->id}});' >
        	    				{{$vitrine->titulo}}
        	    			    </a>                    
                            </div>
                            
                            	<!--p id="like" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)"-->
                                <p class="likes {{ $curtiu == 1 ? 'like' : '' }}" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)">
				                    <i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu">{{ $qtdeCurtiu }}</span>
				               	</p>   
                                    
           						
								<!--p id="dislike" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 0)"-->
                                <p class="likes {{ $curtiu == 0 ? 'like' : '' }}" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 0)">
				                    <i class="fa fa-thumbs-down"></i> <span id="qtdeNaoCurtiu">{{ $qtdeNaoCurtiu }}</span>
						       </p>       
                        </div>    
                               
                      
                       
                        @if($loop->last)
                            @break
                        @else
                            @continue 
                        @endif      
 

                </section>
            
  
            @endforeach
			</div>

	</div>
@endsection

<!--
@section('scripts')
	<script src="{{ asset('js/hotsite/Hotsite.Formatadores.js').'?v='.md5(uniqid()) }}" ></script>
	<script src="{{ asset('js/hotsite/hotsite.Vitrine.js').'?v='.md5(uniqid()) }}" ></script>

	<script>
		$(document).ready(function() {
			if($('#hdnCurtiu').val() == "1")
				$('#like').addClass('like');
			else if($('#hdnCurtiu').val() == "0")
				$('#dislike').addClass('like');
		})
	</script>
@endsection
-->

Open in new window


The id(s) are correctly captured but still not actualizing the likes/ dislikes of 2nd/3rd/... pictures.
 img001
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Hey Eduardo,

You've still got duplicate IDs in your code. Take a look at the <span> that wraps the number of likes and dislikes:

<i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu">{{ $qtdeCurtiu }}</span>
<i class="fa fa-thumbs-down"></i> <span id="qtdeNaoCurtiu">{{ $qtdeNaoCurtiu }}</span>

They both have an ID, so when you loop through your data, you will have several <span> elements with the same ID. If the code that updates that number looks for that ID, it will only ever find the first one. IDs HAVE to be unique for this to work properly.

I suspect you'll need to change or remove those IDs and then edit your Javascript code to make sure the correct number is being updated.
Eduardo FuerteDeveloper and Analyst

Author

Commented:
You means dinamically changes the id?

Remove the  id="qtdeCurtiu" ?


If you see the console at the picture the values received on JS code is correctly assigned to the picture. Just the counting is done just for the first.

JS code:

Vitrine.prototype.salvarEscolha = function(vitrine_id, curtiu) {
    
//---------------------------------------
    // Foto id
    console.log(vitrine_id);   

   // Like or dislike
    console.log(curtiu);

//-----------------------------------------
    
  $.ajax({
    url: "/vitrine/salvarescolha",
    data: {
      _token: $('input[name="_token"]').val(),
      vitrine_id: vitrine_id,
      curtiu: curtiu
    },
    method: "POST",
    dataType: "json",
    error: function() {
      hotsite.openModalCustom(
        "Erro",
        "Erro ao salvar a escolha.",
        "Entendi",
        "error"
      );
    },
    success: function(data) {
      var qtdeCurtiu = parseInt($("#qtdeCurtiu").html());
      var qtdeNaoCurtiu = parseInt($("#qtdeNaoCurtiu").html());

      if (curtiu == 1) {
        $("#qtdeCurtiu").html(qtdeCurtiu + 1);

        if (qtdeNaoCurtiu > 0) $("#qtdeNaoCurtiu").html(qtdeNaoCurtiu - 1);

        $("#like").addClass("like");
        $("#dislike").removeClass("like");
      } else {
        if (qtdeCurtiu > 0) $("#qtdeCurtiu").html(qtdeCurtiu - 1);

        $("#qtdeNaoCurtiu").html(qtdeNaoCurtiu + 1);

        $("#like").removeClass("like");
        $("#dislike").addClass("like");
      }
    }
  });
};

Open in new window

Most Valuable Expert 2018
Distinguished Expert 2019
Commented:
Yeah - that's because you have duplicate IDs in your HTML.

In your HTML, once your page has rendered you will have code that looks something like this:

<i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu">5</span>

That piece of code will be repeated several times, depending on how many times your foreach runs. Now if you look at that, you'll see that it has an ID of #qtdeCurtiu. That's several elements with exactly the same ID, which you can't have.

Now look at your Javascript. You have code like this:

var qtdeCurtiu = parseInt($("#qtdeCurtiu").html());

if (curtiu == 1) {
    $("#qtdeCurtiu").html(qtdeCurtiu + 1);

Open in new window

That will only ever update the FIRST element it finds with that ID. It will NEVER update elements after the first one. You just can't have the same ID more than once in your code.

You will have to edit your HTML (Blade template) and your Javascript to make it work without using duplicate IDs. Probably the easiest option is to use the $vitrine->id in your element IDs, so in your blade template, use this:

<span id="qtdeCurtiu_{{ $vitrine->id }}">{{ $qtdeCurtiu }}</span>
<span id="qtdeNaoCurtiu_{{ $vitrine->id }}">{{ $qtdeNaoCurtiu }}</span>

Now your <span> elements won't have the same IDs - they'll all be unique.

You then need to change your Javascript to use those IDs:

var qtdeCurtiu = parseInt($("#qtdeCurtiu_" + vitrine_id).html());
var qtdeNaoCurtiu = parseInt($("#qtdeNaoCurtiu_" + vitrine_id).html());

$("#qtdeCurtiu_" + vitrine_id).html(qtdeCurtiu + 1);
...

Open in new window

Eduardo FuerteDeveloper and Analyst

Author

Commented:

After adaptations:

 
 

Produced:



The controller code:

public function salvarEscolha(Request $request){ 
 
 
      $vitrine_id = $request->input('vitrine_id'); 
      $curtiu = $request->input('curtiu'); 
 
      $mUserVitrine = new UserVitrine(); 
    
      $userVitrine = $mUserVitrine->obter(Auth::user()->id, $vitrine_id); 
 
 
      if(empty($userVitrine)){ 
        $userVitrine = new UserVitrine(); 
        $userVitrine->user_id = Auth::user()->id; 
        $userVitrine->vitrine_id = $vitrine_id; 
        $userVitrine->created_at = Carbon::now(); 
      } 
 
 
 
      $userVitrine->curtiu = $curtiu; 
      $userVitrine->updated_at = Carbon::now(); 
      $userVitrine->save(); 
 
      return response()->json(new Resultado(true, 'Sucesso', null), 200); 
    }
Eduardo FuerteDeveloper and Analyst

Author

Commented:
The first part of code above was not ok.


JS Code:

Vitrine.prototype.salvarEscolha = function(vitrine_id, curtiu) {
    
    // EF 2020
    
    console.log(vitrine_id);
    console.log(curtiu);
    
  $.ajax({
    url: "/vitrine/salvarescolha",
    data: {
      _token: $('input[name="_token"]').val(),
      vitrine_id: vitrine_id,
      curtiu: curtiu
    },
    method: "POST",
    dataType: "json",
    error: function() {
      hotsite.openModalCustom(
        "Erro",
        "Erro ao salvar a escolha.",
        "Entendi",
        "error"
      );
    },
    success: function(data) {
        
        
      //var qtdeCurtiu = parseInt($("#qtdeCurtiu").html());
      //var qtdeNaoCurtiu = parseInt($("#qtdeNaoCurtiu").html());
      
      var qtdeCurtiu = parseInt($("#qtdeCurtiu_" + vitrine_id).html());
      var qtdeNaoCurtiu = parseInt($("#qtdeNaoCurtiu_" + vitrine_id).html());
      
      console.log(qtdeCurtiu);
      console.log(qtdeNaoCurtiu);

      if (curtiu == 1) {
        $("#qtdeCurtiu").html(qtdeCurtiu + 1);

        if (qtdeNaoCurtiu > 0) $("#qtdeNaoCurtiu").html(qtdeNaoCurtiu - 1);

        $("#like").addClass("like");
        $("#dislike").removeClass("like");
      } else {
        if (qtdeCurtiu > 0) $("#qtdeCurtiu").html(qtdeCurtiu - 1);

        $("#qtdeNaoCurtiu").html(qtdeNaoCurtiu + 1);

        $("#like").removeClass("like");
        $("#dislike").addClass("like");
      }
    }
  });
};

Open in new window


Page code::
 @foreach($vitrinesX as $vitrine)

	<section class="row">

				   
				   
			<div class="col-sm-12 col-md-4">
				<div class="box-noticias">
					<a href="javascript:void(0);" onclick='hotsite.vitrine.abrirNoticia({{$vitrine->id}});' >
					{{$vitrine->titulo}}
					</a>                    
				</div>
				
					<p id="like" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)">
					<!--p class="likes {{ $curtiu == 1 ? 'like' : '' }}" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 1)"-->
						<i class="fa fa-thumbs-up"></i> <span id="qtdeCurtiu_{{ $vitrine->id }}">{{ $qtdeCurtiu }}</span>
					</p>   
						
					<p id="dislike" class="likes" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 0)">
					<!--p class="likes {{ $curtiu == 0 ? 'like' : '' }}" onclick="hotsite.vitrine.salvarEscolha({{ $vitrine->id }}, 0)"-->
						<i class="fa fa-thumbs-down"></i> <span id="qtdeNaoCurtiu_{{ $vitrine->id }}">{{ $qtdeNaoCurtiu }}</span>
				   </p>       
			</div>           
				   
   
		   
			@if($loop->last)
				@break
			@else
				@continue 
			@endif      
				  

	</section>


@endforeach

Open in new window

Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
You're still referring to the old IDs in your Javascript code:

if (qtdeNaoCurtiu > 0) $("#qtdeNaoCurtiu").html(qtdeNaoCurtiu - 1);
    $("#like").addClass("like");
    $("#dislike").removeClass("like");
} else {
    if (qtdeCurtiu > 0) $("#qtdeCurtiu").html(qtdeCurtiu - 1);
    $("#qtdeNaoCurtiu").html(qtdeNaoCurtiu + 1);

Anywhere these ID are used in your Javascript, you need to add the vitrine_id to them:

if (qtdeNaoCurtiu > 0) $("#qtdeNaoCurtiu_" + vitrine_id).html(qtdeNaoCurtiu - 1);
    $("#like").addClass("like");
    $("#dislike").removeClass("like");
} else {
    if (qtdeCurtiu > 0) $("#qtdeCurtiu_" + vitrine_id).html(qtdeCurtiu - 1);
    $("#qtdeNaoCurtiu_" + vitrine_id).html(qtdeNaoCurtiu + 1);
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Yes....

Now it's working!!!
img003
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
Excellent news.

We got there in the end :)
Eduardo FuerteDeveloper and Analyst

Author

Commented:
Chris

Thank you very much for one more excelent help!!!
Most Valuable Expert 2018
Distinguished Expert 2019

Commented:
You're welcome Eduardo