Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Route-Dependent CSS Page Transitions in AngularJS

Tags:

angularjs

I am new to AngularJS and would like to implement route dependent page transitions. For example, I would like the page to slide left, slide right or fade depending on the route.

My 'Plunker' below achieves this by listening to the $routeChangeSuccess event and then applying a transition style specific CSS class to the entering and leaving view (inspired by http://phillippuleo.com/articles/scalable-approach-page-transitions-angularjs):

http://plnkr.co/edit/ee4CHfb8kZC1WxtDM9wr?p=preview

However, the call to $scope.$apply() in the event listener makes AngularJS issue an error message '$digest already in progress'. But if I don't call $scope.$apply() the CSS class of the leaving view is not updated and the animation does not work correctly.

What is going on here?

like image 916
user2327642 Avatar asked Jan 18 '14 23:01

user2327642


1 Answers

I looked in your plunker. The problem is with the way you use classes to animate your views.

When the $routeChangeSuccess event is fired, ngView had already removed the class before you get the chance of changing the direction. You override it by applying the new class so quickly so it would not be noticed but then you get the digest in progress error.

My solution (plunker):

I came up with a directive:

app.directive('animClass',function($route){
  return {
    link: function(scope, elm, attrs){
      var enterClass = $route.current.animate;
      elm.addClass(enterClass);
      scope.$on('$destroy',function(){
        elm.removeClass(enterClass);
        elm.addClass($route.current.animate);
      })
    }
  }
});

Declare an animate option for each route:

app.config(function($routeProvider) {
  $routeProvider.
    when("/page1", {
      templateUrl: "page1.html",
      controller: "Page1Ctrl",
      animate: "slideLeft"
    }).
    when("/page2", {
      templateUrl: "page2.html",
      controller: "Page2Ctrl",
      animate: "slideRight"
    }).
    otherwise({
      redirectTo: "/page1"
    });
});

And just add it to ngView like so:

<div ng-view ng-controller="ViewCtrl" anim-class class="view"></div>

css:

.view {
    width: 100%;
    padding-left: 1em;
    position:absolute;
    top: 0;
    left: 0;
}

.slideLeft.ng-enter, .slideLeft.ng-leave, .slideRight.ng-enter, .slideRight.ng-leave  {
    -webkit-transition:all 1s;
    transition:all 1s;
}

.slideLeft.ng-enter {
    left:100%;
}

.slideLeft.ng-enter.ng-enter-active {
    left:0;
}

.slideLeft.ng-leave.ng-leave-active {
    left:-100%;
}

.slideRight.ng-enter {
    left:-100%;
}

.slideRight.ng-enter.ng-enter-active {
    left:0;
}

.slideRight.ng-leave.ng-leave-active {
    left:100%;
}
like image 155
Ilan Frumer Avatar answered Oct 10 '22 14:10

Ilan Frumer