Left / right slide using angular ui-router when changing state + back button (for use on mobile devices)

I am using Angular ui-router and ng-animate for a hybrid mobile application. Therefore, I would like to use the mobile standard transitions between screens (or states). Going deeper into the application, move left. Return (using the "Back" button): slide right. Nothing unusual and does not work with a normal ng-route. However, this should also work with ui-router. In fact, the slide left works fine, the problem occurs when returning. It applies the slide-left class on the β€œoriginal” div, but applies the slide-right on the copy or ng-animate div. This makes the animation "cross" rather than pleasantly.

The examples there do not work 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 .js routes: I set ng-class = "slide" in an abstract view.

  $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 $ window.history.back () to go to the previous screen / state, and if the current direction remains, I set it to the right, otherwise I am not doing anything. This primary controller is added to the Body tag. This is what happens when in the state of registration and registration it returns and returns to the state enrollments.list.

 <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 the ng class outside of synchronization was solved by the ui-router command, but apparently I'm doing something wrong. I also don't like my current workaround for every click to go deeper into the application.

So: how can I use the left / right slide with the back button and keep the classes in sync?

+8
angularjs angular-ui-router ng-animate
source share
3 answers

I tried 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 -&gt;</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);">&lt;- back</button> </div> {{tip}} </div> 

some css

 .ui-view-container { position:relative; } .ani-ui-view{ position: absolute; left: 0; top: 0; width:100%; } 

Hope this helps you.

+1
source share

So, if you need some functionality when changing state, you use modulename.run () , where you use states, and in modulename.run () you can indicate that everything you want from your current state or change URL .

Assume your module

 var mod = angular.module('yourModuleName', ['ui.router']); mod.config(['$stateProvider', '$urlRouterProvider', function($stateProvider,$urlRouterProvider){ $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' }) }]); mod.run(function($rootScope) { $rootScope.$on("$stateChangeStart", function(event, currRoute, prevRoute, rejection) { $rootScope.$emit('cancelTravellerPopUpTimer'); $rootScope.$emit('closeTravellerInfoPopup'); }); }); 
0
source share

I had the same problem, but I only had three screens, but maybe with some settings this will lead to the desired effect.

So, first things first:

 <span ng-class="navReverse ? 'navleft' : 'navright'"> <div ui-view="nav"></div> </span> 

You must add an ng class in front of the user interface. Otherwise, it will add a new template with the current class instead of the desired class.

Then in the parent controller you can define the logic for the transitions. For me it was something like:

 $transitions.onCreate({}, function($transition) { if ($transition.$from().name == 'a' && $transition.$to().name == 'a.b') { $scope.navReverse = false; } if ($transition.$from().name == 'b' && $transition.$to().name == 'a') { $scope.navReverse = true; } } 

You can probably tweak this somehow if you need to apply it to more screens. As a check for the depth of the routes.

0
source share

All Articles