2

I'm attempting to change an icon based on a result from clicking on the previous icon.

Here is my code:

$(document).on('click','.switchButton', function(){
     $(this).attr('data-prefix', 'fas').attr('data-icon', 'spinner').addClass('fa-pulse');
     $.ajax({
        url: 'tasks/update_table.php',
        type: 'post',
        data: { "uid": $(this).attr('data-uid')},
        success: function(response) { 
            if(response == 1) {
                $(this).attr('data-prefix', 'far').attr('data-icon', 'check-square');
            } else {
                $(this).attr('data-prefix', 'fas').attr('data-icon', 'check-square');
            }
        }
    });
});

The icon is initially on the page by:

<i data-uid="<?=$task['uid'];?>" class="far fa-square fa-lg switchButton"></i>

When a user clicks this icon, an ajax request is sent to a php script that will update a boolean variable in a table, and return the truthy value of if the boolean is true or not (0 or 1).

When the icon is clicked initially, the icon is switched to a spinner icon which is done by the first like mentioning $(this), once the request gets to the success function, it should change the icon again based on the response given, but it does not work. There is simply no update to the page. I assume this is is a scope issue, but reading various articles about this and doing some research I haven't been able to find a way to fix it. It certainly doesn't help that I don't actually know if it is a scope issue or not.

how can I update these icons inside the success function?

Sajib Khan
  • 22,878
  • 9
  • 63
  • 73
GrumpyCrouton
  • 8,486
  • 7
  • 32
  • 71

3 Answers3

6

The $.ajax method supports passing a context property which will become the value of this inside the callback:

$.ajax({
    context: this,
    success: function(response) {
        // this === context here
    },
    ...
});
Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • What do you get if you `console.log(this)` inside that callback? – Alnitak Mar 13 '18 at 16:51
  • When I do that, I get the element as it was before the edit. I have the log before the attr's are changed. This is the return: https://pastebin.com/7XscRA4y (Put it on pastebin because formatting in comments would look screwy) – GrumpyCrouton Mar 13 '18 at 16:55
  • Your problem is elsewhere, and very likely unrelated to the specific question you asked here (which is how to make `this` in the callback refer to the correct element) – Alnitak Mar 13 '18 at 16:57
5

Save the this context by const that = this before $.ajax call. Then inside the success() just use that instead of this.

$(document).on('click','.switchButton', function(){
 $(this).attr('data-prefix', 'fas').attr('data-icon', 'spinner').addClass('fa-pulse');

 const that = this; // save 

 $.ajax({
    url: 'tasks/update_table.php',
    type: 'post',
    data: { "uid": $(this).attr('data-uid')},
    success: function(response) { 
        if(response == 1) {
            $(that).attr('data-prefix', 'far').attr('data-icon', 'check-square');
        } else {
            $(that).attr('data-prefix', 'fas').attr('data-icon', 'check-square');
        }
    }
  });
});
Sajib Khan
  • 22,878
  • 9
  • 63
  • 73
  • there's no need - jQuery can do this for you – Alnitak Mar 13 '18 at 16:14
  • or if you prefer variables - `var $this = $(this)` – treyBake Mar 13 '18 at 16:15
  • @Alnitak - true but defining this outside means use throughout the function, no t just within the ajax call – treyBake Mar 13 '18 at 16:16
  • @ThisGuyHasTwoThumbs that's a separate problem. The OP specifically wanted the context within the `success` callback. Your `$this = $(this)` would be preferable to `that = this`, though. – Alnitak Mar 13 '18 at 16:17
  • 1
    @Alnitak yes the method has a way to do this, but this approach also works. No reason to get worked up over it. Either way it's literally one line difference in code. Also this approach would work if a user wanted to use arrow functions for the callbacks. – Taplar Mar 13 '18 at 16:17
  • @Alnitak true, but like taplar said, no reason to get worked up, I prefer this method due to the fact you can use `$this` throughout the function :) – treyBake Mar 13 '18 at 16:19
  • re: "`this` refers to the jqXHR object" - the documentation disagrees: _"By default, the context is an object that represents the Ajax settings used in the call (`$.ajaxSettings` merged with the settings passed to `$.ajax`)"_ – Alnitak Mar 13 '18 at 16:25
  • They're not the same thing. – Alnitak Mar 13 '18 at 16:41
  • Edited, and removed the comments. Thanks @Alnitak – Sajib Khan Mar 13 '18 at 16:43
  • This doesn't seem to be working for me, the icon is still not changed – GrumpyCrouton Mar 13 '18 at 16:51
  • Do you see any error in browser console? maybe better if you can provide any JSFiddle link. – Sajib Khan Mar 13 '18 at 16:59
  • It is more common tot immediately wrap the variable in a jQuery object rather than doing so whenever you use it. Your way kind if defeats the purpose of caching the variable. Instead, use `const that = $(this)`. – Bram Vanroy Mar 14 '18 at 07:28
-1

$(this) will not availbe after ajax response. You need to make variable and store the current elm. Then triger as you need after ajax call.

Daniel Smith
  • 1,626
  • 3
  • 29
  • 59