Two different animations for route changes
Solution 1
You can control the classes on your view by setting up a controller to do that specifically. You can then subscribe to events within the app and change the way the page animates.
<div class="viewWrap" ng-controller="viewCtrl">
<div class="container" ui-view ng-class="{back: back}"></div>
</div>
Then within your controller
.controller('viewCtrl', function ($scope) {
$scope.$on('$stateChangeSuccess', function (event, toState) {
if (toState.name === 'state1') {
$scope.back = true;
} else {
$scope.back = false;
}
});
});
I've set up a codepen to demonstrate here http://codepen.io/ed_conolly/pen/aubKf
For anybody trying to do this please note that I've had to use the ui.router.compat module due to the current incompatibility of the animations in Angular 1.2 and UI Router.
Solution 2
You could always checkout the angular-1.2 branch: https://github.com/angular-ui/ui-router/tree/angular-1.2. This fixes up ngAnimate along with a few other things.
I believe this will be included in ui-router 0.3.0, so as long as you won't be pushing live soon, this should provide you with the function you need until you can get back on the 'stable' branch.
Disclaimer: I have no authority on when the next release of UI-router will be or what it will include. I have simply found this information in various issues on the github page.
Solution 3
I was attempting to do this same thing with ngRoute
using $routeChangeSuccess
but the problem I ran into was that the ng-leave
animation would start before a digest cycle ran. The enter animation was always correct, but the leave animation was always the previous one.
The solution that worked for me (Angular 1.57) was to wrap the $location.path()
call in a $timeout
. This makes sure a full digest runs before the animation is started.
function goto(path) {
if(nextIndex > currentIndex) {
ctrl.transition = 'slide-out-left';
} else {
ctrl.transition = 'slide-out-right';
}
$timeout(function() {
$location.path(path);
});
}
Solution 4
Eddiec's solution was a really nice start but I still found myself hacking it up a bit. Here is a modified controller that works better for my purposes. This is more dynamic:
function ViewCtrl($scope, $state) {
$scope.$on('$stateChangeStart', function (event, toState) {
var movingToParent = $state.includes(toState.name);
if (movingToParent) {
$scope.back = true;
} else {
$scope.back = false;
}
});
}
Related videos on Youtube
Sammy S.
Updated on August 23, 2020Comments
-
Sammy S. over 3 years
I have the following case: I'm using the ui-router for the routing in my AngularJS application. In one route, there are five child states for different subscreens. I want to animate the transition between these in a carousel-like manner.
The navigation looks like this:
Link to A | Link to B | Link to C | Link to D | Link to E
Navigating from
state A
tostate B
should makescreen A
slide out to the left andscreen B
slide in from the right; vice versa for navigating fromstate B
tostate A
.What does work is animating the screen transitions with
transform: translateX(...);
onenter
andleave
in one direction only.Usually, I control my animations using
ng-class
with a flag. In this case, however, setting a class on theui-view
element doesn't work at all (Angular 1.2 and ui-router 0.2 aren't completely compatible yet). Neither is it working with setting it with a custom directive listening toscope.$on "$stateChangeStart"
which is fired after the transition has begun.How can I implement the desired behavior?
Edit: The solution
For the record: I ended up implementing it using a custom
$scope
function using$state.go()
to determine the direction before changing the route. This avoids the$digest already in progress
errors. The class determining the animation is added to theui-view
's parent element; this animates both the current as well as the futureui-view
in the correct direction.Controller function (Coffeescript):
go: (entry) -> fromIdx = ... toIdx = ... if fromIdx > toIdx $scope.back = false else $scope.back = true $state.go entry
Template:
<div ng-class="{toLeft: back}"> <div ui-view></div> </div>
-
kontur over 10 yearsCouldn't you use the javascript based animation variant of ng-animate, within which you can check from where to where you are animating and thus apply a different animation based on direction?
-
Sammy S. over 10 years@kontur: If you have an idea how to implement it, feel free to add an answer yourself :).
-
-
Nathaniel Johnson over 10 yearsNice answer. I was looking at this and wondering if another approach might be use
$locationChangeStart
. +1 for the nifty codepen. -
eddiec over 10 yearsyou could do yes - locationChange is for ngRoute and the question is specifically about using ui router. Using
Success
is useful as we know the system has accepted the route change at that point. -
Sammy S. over 10 yearsThank you for your answer! However, this doesn't eliminate my problems. I get
$digest already in progress
messages all the time. Furthermore, theui-view
to be removed is keeping the old class while the new view gets another. This leads to a very strange effect where the leaving view animates into the wrong direction while the entering view animates into the right direction overlaying the leaving one. -
eddiec over 10 yearswhat browser are you seeing that in? I see the digest problem, but for me they both animate in the same direction.
-
Sammy S. over 10 yearsI'm always on the latest stable of Chrome (which would be Chrome 31 at the moment). Which version of
ui.router
are you using? -
Sammy S. over 10 yearsThank you for your answer! I already tried that and it didn't solve my problem, unfortunately.
-
eddiec over 10 yearsSorry, not sure where I grabbed it from, and now it's minified in my codepen. You could always add that class to wrap the ui-view element, that way the class wouldn't be affected by a new element being created.
-
Sammy S. over 10 yearsThanks for the hint. I ended up implementing it using a custom
$scope
function using$state.go
to determine the direction before changing the route. This avoids the$digest already in progress
errors. The class determining the animation is added to theui-view
's parent element. -
tenphi about 10 yearsThis solution works much better with complex animations if we move ng-class to viewCtrl container. And yes, $scope.$apply() is excess.