Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pause routing in Meteor's Iron Router while a page transition completes

In my Meteor app I have some complex page animations that require a few seconds to complete (instructive animations take priority over page transition speed).

There's an out state and an in state in the animation. For simplicity's sake, let's say I need to fade out one page, and then fade in the next, but that I want those fades to take multiple seconds. To do this I use Meteor's Iron Router to call some animation functions that manipulate the CSS.

lib/router.js

animateContentOut = function(pause) {
    return $('#content').removeClass("animated fadeIn");
}
Router.onAfterAction(animateContentOut);

animateContentIn = function() {
    return $('#content').addClass("animated fadeIn");
}
Router.onAfterAction(animateContentIn);

This is based on a great tip from Manuel Schoebel and the fadeIn works. However, my fade animation takes several seconds. So the user only sees the first few miliseconds of the fadeOut animation because it starts and then the router quickly navigates away to the new route before the animation completes.

So my question, is: how can I tell the router to wait for the animation to complete or for a setTimeout on an action in the onAfterAction call? Is there a better hook to use when animating the process of leaving a page?

like image 956
bryan kennedy Avatar asked Jul 23 '14 15:07

bryan kennedy


2 Answers

It depends what's generating the change of page. If it's a link/button/generic event, then rather than using an anchor href, you could just register an event like below, and store the route you want to move to (like "/home") in the data-route attribute of the anchor tag:

Template.links.events({
    'click a': function(event) {
        var _currentTarget = event.currentTarget;
        $('#content').removeClass('animated fadeIn').on('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', function() {
            Router.current().redirect(_currentTarget.attributes['data-route'].value);
        });
    }
});

That should begin the fade out, and actually wait for it to end before changing the route. A few caveats:

  1. It won't do anything for you if the user manually changes the url, and you'll have to add it to every piece of logic that changes page - to avoid either of these problems you'll probably have to pick apart the iron-router code and find a way to hook into page changes, which I'm not in a position to do at present!
  2. I haven't tested cross-browser, but it works fine in Chrome.
  3. In my experience you need to be careful with the currentTarget property of an event in Meteor - I don't think it will always give you what you expect, but this is something I need to take up separately.
like image 87
richsilv Avatar answered Nov 14 '22 23:11

richsilv


I have run into same question, when trying to combine Meteor with Framework7. Here is solution that absolutely works for me:

Meteor.startup(function () {
    var _animationEnd = 'oanimationend animationend webkitAnimationEnd otransitionend oTransitionEnd msTransitionEnd mozAnimationEnd MSAnimationEnd',
            _enterAnimation = 'fadeIn animated',
            _leaveAnimation = 'fadeOut animated',
            _animate = function ($el, anim, next) {
                return $el.addClass(anim)
                        .on(_animationEnd, function () {
                            $(this).removeClass(anim);
                            next && next();
                        });
            };
    Router.onAfterAction(function () {
        _animate($(".view-main"), _enterAnimation);
    });
    $(document.body).click(function (event) {
        var $t = $(event.target).parents().andSelf().filter("[href]:last"), url;
        if ($t.size() && (url = $t.attr('href'))) {
            var currentRoute = Router.current();
            _animate($(".view-main"), _leaveAnimation, function () {
                currentRoute.redirect(url);
            });
            event.preventDefault(), event.stopPropagation();
        }
    });
});

Comments and pros vs. solution provided by richsilv:

  • It works for all templates you ever use, since it's using body events
  • It works with any element, even a.href's, since preventing click event from default and further propagation
  • It is more compatible with other browsers, since more "animationend/transitionend/etc" events listed
like image 25
Jevgeni Avatar answered Nov 14 '22 23:11

Jevgeni