Question

I want to execute a callback function inside an object. I don't know if there is something wrong in the way I'm doing this.

I've googled for a solution, also searched on stackoverflow but couldn't find anything similar to the way I'm coding this.

PHPGateway.js

var PHPGateway = {

    opt_friendlyURL: true,
    opt_folder: 'ajax/',

    callback_function: null,

    useFriendlyURL: function (bool) {
        this.opt_friendlyURL = bool;
    },

    setFolder: function (folder) {
        this.opt_folder = folder;
    },

    send: function (service, method, data, callback) {
        var url,
            json_data = {};
        if (this.opt_friendlyURL) {
            url = this.opt_folder + service + '/' + method;
        } else {
            url = this.opt_folder + 'gateway.php?c=' + service + '&m=' + method;
        }
        if (data != undefined) {
            json_data = JSON.stringify(data);
        }
        this.callback_function = (callback == undefined) ? null : callback;
        $.ajax({
            method: 'POST',
            url: url,
            data: {data: json_data},
            success: this.ajax_success,
            error: this.ajax_error
        });
    },

    ajax_success: function (returned_object) {
        if (this.callback_function != null) {
            this.callback_function(returned_object.error, returned_object.data);
        }
    },

    ajax_error: function () {
        this.callback_function.call(false, {});
    }

};

Then inside the HTML file that loads PHPGateway.js, I've the following code:

<script>
    function submit_handler(event) {
        event.preventDefault();
        form_submit();
    }
    function form_callback(error, data) {
        if(error == null) {
            alert(data.text);
        }
    }
    function form_submit() {
        var data = {
            status: $('#inStatus').val(),
            amount: $('#inAmount').val(),
            id: $('#inBudgetID'). val()
        }
        PHPGateway.send('budget', 'status', data, form_callback);
    }
    $('form').one('submit', submit_handler);
</script>

I get an error on this.callback_function(returned_object.error, returned_object.data);, the error is Uncaught TypeError: Object # has no method 'callback_function'.

  1. What am I doing wrong?
  2. Is this the best way to do it?

Thank You!

Based on minitech answer, I've updated PHPGateway.js like this. I've omitted the parts that weren't updated.

var PHPGateway = {

    // Omitted code

    send: function (service, method, data, callback) {
        var url,
            json_data = {},
            that = this;
        if (this.opt_friendlyURL) {
            url = this.opt_folder + service + '/' + method;
        } else {
            url = this.opt_folder + 'gateway.php?c=' + service + '&m=' + method;
        }
        if (data != undefined) {
            json_data = JSON.stringify(data);
        }
        this.callback_function = (callback == undefined) ? null : callback;
        $.ajax({
            method: 'POST',
            url: url,
            data: {data: json_data},
            success: function(data, textStatus, jqXHR) {
                that.ajax_success(data, textStatus, jqXHR);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                that.ajax_error(jqXHR, textStatus, errorThrown);
            }
        });
    },

    ajax_success: function (data, textStatus, jqXHR) {
        if (this.callback_function != null) {
            this.callback_function(true, data.data);
        }
    },

    ajax_error: function (jqXHR, textStatus, errorThrown) {
        this.callback_function.call(false, {});
    }

};

Now it works!!!

Was it helpful?

Solution 2

Here’s your problem:

$.ajax({
    method: 'POST',
    url: url,
    data: {data: json_data},
    success: this.ajax_success,
    error: this.ajax_error
});

When you set success and error to methods on this, they don’t keep their this. When a JavaScript function is called, it gets bound a this:

someFunction(); // this is undefined or the global object, depending on strict
someObject.someFunction(); // this is someObject

The built-in .call, .apply, and .bind of Function objects help you override this.

In your case, I think jQuery binds this to the Ajax object – a good reason to both not use jQuery and always use strict mode.

If you can guarantee or shim ES5 support, bind is an easy fix:

$.ajax({
    method: 'POST',
    url: url,
    data: {data: json_data},
    success: this.ajax_success.bind(this),
    error: this.ajax_error.bind(this)
});

Which is equivalent to this if you can’t:

var that = this;

$.ajax({
    method: 'POST',
    url: url,
    data: {data: json_data},
    success: function() {
        that.ajax_success.apply(that, arguments);
    },
    error: function() {
        that.ajax_error.apply(that, arguments);
    }
});

And now, a tip for you: don’t namespace, and if you do, don’t use this. this is great for objects that are meant to be constructed. What would seem more appropriate is something like this, if you really have to:

var PHPGateway = (function() {
    var callbackFunction;
    var options = {
        friendlyURL: true,
        …
    };
    …

    function send(service, method, data, callback) {
        …
    }
    …

    return { send: send };
})();

OTHER TIPS

In your call to $.ajax, you need to add a context option:

$.ajax({
    method: 'POST',
    url: url,
    data: {data: json_data},
    context: this,
    success: this.ajax_success,
    error: this.ajax_error
});

Your this variable in your Ajax success and error handlers are not pointing to the object you think they are. The context option to $.ajax() sets which object this points to in the Ajax callbacks.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top