0

I make a call to a function that makes an ajax call like this:

send.startMonitoring({'fetchMethod': 'notificationInterval', 'lastmodif':0}).then(function(value){
console.debug(value);
});

But the error I'm getting is this:

Uncaught TypeError: Cannot read property 'then' of undefined in jquery

As in above, I'm calling startMonitoring function which is on another page and passing an object for it to make ajax call to the server. That function returns value from server and I want to be able to do something with it. That's why I'm trying to use .then to process the value returned.

Since I'm getting the above error, how could I modify it so that returned value can be processed? Also how and when I can use .then()?

var interface = (function(config) {

        return {

                transporter: function(options) {
                    return config.ajax(options);
                },

                startMonitoring: function(options) {

                    var PERIOD_NOT_VISIBLE = 60000;
                    var PERIOD_VISIBLE = 5000;
                    var timer = 0;
                    var timestring = 0;

                    (function callThis(timestamp) {                 

                        interface.transporter(options).then(function(value) {

                            if (value[1].notification[0].output == null) {
                                timestring = value[1].notification[0].lastmodif;
                                console.log(timestring);
                                return value;
                            }


                        }).catch(function(e) {

                        });

                        timer = setTimeout(function(){

                        callThis();
                            if (interface.isMonitoring() == 0 ) {
                            clearTimeout(timer);
                            }
                        }, (document.hidden) ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);

                    })();
                }
        };

})(settings);

This is how ajax calls made:

ajax: function(opt) {

        var defaultData = settings.getDefaultDataset();
        var self = this;
        var opt = $.extend({}, defaultData, opt);
        var output = [];
        return new Promise(function(resolve, reject) {
            token = window.es.token;
            opt[token] = "1";
            jQuery.ajax({

                method: "POST",
                url: self.system.path+"/index.php",
                "data": opt,
                error: function() {
                    reject('error');
                },  
                success: function(result) {
                    output.push(opt, result);
                    resolve(output);           
                }
            });

        });
    }
112233
  • 2,406
  • 3
  • 38
  • 88
  • what does the function `send.startMonitoring` return ... `That function returns value from server` - clearly it doesn't ... I bet this is "how to return value from asynchronous call" issue - the problem is in the code you **haven't** shown – Jaromanda X Oct 07 '16 at 02:54
  • Possible duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Jaromanda X Oct 07 '16 at 02:55
  • `how and when I can use .then()` when the object you're using `.then()` on is an object with a property called `then` that is a `function` – Jaromanda X Oct 07 '16 at 02:56
  • @JaromandaX, I added the function that I didn't show earlier..please check – 112233 Oct 07 '16 at 02:58
  • as I suspected, `startMonitoring` doesn't return anything – Jaromanda X Oct 07 '16 at 02:59
  • `startMonitoring` would never return a single value, as it repeats every 5/60 seconds - therefore it is **not** a Promise candidate - as Promises can only be fulfilled/rejected once and once only – Jaromanda X Oct 07 '16 at 03:01
  • @JaromandaX, I added full code with ajax itself. See that It uses promise object to return value.. – 112233 Oct 07 '16 at 03:03
  • indeed, I never said the ajax call shouldn't use a Promise, I said `startMonitoring` can't use a Promise - which it isn't, fair enough - except that your first bit of code calls `startMonitoring` as if it does return a Promise (`.then` is a Promise thing, though `.then` isn't restricted to promises) - having said that, your ajax function is guilty of the Promise Constructor Anti-pattern ... jquery Ajax returns a Promise, so no need to create one – Jaromanda X Oct 07 '16 at 03:05
  • @JaromandaX, if promises can only be fulfilled once and the function would never return single value as it repeats, how is it possible to pass the value to the calling party to be done something with the returned value? – 112233 Oct 07 '16 at 03:08
  • 1
    use a callback argument to `startMonitoring` and rewrite the code that calls it – Jaromanda X Oct 07 '16 at 03:12
  • @Keren you need to consume the response from `interface.transporter` in it's `then` if you need each occurrence to update something in the app. When `callThis()` gets called recursively it could only ever fullfill one promise once – charlietfl Oct 07 '16 at 03:12
  • @charlietfl, I got your point, I'm updating current timestamp return from ajax inside .then() as you said. However I still need to pass the object when it meet certain condition to send.startMonitoring.then() – 112233 Oct 07 '16 at 03:15
  • `send.startMonitoring.then()` can only ever be called **once** - yet your code clearly wants to return values periodically - forget Promises for functions that generate multiple outputs – Jaromanda X Oct 07 '16 at 03:17

2 Answers2

1

Change startMonitoring to accept and call a callback parameter

startMonitoring: function(options, callback) {
    var PERIOD_NOT_VISIBLE = 60000;
    var PERIOD_VISIBLE = 5000;
    var timer = 0;
    var timestring = 0;
    (function callThis(timestamp) {
        interface.transporter(options).then(function(value) {
            callback(value);
        }).catch(function(e) {
        });
        timer = setTimeout(callThis, (document.hidden) ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);
    })();
},

Tidy up ajax to remove the Promise constructor anti-pattern, and to use .then of the promise returned by jQuery.ajax

ajax: function(opt) {
    var defaultData = settings.getDefaultDataset();
    var opt = $.extend({}, defaultData, opt);
    var output = [];
    var token = window.es.token;
    opt[token] = "1";
    return jQuery.ajax({
        method: "POST",
        url: this.system.path + "/index.php",
        "data": opt,
    })
    .then(function(result) {
        output.push(opt, result);
        return output;
    });
}

Change how you call startMonitoring to pass in a callback function

send.startMonitoring({'fetchMethod': 'notificationInterval', 'lastmodif':0}, function callback(value){
    console.debug(value);
});
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • thanks, it works except that the ajax fix throwing some error saying..$.ajax.then()....catch() is not a function..but it's okay I'll do some study on deferred objects – 112233 Oct 07 '16 at 03:20
  • I'm a little suspect of the `var output = [];` then `output.push(opt, result); return output;` code ... this will always only ever return an array with a two elements, `opt` and `result` ... I suspect you could remove the var `output` altogether, and simply `return [opt, result];` – Jaromanda X Oct 07 '16 at 03:21
  • what version of jQuery are you using? I think some old version didn't have `.catch` – Jaromanda X Oct 07 '16 at 03:22
  • I'm using the latest and catch is supported in some part of my code – 112233 Oct 07 '16 at 03:23
  • If by latest you mean something in 3.x.x or higher then, that's odd, because it's only 2.x.x and below that show that error – Jaromanda X Oct 07 '16 at 03:29
  • `catch is supported in some part of my code` - `catch` or `.catch` ... and if `.catch` is that as a result of a `Promise` or a `jQuery.ajax` call? – Jaromanda X Oct 07 '16 at 03:30
0

In jQuery, you can use the $.Deferred() function. For example :

function startMonitoring() {
    var deferred = $.Deferred();

    jQuery.ajax({
        url: your_url,
        type: 'GET',
        success: function (data) {
            deferred.resolve(data);
        },
        error: function (error) {
            deferred.reject(error);
        }
    });

    return deferred.promise();
}

Then, you can call your function :

startMonitoring().done(function (data) {
    //Went well
}).fail(function (error) {
    //Error
});
Philippe Genois
  • 599
  • 4
  • 6
  • this is a classic anti-pattern.....`$.ajax` already returns a promise. You shouldn't be using `$.Deferred()` to create a new one when one already exists – charlietfl Oct 07 '16 at 03:04