I use Angular ui-router and ng-animate for a hybrid mobile app. So I would like to use mobile standard transitions between screens (or states). Going deeper into the application, slide-left. Going back up (with the back button): slide-right. Nothing fancy and working with the normal ng-route. However, this should also work with ui-router. In fact, slide-left works fine, the problem arises when going back. It applies the class slide-left on the "original" div, but applies slide-right on the copy or ng-animate div. This is causing the animations to "cross", not nice.
The examples out there are not working in my case.
Index.html:
<div class="container">
<div ui-view class="view"></div>
</div>
In main.css:
.slide-left.ng-enter,
.slide-left.ng-leave,
.slide-right.ng-enter,
.slide-right.ng-leave {
position: absolute;
top: 0px; right: 0; bottom: 0; left: 0;
overflow-x: hidden;
background: inherit;
-ms-transition: 5.5s ease-in-out;
-webkit-transition: 5.5s ease-in-out;
transition: 5.5s ease-in-out;
}
.slide-left.ng-enter {
z-index: 100;
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
.slide-left.ng-enter.ng-enter-active {
-webkit-transform: translateX(0);
transform: translateX(0);
}
.slide-left.ng-leave {
z-index: 101;
-webkit-transform: translateX(0);
transform: translateX(0);
}
.slide-left.ng-leave.ng-leave-active {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
.slide-right.ng-enter {
z-index: 101;
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
.slide-right.ng-enter.ng-enter-active {
-webkit-transform: translateX(0);
transform: translateX(0);
}
.slide-right.ng-leave {
z-index: 100;
-webkit-transform: translateX(0);
transform: translateX(0);
}
.slide-right.ng-leave.ng-leave-active {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
In my routes.js: I have in the abstract view set the ng-class="slide".
$stateProvider
.state('enrollments', {
abstract: true,
url: '/tutorProcessEnrollments',
template: '<div class="scroller" ui-view ng-class="slide" ></div>'
})
.state('enrollments.list', {
url: '',
templateUrl: 'views/tutorProcessEnrollments.list.html',
controller: 'TutorEnrollmentsCtrl'
})
.state('enrollments.enrollment', {
url: '/:enrollment_id',
templateUrl: 'views/tutorProcessEnrollments.enrollment.html',
controller: 'TutorEnrollmentCtrl'
})
in App.js
.controller('MainCtrl', ['$scope', '$rootScope', '$window', '$location', '$state', function ($scope, $rootScope, $window, $location, $state) {
$scope.slide = 'slide-left';
// Implement own state.goTo functionality, to set the slide-left default on every menu action.
$rootScope.goTo = function (route, param) {
$scope.slide = 'slide-left';
$state.go(route, param);
};
// Function for going back in the history. The back button is hidden on items where no sub items/states\ are available.
$rootScope.back = function () {
if ($scope.slide === 'slide-left') {
$scope.slide = 'slide-right';
}
$window.history.back();
};
}]);
As you can see, I use the $window.history.back() to navigate back to the previous screen/state, and if the current direction is left, I set it to right, else, I don't do anything. This main controller is added in the Body tag. This is what happens when on the enrollments.enrollment state, and going back up to the enrollments.list state.
<div class="scroller ng-scope slide-left ng-animate ng-enter ng-enter-active" ui-view="" ng-class="slide" style=""><div ng-model="enrollment" class="ng-scope ng-pristine ng-valid">
<div class="scroller ng-scope slide-right ng-animate ng-enter ng-enter-active" ui-view="" ng-class="slide" style=""><div ng-model="enrollment" class="ng-scope ng-pristine ng-valid">
The problem of ng-class out of sync was solved by the ui-router team, but apparently I'm doing something wrong. I also don't like my current workaround to fetch every click to navigate deeper in the app.
So: how can I use slide-left/right with the back button and keep the classes in sync?
I have try my best
var myapp = angular.module('myApp', ["ui.router", "ngAnimate", 'hmTouchEvents', 'ngSanitize'])
myapp.config(function($stateProvider, $urlRouterProvider, $animateProvider){
$animateProvider.classNameFilter(/ani-/);
$stateProvider
.state('anon',{
template:'<ui-view class="ani-ui-view" ng-class="abstractView"/>',
abstract:true
})
.state("anon.foo", {
url: "/foo",
templateUrl : '/views/statechange/resources/partials/foo.html',
controller : 'fooCtl'
})
.state("anon.bar", {
url: "/bar",
templateUrl : '/views/statechange/resources/partials/bar.html',
controller : 'barCtl'
});
$urlRouterProvider.otherwise("/foo");
})
.run(function($rootScope){
$rootScope.$on("$stateChangeStart", function(event, currRoute, prevRoute, rejection) {
});
})
.animation('.fade-in', function($timeout){
return {
enter : function(element, done){
element.css({
'opacity':0,
transition:'all 300ms'
});
$timeout(function(){
element.css({
'opacity':1
});
},0)
}
}
})
.animation('.show-bar', function($timeout) {
return {
enter : function(element, done) {
element.css({
transition:'all 300ms',
transform:'translate3d(100%, 0, 0)'
});
$timeout(function(){
element.css({
transform:'translate3d(0, 0, 0)'
});
},0);
},
leave : function(element, done) {
element.css({
transition:'all 300ms',
transform:'translate3d(0, 0, 0)'
});
$timeout(function(){
element.css({
transform:'translate3d(100%, 0, 0)'
});
},0);
},
// you can also capture these animation events
addClass : function(element, className, done) {},
removeClass : function(element, className, done) {}
}
})
.animation('.slide-foo', function($timeout) {
return {
enter : function(element, done) {
element.css({
transition:'all 300ms',
transform:'translate3d(-100%, 0, 0)'
});
$timeout(function(){
element.css({
transform:'translate3d(0, 0, 0)'
});
},0);
},
leave : function(element, done) {
element.css({
transition:'all 300ms',
transform:'translate3d(0, 0, 0)'
});
$timeout(function(){
element.css({
transform:'translate3d(100%, 0, 0)'
});
},0);
},
// you can also capture these animation events
addClass : function(element, className, done) {},
removeClass : function(element, className, done) {}
}
})
.controller('mainCtl',[
'$scope', '$state', '$rootScope', '$window',
function($scope, $state, $rootScope, $window){
$rootScope.abstractView = 'fade-in';
console.log('mainCtl');
}
])
.controller('fooCtl',[
'$scope', '$state', '$timeout', '$rootScope',
function($scope, $state, $timeout, $rootScope){
$scope.changeState = function(_state){
$rootScope.abstractView = 'show-bar';
$state.go('anon.bar');
}
$scope.tip="I am foo";
}
])
.controller('barCtl',[
'$scope', '$state', '$stateParams', '$timeout', '$rootScope', '$window',
function($scope, $state, $stateParams, $timeout, $rootScope, $window){
$timeout(function(){
$scope.barshow = true;
});
$scope.tip="I am bar";
$scope.goBack = function($event){
$rootScope.abstractView = 'show-bar';
$window.history.back();
}
}
]);
index html
<body ng-controller="mainCtl">
<div class="ui-view-container">
<div ui-view></div>
</div>
</body>
foo html
<section ng-controller="fooCtl">
<div class="well">
{{tip}}
<div class="text-right">
<button class="btn btn-default" hm-tap="changeState('anon.bar')">to bar -></button>
</div>
</div>
bar html
<section ng-controller="barCtl">
<div class="well">
<div class="text-left">
<button class="btn btn-info" hm-tap="goBack($event);"><- back</button>
</div>
{{tip}}
</div>
some css
.ui-view-container {
position:relative;
}
.ani-ui-view{
position: absolute;
left: 0;
top: 0;
width:100%;
}
I hope it can help you
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