9

I'm trying to trace the return value from a function call:

$('#button').on('click', function(){
   console.log( getMessage(3) ); // I'm trying to get this to "hang" until ajax-related stuff is finished below
});

The ajaxFetch() below is a generic ajax handler that returns the expected ajax deferred object. let's assume it's a string value: 'hello'. Server response is several seconds.

function getMessage(id){
   ajaxFetch(id).done(function(result){
      // ... more stuff happening, but not relevant
   }).then(function(result){
      return (result); // I thought this would return to the click handler
   });
}

How can I get my trace to output 'hello'?

I think...

... that the console.log() needs to be somehow set up as a promise but I'm having a really hard time understanding the jQuery documentation.

tim
  • 3,823
  • 5
  • 34
  • 39
  • 1
    A `promise` is just supposed to give you an immutable reference to the `deferred` object created by either an AJAX call or `$.Deferred()` call. You can run the `deferred._____()` functions on the promise object to get its state or act on it. roasted's answer is probably what you're looking for. Also, I think the first argument to functions passed as `deferred` handlers is usually the deferred object itself. – Corion Jul 17 '13 at 22:14
  • @roasted's answer is treating `getMessage()` like a `promise` if I understand right - but it's just a simple function, so I can't use `.then()` - is there a way to define a function as a deferred? – tim Jul 17 '13 at 22:46
  • 1
    what is the return of `ajaxFetch`? Are you returning the `jqXHR` from `$.ajax()`? The functions that handle this `deferred` should expect `(data, status, jqXHR)` arguments too. Does this help? – Corion Jul 17 '13 at 23:28

2 Answers2

5

Return the promise interface and code logic from it:

 $('#button').on('click', function(){
        $.when(getMessage(3)).then(function(result){console.log(result)});
    });

function getMessage(id){
   return ajaxFetch(id).done(function(result){
      // ... more stuff happening, but not relevant
   }).then(function(result){
      return result; //needed, otherwise it will return the object, not the result
   });
}
Franco Rondini
  • 10,841
  • 8
  • 51
  • 77
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
  • It seems redundant to wrap `ajaxFetch()` when you could just `ajaxFetch(3).done()` in the handler itself. – Corion Jul 17 '13 at 22:16
  • 1
    Yes, but my `getMessage()` does a whole lot more than just return a promise. That's why I'm trying to pass the result from `getMessage()` on back to the click handler. – tim Jul 17 '13 at 22:19
  • @Corion, yes it does. – tim Jul 17 '13 at 22:20
  • @tim have you tried it? Why couldn't you still chain method inside getMessage()? I just don't put all your code inside my answer – A. Wolff Jul 17 '13 at 22:21
  • @roasted, are you saying the getMessage(3) in your click handler version is supposed to be a promise? If so, wouldn't I need to define it as such? – tim Jul 17 '13 at 22:29
  • 1
    @tim Store the promise in a variable and return an object from getMessage, e.g. `{ messagePromise: thePromise, otherReturn: "etc" }`? – Corion Jul 17 '13 at 22:31
  • 2
    I don't know what is ajaxFetch() method and why are you using that, but usually, jqXHR objects returned by ajax methods implement promise interface. I don't know what you mean by implement it as such too. What i know is that console.log(someAjaxFunction()) will never produce the result you seem to expect – A. Wolff Jul 17 '13 at 22:33
  • 1
    @tim Support for roasted's comment is here: http://api.jquery.com/jQuery.ajax/#jqXHR "The jqXHR objects returned by `$.ajax()` as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise..." – Corion Jul 17 '13 at 22:35
  • I tried @roasted's suggestion and it does not work because `getMessage()` function is not a deferred. I edited my question btw. – tim Jul 17 '13 at 22:37
  • @roasted, `ajaxFetch()` is just my own wrapper, because I'm doing other things with the result before sending it back up to the click handler. My `.done()` is doing just fine, and the `.then()` works too. I just can't figure out how to finish off by sending my result back from where the `.then()` method is used. – tim Jul 17 '13 at 22:40
  • @roasted, thank you THANK YOU very much for your help. It required one tweak to work properly as outlined in my OP. I submitted the edit to your answer. `$.when()` -- what a nice method to use for this. TO get the return value instead of the ajax object, add `return result` in the `.done()` – tim Jul 17 '13 at 23:35
3

I'm not completely sure I understand what you're trying to do, but if you want to execute callbacks using the deferred object within the context of the click handler you can return the ajax function itself from getMessage. Try something like this: (untested)

$('#button').on('click', function(){
    getMessage(3).then(function(result) {
        // do success callback here
        console.log(result); // 'hello'
    }, function(result) {
        // do fail callback here
    });
});

function getMessage(id){
    return ajaxFetch(id);
};
mcbex
  • 446
  • 4
  • 8
  • yes that is a way - but it's not what i'm trying to do. I'm specifically trying to *avoid* any logic inside the click handler. – tim Jul 17 '13 at 22:42
  • I don't believe there is any way to return just the result from the server to the click handler. The only other option I can think of is to pass your callback as an argument to getMessage like `getMessage(id, callback)`. Then in the ajaxFetch success you would do `callback(result)` – mcbex Jul 17 '13 at 22:56