I have an app that basically looks like this
<div ui-view="header">
<div ui-view="main">
<div ui-view="footer">
Now, the footer will stay the same for all different states of the app, but the header will change in some states, but also share content in a lot of the states. The only ui-view that will change across all states is ui-view="main".
Currently my $stateProvider looks like this (footer not implemented yet):
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider.state('root',{
url: '',
abstract: true,
views: {
'header': {
templateUrl: appHelper.views+'/header.html',
},
}
})
.state('root.home', {
url: '/',
views: {
'header': {
templateUrl: appHelper.views+'/header.html',
},
'main@': {
templateUrl: appHelper.views+'/home.html',
controller: 'HomeController as homeVm',
}
},
resolve: {
posts: function(dataService) {
return dataService.getPosts();
},
artists: function(dataService) {
return dataService.getArtists();
}
}
})
.state('root.artist', {
url: '/artist/:slug',
views: {
'header@': {
templateUrl: appHelper.views+'/artistHeader.html',
controller: 'ArtistController as artistVm',
},
'main@': {
templateUrl: appHelper.views+'/artist.html',
controller: 'ArtistController as artistVm',
}
},
resolve: {
artist: function($stateParams, dataService) {
return dataService.getArtist($stateParams.slug);
}
}
});
}]);
So far, so good. But here’s the catch. During transitions I want to animate all the ui-views as one. To make things look cohesive in my case (it’s a fade animation) I would like to put them in a wrapping div and have that div do the fade out/fade in (doing it on each different ui-view will cause all kinds of ugliness).
What is best practice in this scenario?
Do I wrap them in a ui-view and hook that up in the $stateProvider somehow (nested ui-views?).
Are there any other ways to do it? Can I listen to $stateChange and apply classes to my wrapper like ngAnimate would with an ui-view? (fade out then wait until entirely faded out with a successful resolve before fading in).
From my googling efforts it seems ui-view is much preferred when handling animations of the transition type.
Option 1: Using event hooks
$stateChangeStartand$stateChangeSuccessThis approach would have some side effects as @David mentioned in comments. So avoid it until
ui-routercomes up with a better way to manage state transition promise. Currently it relies onevent.preventDefault()to prevent the transition from happening.Basically,
ui-routerwill fire yourui-viewroute change view-out at the same time as the incoming view-in. So what you get is the previousui-viewstill visible while the nextui-viewis rendered and if you're animating the view-out then there will be that transition duration of overlap between the old view and the new. You should look into holding off on rendering the new ui-view until the old one is finished animating out (before animating the new one in)For similar reasons, wrapping them in another
ui-viewand hooking them up in the$stateProviderwould not be wise.Option 2:(Recommended) CSS based animations
I mostly go with CSS based transitions and you may achieve this either by
ui-viewand applying animation on that class.ui-viewin a<div>(if you really need this) and apply animation on it.Either way, you would be treating all
ui-viewsas a single entity and animating them would make things look more cohesive.HTML:
CSS:
Here's a working plunkr based on your use case where, I have an abstract state
rootand three nested statesroot.home,root.artistandroot.band. While theui-view='main'gets changed across all states,ui-view='footer'doesnt change in any andui-view='header'changes for the state 'root.artist'. The fact that you are using css based.ng-enterand.ng-leaveclasses to trigger the animations, you technically overcome the issues with previous approach.