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-view
s 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-view
s?).
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.
... 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 uglyness).
What is best practice in this scenario?
Option 1: Using event hooks $stateChangeStart
and $stateChangeSuccess
This approach would have some side effects as @David mentioned in comments. So avoid it until ui-router
comes up with a better way to manage state transition promise. Currently it relies on event.preventDefault()
to prevent the transition from happening.
Basically, ui-router
will fire your ui-view
route change view-out at the same time as the incoming view-in. So what you get is the previous ui-view
still visible while the next ui-view
is 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-view
and hooking them up in the $stateProvider
would not be wise.
Option 2:(Recommended) CSS based animations
I mostly go with CSS based transitions and you may achieve this either by
ui-view
and applying animation on that class.ui-view
in a <div>
(if you really need this) and apply animation on it.Either way, you would be treating all ui-views
as a single entity and animating them would make things look more cohesive.
HTML:
<div ui-view="header" ></div>
<div ui-view="main" ></div>
<div ui-view="footer" ></div>
CSS:
[ui-view].ng-enter {
animation: fadein 2s;
}
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
Here's a working plunkr based on your use case where, I have an abstract state root
and three nested states root.home
, root.artist
and root.band
. While the ui-view='main'
gets changed across all states, ui-view='footer'
doesnt change in any and ui-view='header'
changes for the state 'root.artist'.
The fact that you are using css based .ng-enter
and .ng-leave
classes to trigger the animations, you technically overcome the issues with previous approach.
$stateProvider
.state('root',{
abstract:true,
views:{
'header':{ //absolutely targets the 'header' view in root unnamed state.
templateUrl:'header.html'
},
'footer':{ //absolutely targets the 'footer' view in root unnamed state.
templateUrl:'footer.html'
}
}
})
.state('root.home',{
views:{
'main@':{
templateUrl:'main.html'
},
}
})
.state('root.artist',{
views:{
'header@':{
templateUrl:'artist-header.html'
},
'main@':{
templateUrl:'artist-main.html'
},
}
})
.state('root.band',{
views:{
'main@':{
templateUrl:'band-main.html'
},
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With