4

What is the idiomatic way to have a callback executed when ALL of triggers are satisfied?

In particular, in the example below, what is the way to run the proceed function when the user presses the #btn, but no earlier than the previously launched AJAX request returns a response (or, if the users presses the button too early, wait for the AJAX response to come before firing proceed)?

proceed = (ajaxData) -> ...

# Launch an AJAX request and display a button:
$("#btn").on 'click', -> ???

$.ajax
  type: "POST"
  url: ...
  data: ...
  success: (ajaxData) -> ???
isherwood
  • 58,414
  • 16
  • 114
  • 157
Aleph Aleph
  • 5,215
  • 2
  • 13
  • 28

4 Answers4

1

Use promises, it exists in ES6, jQuery and in other frameworks (angular ...)

Use Promise.all(...) in ES6

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

You have to encapsulate all your ajax call in promises, then Promise.all permit to be called when all promises are resolved.

There also an equivalent in jQuery, see example here: How do you work with an array of jQuery Deferreds?

Community
  • 1
  • 1
pdem
  • 3,880
  • 1
  • 24
  • 38
  • Thank you, this is interesting and it seems that using .when() / .then() with JQuery deferreds is a way towards the solution, but, as I understand from the docs, wrapping a button click event in a deferred requires too much code for a one-off case. – Aleph Aleph Jul 02 '15 at 08:37
1

An easy way to achieve this, just use a boolean variable as a flag, and set it to true when the ajax request succeeds:

proceed = function() {...};

ajax_completed =  false;

$.ajax(...,
    success: function(data) {
        ajax_completed = true;
        ...
    }
);

$("#btn").on('click', function(ev){ if(ajax_completed) {...} });
davids
  • 6,259
  • 3
  • 29
  • 50
  • Doesn't quite work for me - the click is just ignored if the button is clicked before the data is received... – Aleph Aleph Jul 02 '15 at 08:49
  • 1
    @AlephAleph This seems to be the idiomatic way(*might need slight change/fixes if necessary*). If this doesn't answer the question, then you're missing to be clear enough with the question. – code-jaff Jul 02 '15 at 10:29
0

Every $.ajax call return a Promise.

Consider this:

var promise = $.ajax('...',{
  type: "POST"
  url: ...
  data: ...
  success: callFunction()
});

promise.done(function(result){
   //use result on your function
});

Anyway, I don't think that disabling a button is the best UX option here. Think about hidding it or showing some message.

Renato Galvones
  • 533
  • 1
  • 3
  • 14
  • Probably I didn't make it clear - the button must not be disabled! In the case the user press the button early, the action is delayed until the content is received – Aleph Aleph Jul 02 '15 at 08:38
0

Looks that wrapping into promises / deferreds is a correct way to do, but it seems that wrapping a button click in a JQuery Deferred requires a lot of code for a seemingly easy thing.

For reference, that's what I've come up with for this particular case and what seems to work as a one-off solution:

proceed = (ajaxData) -> ...

proceedLock = {buttonClicked: false, data: null}
tryProceed = ->
  if proceedLock.buttonClicked and proceedLock.data?
    proceed proceedLock.data

# Launch an AJAX request and display a button:
$("#btn").on 'click', ->
  proceedLock.buttonClicked = true
  tryProceed()

$.ajax
  type: "POST"
  url: ...
  data: ...
  success: (ajaxData) ->
    proceedLock.data = ajaxData
    tryProceed()
Aleph Aleph
  • 5,215
  • 2
  • 13
  • 28