0

I'm working with jQuery and Ruby on Rails. I have a table that consists of 3 columns including a form element via select box that is using AJAX to submit the result. I want to change the color of a check mark by adding/removing a class from the stylesheet signifying whether or not the user has completed the form to that corresponding row. I can get ALL of the check marks to change when one row is complete but I can't pinpoint the check mark for the row that was complete.

This seems simple (and I thought it was) but it doesn't seem to be working for some reason.

show.html.erb

<div id="container">
 <tr>

  <td>      
    <span class="glyphicon glyphicon-ok incomplete"></span>
    <%= work_set.reps %> x                                  
    <%= work_set.weight %>kg                            
  </td>

  <td>                                      
    <%= form_for object, :format => 'json' do |f| %>                                     
    <%= f.select :column2, options_for_select((0..object.column1).map {|i| [i,i]}, object.column2) %>                                                       
    <% end %>   
  </td>

 </tr>
</div>

application.js

$('#container').on('change', 'select', function(e) {
  var currentTarget = $(e.currentTarget);
  var form = currentTarget.parents('form');

  $.ajax({
    url: form.attr('action'),
    type: 'POST', 
    data: form.serialize(),
    dataType: 'json',
    success: function(xhr, textStatus){

          // NOT WORKING
      $(this).closest('tr').find('span').removeClass('incomplete').addClass('complete');

    }
  });
});

style.css.scss

.glyphicon-ok.incomplete {
  color: #777;
  opacity: 0.5;
  float: left;
}

.glyphicon-ok.complete {
  color: green;
  float: left;
}
BB123
  • 215
  • 3
  • 10

1 Answers1

4

Try changing it to:

currentTarget.closest('tr').find('span').removeClass('incomplete').addClass('complete');

Explanation:

The cause of the problem is that the value of this within your callback function refers to jqXHR object of that ajax call. But, $.ajax method allows you to set the value of this using context option.

  $.ajax({
    url: form.attr('action'),
    type: 'POST', 
    data: form.serialize(),
    dataType: 'json',

    context: e.currentTarget,      // < === HERE ===

    success: function(xhr, textStatus){    
      // Now, `this` refers to `e.currentTarget`
      $(this).closest('tr').find('span').removeClass('incomplete').addClass('complete');
    }
  });

Alternatively, you can refer to a local variable that refers to the DOM element you want. This the first option that is at the top of the answer.

PS. I found this SO answer about this very informative.

Community
  • 1
  • 1
Uzbekjon
  • 11,655
  • 3
  • 37
  • 54
  • Thank you so much! Can I ask why '$(this)' didn't work but 'currentTarget' worked? – BB123 Apr 27 '16 at 17:56
  • @BB123 cuz in jqury documentation https://api.jquery.com/closest/ -> `$( event.target ).closest( "li" )...` – 7urkm3n Apr 27 '16 at 18:02
  • Because, `this` in ajax callback functions refers to `jqXHR` object of that ajax call, not the select DOM element. `$.ajax` method allows you to override the context using `context` option and use `this` to refer to whatever you want. I'll update my answer to show that option as well. – Uzbekjon Apr 27 '16 at 18:06
  • @BB123 added some explanation. – Uzbekjon Apr 27 '16 at 18:16
  • Ah! I see! Thank you for the thorough response, I appreciate that. @Uzbekjon – BB123 Apr 27 '16 at 18:20