AnthonyGalli.com AnthonyGalli.com - 7 months ago 23
Javascript Question

removeClass if addClass clicked?

If a new ranking is clicked how can we automatically declick the previous click?

<%= f.hidden_field(:ranking, id: 'ranking') %>
<%= image_tag('4.png', data: { ranking: 4 }, class: 'image-clicker') %>
<%= image_tag('3.png', data: { ranking: 3 }, class: 'image-clicker') %>
<%= image_tag('2.png', data: { ranking: 2 }, class: 'image-clicker') %>
<%= image_tag('1.png', data: { ranking: 1 }, class: 'image-clicker') %>

<script>
$('.image-clicker').click(function() {
$('#ranking').val($(this).data('ranking'));
if ($('#ranking').hasClass('clicked')){ #Conditional doesn't work. If user clicks on second image the first image will stay clicked
$('.clicked').removeClass('clicked')
}else{
$(this).addClass('clicked');
}
});
</script>


I tried to incorporate the answers from here: removeClass() if it exists, but they didn't work for me.

Answer

The 'click' event is assigned to your 'image-clicker' elements, but the 'clicked' class is added to the hidden field. The element references are mixed up, and the code needs to check to see if the image has already been clicked.

This might be closer to what you're trying to do:

<script>
  $('.image-clicker').click(function() {
    $('#ranking').val($(this).data('ranking'));
    var already_clicked = $(this).hasClass('clicked');
    $('.clicked').removeClass('clicked')
    if (!already_clicked) {
      $(this).addClass('clicked');
    }
  });
</script>

The already_clicked check determines if the image is already clicked, so that it can tell whether to keep click it after clearing the existing 'clicked' classes from the other images.

Note that this will allow all images to become 'unclicked'. If you want this to behave like radio buttons, you can leave out the check for already_clicked and always add the 'clicked' class to the element that was clicked. This will do that:

<script>
  $('.image-clicker').click(function() {
    $('#ranking').val($(this).data('ranking'));
    $('.clicked').removeClass('clicked')
    $(this).addClass('clicked');
  });
</script>

In this case, you'll likely also want to start your radio buttons in a known state. In the original markup (ERB), you would want to add the 'clicked' class to one of the image_tag elements. You simply have to add the 'clicked' class to one of the images at creation time, like so:

<%= f.hidden_field(:ranking, id: 'ranking') %>
<%= image_tag('4.png', data: { ranking: 4 }, class: 'image-clicker clicked']) %>
<%= image_tag('3.png', data: { ranking: 3 }, class: 'image-clicker') %>
<%= image_tag('2.png', data: { ranking: 2 }, class: 'image-clicker') %>
<%= image_tag('1.png', data: { ranking: 1 }, class: 'image-clicker') %>

You can also do this dynamically, based on the value of a variable or field from your model. Assuming that a variable named ranking contains this value, consider this initialization code:

<%= f.hidden_field(:ranking, id: 'ranking') %>
<%= image_tag('4.png', data: { ranking: 4 }, class: 'image-clicker' + (ranking == '4' ? ' clicked' : '')) %>
<%= image_tag('3.png', data: { ranking: 3 }, class: 'image-clicker' + (ranking == '3' ? ' clicked' : '')) %>
<%= image_tag('2.png', data: { ranking: 2 }, class: 'image-clicker' + (ranking == '2' ? ' clicked' : '')) %>
<%= image_tag('1.png', data: { ranking: 1 }, class: 'image-clicker' + (ranking == '1' ? ' clicked' : '')) %>