Search code examples
javascriptjqueryprototypejsprototypeprototype-programming

JavaScript - Prototype Based Programming - this.myFunction is not a function error


I have instantiated the JavaScript object "User". It contains all the necessary for the user management. Even loading and possible AJAX error are managed here. Below there's a snapshot of this object.

var User = function(uid, ajaxURL) {
        this.uid = uid;
        this.ajaxURL = ajaxURL;
     };
     User.prototype = {
        loadingShow: function (tag) {
            this.tag = (tag) ? tag : '.tab-pane';
            $(this.tag + ' .loading').html('<img src="img/template/loading.gif" alt="Loading..." title="Loading...">').fadeIn('fast'); 
            },
            //...
    };
    User.prototype.loadAction = function (rel) {
        var utls = new User();
            var relAttr = rel;
        $.ajax({
            type: 'POST',
            url: this.ajaxURL + '&id=' + parseInt(this.uid),
            cache: true,
            dataType: 'json',
            data: {
                toDo: relAttr
            },
            beforeSend:function(){
                utls.loadingShow('#' + relAttr + '-tab');
            },
            //...

It works fine but i have just a question, perhaps stupid but I'm facing for first times JavaScript OOP and Prototype-Based-programming.

Why must i create var utls = new User(); for call this utls.loadingShow( and not simply call it by this.loadingShow(? Using the this property i obtain the error "TypeError: this.loadingShow is not a function".


Solution

  • "Why must i create var utls = new User(); for call this utls.loadingShow( and not simply call it by this.loadingShow(?"

    Because this in the callback is set to the jqXHR object.

    To override it, you can set the context: property of the $.ajax request to the this value that you want.

    $.ajax({
            type: 'POST',
            url: this.ajaxURL + '&id=' + parseInt(this.uid),
            cache: true,
            dataType: 'json',
            context: this, // <-- set the `this` value of the callbacks
            data: {
                toDo: relAttr
            },
            beforeSend:function(){
            //   v--- now it's correct
                this.loadingShow('#' + relAttr + '-tab');
            },
            success: function(data) {
                var art_tmp_str = '';
    
     // Why are you using this? ---v
     //           $(document).ajaxComplete(function(event, request, settings) {
    
                 //   v--- now it's correct
                    this.loadingHide('#' + relAttr + '-tab');
                    $('#' + relAttr + '-tab').html(''); 
                    if(data.success === true) {
                                   //   v--- now it's correct
                        art_tmp_str = this.writeAction(relAttr, data);
                        $('#' + relAttr + '-tab').append(art_tmp_str);
                    } else
                        $('#' + relAttr + '-tab').append('<p>' + data.error + '</p>');
    //            });
    

    Furthermore, there shouldn't be any need to give a handler to .ajaxComplete() when you're already in a success callback. This should be done before any ajax requests are made if you really want a single behavior applied to all completed requests.