9

The following code refers to a component function which fetches data from an url and tries to set that data to a property. It's not working, seems like this is not accessible form the ajax clousure scope.

var MyComp = Vue.extend({
props: {
        html_prop: {}
        ....
},
methods: {
        fetchCondiciones: function(url){

            $.ajax({
                    type: "GET",
                    url: url,
                    cache: false,
                    data: vardata ,
                    success: function(data,status,error) {
                        if( data!=''){
                            this.html_prop = data;
                        }
                    },
                    error: function(data,status,error){
                        alert(error);
                    }
            });

        }

        ...
    }
})

How could I make this accessible?

4 Answers 4

18

You need to .bind the this context, as the callback is not naturally called in the context of the component:

var MyComp = Vue.extend({
props: {
        html_prop: null,
},
        // ....
        fetchCondiciones: function(url){

            $.ajax({
                    type: "GET",
                    url: url,
                    cache: false,
                    data: vardata,
                    success: function(data,status,error) {
                        if(data != ''){
                            this.html_prop = data;
                        }
                    }.bind(this), // bind this here
                    error: function(data,status,error){
                        alert(error);
                    }.bind(this) // bind this here
            });

        }

        // ...
});

You can learn more about .bind and this here: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

Sign up to request clarification or add additional context in comments.

Comments

14

As already answered, .bind will fix the issue on this, however, I like to use a different approach, and store this in a variable before any Ajax calls or nested functions. Very helpful when your code grows inside the method. It is also easier to read.

You can save this to a var called self for example. Then use self anywhere inside that method without a problem.

var MyComp = Vue.extend({
props: {
    html_prop: null,
},
    // ....
    fetchCondiciones: function(url){

        var self = this;

        $.ajax({
                type: "GET",
                url: url,
                cache: false,
                data: vardata,
                success: function(data,status,error) {
                    if(data != ''){
                        self.html_prop = data;
                    }
                }
                error: function(data,status,error){
                    alert(error);
                }
        });

    }

    // ...
});

UPDATE:

Today we could just use ES6 arrow function syntax.

The value of this inside the function is determined by the surrounding scope, and there is no need to create a new variable, or to use bind:

    // ....
    fetchCondiciones: url => {
        $.ajax({
                type: "GET",
                url: url,
                cache: false,
                data: vardata,
                success: (data,status,error) => {
                    if(data != ''){
                        this.html_prop = data;
                    }
                }
                error: (data,status,error) => {
                    alert(error);
                }
        });
    }

Or:

    // ....
    fetchCondiciones(url) {
        $.ajax({
                type: "GET",
                url: url,
                cache: false,
                data: vardata,
                success(data,status,error) {
                    if(data != ''){
                        this.html_prop = data;
                    }
                }
                error(data,status,error) {
                    alert(error);
                }
        });
    }

4 Comments

It's working for me, thanks a lot. Is it considered good practice or it's a good hack/trick ?
Works for me too, but I am also wondering which approach is the best ?
Using the arrow function in the es6 example above is definitely the best approach!
I also used the 'self' hack for a few years. This is like using a global variable. From my experience, this approach is okay for simple situations, however, one there are multiple parent and child components, and ajax is used in all those components, 'self' may lead to mixup.
3

You can provide a context option and set it to this like so:

$.ajax({
  context: this, 
  ..
})

Which I prefer over binding this as it seems more readable, too.

From the jQuery AJAX docs:

The this reference within all callbacks is the object in the context option passed to $.ajax in the settings; if context is not specified, this is a reference to the Ajax settings themselves.

1 Comment

its also supported in older jquery versions which is another plus
0

You can also use arrow functions since ES6, arrow functions do not bind their own this, instead, they inherit the one from the parent scope, which is called "lexical scoping". so instead of

//....                
  success: function(data,status,error) {
                        if( data!=''){
                            this.html_prop = data;
           }
  }
//...

you can do

//....                
  success: (data,status,error) => {
                        if( data!=''){
                            this.html_prop = data;
            }
  }
//...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.