0

I have a response handler that replaces content from ajax response. I want to fire an event after the content is replaced. This is the response handler:

function(response)
    {
        /* animate to top if called from bottom pagination */
        if ( caller === 'pag-bottom' && jq('#subnav').length ) {
            var top = jq('#subnav').parent();
            jq('html,body').animate({scrollTop: top.offset().top}, 'slow', function() {
                jq(target).fadeOut( 100, function() {
                    jq(this).html(response);
                    jq(this).fadeIn(100);
                });
            });

        } else {
            jq(target).fadeOut( 100, function() {
                jq(this).html(response);
                jq(this).fadeIn(100);
            });
        }
        jq('.item-list-tabs li.selected').removeClass('loading');
     // the event I want to trigger
        jq( document ).trigger( "buddyFilter:replaced", [ object, filter] );
    }

My problem is this event fires to early so my code that fires on event doesn't calculate the size of the div correctly and formatting is incorrect.

I have tried various combinations of trying to chain the event trigger but I can't get it right. I can't use a manual delay because then that will cause visual jump and not always work if loading time is slower than time.

How can I trigger this event the moment the html() value has rendered?

Edit:

Here is jsfiddle that is similar to my code but I had to change it about to get to work in fiddle. It shows that right after the event fires the div is 0 height

http://jsfiddle.net/jq7n4kfL/1/

Guerrilla
  • 13,375
  • 31
  • 109
  • 210

3 Answers3

2

Try utilizing .promise() , .then()

    function success(response)
        {
            /* animate to top if called from bottom pagination */
            if ( caller === 'pag-bottom' && jq('#subnav').length ) {
                var top = jq('#subnav').parent();
                return jq('html,body').animate({scrollTop: top.offset().top}, 'slow', function() {
                    jq(target).fadeOut( 100, function() {
                        jq(this).html(response);
                        jq(this).fadeIn(100);
                        jq('.item-list-tabs li.selected').removeClass('loading');
                    });
                }).promise();

            } else {
               return jq(target).fadeOut( 100, function() {
                    jq(this).html(response);
                    jq(this).fadeIn(100);
                    jq('.item-list-tabs li.selected').removeClass('loading');
                }).promise();
            }             
        };

$.ajax().then(success).then(function() {
  // the event I want to trigger
  jq( document ).trigger( "buddyFilter:replaced", [ object, filter] );
}]);
guest271314
  • 1
  • 15
  • 104
  • 177
  • Thanks! Is there any benefit to adding return before selector? I had a play with the fiddle and it works if I do promise().done(func) http://jsfiddle.net/jq7n4kfL/2/ – Guerrilla Jun 18 '15 at 02:44
  • @Guerrilla Included `return` to return a jQuery promise value to next `.then()` , if any , in chain. Using `.done()` should return similar results as `.then()` to call `.trigger()`. Note, `.done()` returns original jQuery promise value , `.then()` can return a new jQuery promise value . See http://stackoverflow.com/questions/5436327/jquery-deferreds-and-promises-then-vs-done . – guest271314 Jun 18 '15 at 03:03
1

You're triggering the event too early. Try this:

            jq(target).fadeOut( 100, function() {
                jq(this).html(response);
                jq(this).fadeIn(100, function() {
                   //trigger the event herer
                });
            });

Of course, you have to do it in two places.

PeterKA
  • 24,158
  • 5
  • 26
  • 48
  • It still fires too early, the content hasn't rendered in so my code gets incorrect div size. If I add in a 1 second delay then it works (with visual jump). – Guerrilla Jun 18 '15 at 01:54
0

You just put the event firing right after the actual HTML replacement takes place:

jq(target).fadeOut( 100, function() {
    jq(this).html(response);
    jq( document ).trigger( "buddyFilter:replaced", [ object, filter] );
    jq(this).fadeIn(100);
});

Also note that you repeat exactly the same code twice so better DRY it by wrapping it in a method.

Greendrake
  • 3,657
  • 2
  • 18
  • 24
  • It still fires too early, the content hasn't rendered in so my code gets incorrect div size. If I add in a 1 second delay then it works (with visual jump). – Guerrilla Jun 18 '15 at 01:54
  • Once `jq(this).html(response)` is called the content should be fully rendered before any further JS code is executed. I suggest you show a fiddle as the issue might be specific to your content or something. – Greendrake Jun 18 '15 at 02:02
  • here is fiddle that shows exactly what happens but I had to change the code around a bit but it highlights the issue http://jsfiddle.net/jq7n4kfL/1/ – Guerrilla Jun 18 '15 at 02:34
  • I have put the event triggering into `fadeIn` callback (as @PeterKA pointed) and it worked: http://jsfiddle.net/xs0k65vy/ – Greendrake Jun 19 '15 at 11:17
  • Yes you are correct, I looked too hastily at the code and didn't put it correctly in the right callback. – Guerrilla Jun 24 '15 at 22:30