Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage chained AJAX calls with jQuery

I have this website that connects with a local service that manages a CardReader with a PIN Pad. There are many different operations that can be completed using this device. Heres an example of one of them:

  1. Lock the device
  2. Ask for PIN number
  3. Release device

Before I used to chain the callbacks between each other, but now, because there are new operations, that also use methods like "lock" and "release", I need to change my code, so that the code for step 1 and 3 is reusable.

I have been trying to solve this with jQuery promises, but Im quite new to this, and I still havent really figured out how they work. Can someone give me a hand?

This is an example of the code im using now. I have removed the business logic from inside the functions, to simplify the example:

var CardReader = {

    ////////////////////
    // Different possible messages to the Card Reader
    ////////////////////

    lockDevice: function() {
        this.makeAjaxCall("GET", "/LockDevice", this.lockDeviceCallback);
    },

    getPin: function() {
        this.makeAjaxCall("POST", "/getPin", this.getPinCallback);
    },

    releaseDevice: function() {
        this.makeAjaxCall("POST", "/Release", this.releaseDeviceCallback);
    },

    //////////////////
    // Callbacks for each message to the Card Reader
    //////////////////

    lockDeviceCallback: function(jqXHR, textStatus) {
        if (textStatus !== "success") { return; }
        this.getCardLogin();
    },

    getCardLoginCallback: function(jqXHR, textStatus) {
        if (textStatus !== "success") { return; }
        this.releaseDevice();
    },

    releaseDeviceCallback: function(jqXHR, textStatus) {
        if (textStatus !== "success") { return; }
        //End
    },

    ////////////////
    // Other methods
    ////////////////

    init: function() {
        // UI BIndings
        $(#button).on("click", this.logIn.bind(this));
    },

    logIn: function() {
        this.lockDevice();
    },

    makeAjaxCall: function(callType,  resource, callbackMethod) {

        $.ajax({
            type       : callType,
            url        : "http://localhost:1337" + resource,
            cache      : false,
            dataType   : "json",
            contentType: "application/json",
            context    : this,
            complete   : callbackMethod
        });
    }
};
like image 920
Enrique Moreno Tent Avatar asked Oct 22 '22 04:10

Enrique Moreno Tent


1 Answers

This could fit your needs even i'm not sure to understand fully your problematic here.

The important point here seems to keep order on ajax method callbacks. You could do something like that:

Create these methods:

 _nextCall: function (deferreds, method) {
        if (deferreds.length) this._when(deferreds, method);
        else console.log(method + " SUCCESS");
    },
    _when: function (calls, method) {
        var $promise = $.when(this[calls[0]]())
        $promise.then(function () {
            calls.splice(0, 1);
            this._nextCall(calls, method);
        }, function () {
            console.log(method + " FAILED on: " + calls[0]);
        });
    },

Use it like that e.g:

logIn: function logIn() {
        var calls = ["lockDevice", "getCardLogin", "releaseDevice"];
        this._when(calls, arguments.callee.name);
    },
    getPinOnly: function getPinOnly() {
        var calls = ["getPin"];
        this._when(calls, arguments.callee.name);
    },

DEMO

COMPLETE CODE:

var CardReader = {

    ////////////////////
    // Different possible messages to the Card Reader
    ////////////////////

    lockDevice: function () {
        return this.makeAjaxCall("GET", "/LockDevice", this.lockDeviceCallback);
    },
    getCardLogin: function () {
        return this.makeAjaxCall("POST", "/getCardLogin", this.getCardLoginCallback);
    },
    getPin: function () {
        return this.makeAjaxCall("POST", "/getPin", this.getPinCallback);
    },

    releaseDevice: function () {
        return this.makeAjaxCall("POST", "/Release", this.releaseDeviceCallback);
    },

    //////////////////
    // Callbacks for each message to the Card Reader
    //////////////////

    lockDeviceCallback: function (jqXHR, textStatus) {
        console.log("lockDeviceCallback");
        if (textStatus !== "success") {
            return;
        }
    },

    getCardLoginCallback: function (jqXHR, textStatus) {
        console.log("getCardLoginCallback");
        if (textStatus !== "success") {
            return;
        }
    },
    getPinCallback: function (jqXHR, textStatus) {
        console.log("getPinCallback");
        if (textStatus !== "success") {
            return;
        }
    },

    releaseDeviceCallback: function (jqXHR, textStatus) {
        console.log("releaseDeviceCallback");
        if (textStatus !== "success") {
            return;
        }
        //End
    },

    ////////////////
    // Other methods
    ////////////////

    init: function () {
        // UI BIndings
        $('#btn_login').on("click", $.proxy(this.logIn, this));
        $('#btn_getPinCallback').on("click", $.proxy(this.getPinOnly, this));
    },
    _nextCall: function (deferreds, method) {
        if (deferreds.length) this._when(deferreds, method);
        else console.log(method + " SUCCESS");
    },
    _when: function (calls, method) {
        var $promise = $.when(this[calls[0]]())
        $promise.then(function () {
            calls.splice(0, 1);
            this._nextCall(calls, method);
        }, function () {
            console.log(method + " FAILED on: " + calls[0]);
        });
    },
    logIn: function logIn() {
        var calls = ["lockDevice", "getCardLogin", "releaseDevice"];
        this._when(calls, arguments.callee.name);
    },
    getPinOnly: function getPinOnly() {
        var calls = ["getPin"];
        this._when(calls, arguments.callee.name);
    },

    makeAjaxCall: function (callType, resource, callbackMethod) {

        return $.ajax({
            type: callType,
            url: "/echo/json", // + resource,
            cache: false,
            dataType: "json",
            contentType: "application/json",
            context: this,
            success: callbackMethod
        });
    }
};

CardReader.init();
like image 155
A. Wolff Avatar answered Nov 01 '22 11:11

A. Wolff