4

I have a need to manually trigger the change event on a menu. But then I need to wait until change event complete execution then I would perform action.

Here is what I am trying to do in code

$('#menu').change(function(){

  // do some work
  // make multiple AJAX calls....

});

$('#button').click(function(){

   $('#menu').val(5).change(); // once change is completed I want to do some logic here.
});

This is what I tried but is does not seem to wait for the change() event to finish.

$('#button').click(function(){

   $('#menu').val(5).change().promise().done(function(){
      // do some work after the change() event is completed..
   });
});

How can I correctly perform code until after the change event is completed?

UPDATED

I tried the following, but still it does not seems to be working

$('#menu').change(function(){

     makeAjaxCalls($(this).val());

});


$('#button').click(function(){

   makeAjaxCalls(5, function(){
      // do some work after the makeAjaxCalls() is completed..
   });
});

function makeAjaxCalls(id, callback) {
    var task = $.Deferred(function(){
         // Make all ajax calls here...
    });

    $.when(task).then(function() {
        if ($.isFunction(callback)) {
            callback();
        }
    }).catch(function (error) {
        console.log('something wrong... ', error);
    });
}
Junior
  • 11,602
  • 27
  • 106
  • 212
  • Possible duplicate of [jquery change event callback](https://stackoverflow.com/questions/15805000/jquery-change-event-callback) – Matthew Herbst Sep 26 '18 at 16:43
  • 2
    Do you *really* need to trigger the change event, instead of being able to simply call a common function? – Bergi Sep 26 '18 at 16:44
  • 3
    Makes zero sense to call change. Put the logic in to a function and use a promise. – epascarello Sep 26 '18 at 16:44
  • 1
    @MatthewHerbst No, that doesn't seem to deal with async event handlers – Bergi Sep 26 '18 at 16:44
  • @Bergi it accomplishes the same thing, just doesn't use a promise. – Matthew Herbst Sep 26 '18 at 16:46
  • @MatthewHerbst given that the change event handler notes in the comments that some of the work involves ajax method(s), waiting for them to finish would typically involve some sort of promise. – Taplar Sep 26 '18 at 16:47
  • So you want to make ajax call on menu change, and you also want to trigger it through code on button click and execute some code after the ajax call is complete, right? – AvcS Sep 26 '18 at 16:47
  • is your element with #menu present when the dom loads? – tam Sep 26 '18 at 16:48
  • @Taplar yes, and you can either listen for those promises directly as OP is trying to do in the code above, or, when it comes to some events, you can register callbacks ahead of time and the library/framework and/or browser (depending on the event) takes care of dealing with the promise for you. – Matthew Herbst Sep 26 '18 at 16:51
  • @MatthewHerbst - Regardless, that question is not a dupetarget for this question. – T.J. Crowder Sep 26 '18 at 16:56
  • @T.J.Crowder the question in this post is "How can I correctly perform code until after the change event is completed?" The question in the post I linked to is "How to call a function once after change() event complete?" I'm failing to see how the questions are different, unless the question here is something different, or the accepted answer to the other question is incorrect or not technically possible for this OP. – Matthew Herbst Sep 26 '18 at 17:02
  • 2
    @MatthewHerbst the duplicate post you linked associates "complete" by the value of the element being changed. *This* question associates "complete" by all the asynchronous methods that happen inside the change handler being complete. Those are two completely different cases. – Taplar Sep 26 '18 at 17:05
  • @Bergi I am not sure that I do need to call the `change()` event. but the function inside the change() make multiple ajax calls, and I want to ensure all ajax calls are completed before I continue – Junior Sep 26 '18 at 17:09
  • @Taplar Great, that makes sense, so the question should be "How to wait for promises to complete within the onchange event" which is very different from what was asked. Nice answer. – Matthew Herbst Sep 26 '18 at 17:10
  • I updated my question. – Junior Sep 26 '18 at 18:04
  • I don't see in your updated logic where you are calling `task.resolve()`. You would need to do that once you were done with your asynchronous logic in the deferred. – Taplar Sep 26 '18 at 18:45

2 Answers2

4

One potential way of doing this would be to provide the callback to the change event.

$('select').on('change', function(e, data){
  //mimic an async action
  setTimeout(function(){
    console.log('element changed');
    
    //if extra data was given, and one of them is a callback, use it
    if (data && typeof data.callback === 'function') {
      data.callback();
    }
  }, 2000);
});

$('button').on('click', function(){
  //trigger the change with extra data containing a callback
  $('select').val(2).trigger('change', { callback: function(){ console.log( 'weeee' ); } });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select>
  <option></option>
  <option value="1">1</option>
  <option value="2">2</option>
</select>

<button>Click Me</button>
Taplar
  • 24,788
  • 4
  • 22
  • 35
  • Why wrap the callback function in an object? – Bergi Sep 26 '18 at 17:12
  • True, you could give just the function. This was just the first thing my mind went to. So you can attribute that just to my ingrained coding practices, :) @Bergi – Taplar Sep 26 '18 at 17:13
  • I tried the same idea using `$.when().then()` but I can't get it to work. my updated code in is the question. – Junior Sep 26 '18 at 18:06
1

You want to call a function that makes asynchronous calls on both menu change and button click. There is a simple solution to this, make a function that reads value of menu and returns a promise and use it in both the events.

function makeAjaxCalls() {
    var menuValue = $('#menu').val();
    // Run some ajax calls based on menuValue and return the promise
    return Promise.resolve()
}

$('#menu').change(makeAjaxCalls);
$('#button').click(function(){
    $('#menu').val(5);
    makeAjaxCalls().then(function() {
        // Do something after ajax calls completed
    });
});
AvcS
  • 2,263
  • 11
  • 18
  • how would the ajax call look like with the promise in this case? – Junior Sep 26 '18 at 17:27
  • That depends on the library you are using to make ajax calls, i gave an example with promise, if you are using jquery you should replace then with done – AvcS Sep 26 '18 at 17:33
  • I am using jQuery. I updated my question with my current code which isn't working – Junior Sep 26 '18 at 18:05
  • Try putting console.log in catch, may be your ajax call is not reaching then – AvcS Sep 26 '18 at 18:07
  • https://api.jquery.com/jquery.when/, when doesn't accept a function, it accepts deferred objects as parameter – AvcS Sep 26 '18 at 18:12
  • I updated my question/code again. The `$.then` part never seems to be called – Junior Sep 26 '18 at 18:33
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/180827/discussion-between-mike-a-and-avcs). – Junior Sep 26 '18 at 18:40