Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slide left/right with angular ui-router on state change + back button (for mobile usage)

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?

like image 716
DHFW Avatar asked Aug 25 '14 21:08

DHFW


1 Answers

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 -&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%;
    }

I hope it can help you

like image 127
user2544867 Avatar answered Nov 14 '22 23:11

user2544867