AngularJS bidirectionnal ng-views animations

Shows how to dynamically change the ng-view animation.

by Adam Mendoza

HTML

<script src="http://code.angularjs.org/1.1.5/angular.js"></script>
<!-- * * * * * *  P A G E   W R A P P E R  * * * * * -->
<ng-view ng-animate="transitionClass"></ng-view>


<!-- * * * * * *  P A G E   T E M P L A T E S  * * * * * -->
<script type="text/ng-template" id="page1.html">
    <div class="page page1">
        <h1>Page 1</h1>
        <button ng-click="go('/two')">go page 2 (Left to Right)</button>
    </div>
</script>
        
<script type="text/ng-template" id="page2.html">
    <div class="page page2">
        <h1>Page 2</h1>
        <button ng-click="go('/three')">go page 3 (Right to Left)</button>
    </div>
</script>
        
<script type="text/ng-template" id="page3.html">
    <div class="page page3">
        <h1>Page 3</h1>
        <button ng-click="go('/two')">go page 2 (Left to Right)</button>
        <button ng-click="go('/one')">go page 1 (Right to Left)</button>
    </div>
</script>

CSS

body {
    overflow:hidden;
    margin:0;
    padding:0;
}

.page {
    width:100%;
    height:300px;
    padding:20px;
    position: absolute;
}

.page1 { background-color: #cff; }
.page2 { background-color: #fcc; }
.page3 { background-color: #cfc; }

/* * * * * * N O T E * * * * * 
angular 1.1.4 used the classes myname-enter-setup, myname-enter-start
angular 1.1.5 uses the classes myname-enter, myname-enter-active
by default, where 'myname' ist the identifier provided with <ng-view ng-animate="'myname'">
* * * * * * * * * * * * * * * */

/* * * * * * * LR * * * * * * */

.LR-enter {
    -webkit-transition: 1.5s ease-out all;
    -webkit-transform: translate(-100%,0);
}

.LR-enter-active {
    -webkit-transform: translate(0,0);
}

.LR-leave {
    -webkit-transition: 1.5s ease-out all;
    -webkit-transform: translate(0,0);
}

.LR-leave-active {
    -webkit-transform: translate(100%,0);
}

/* * * * * * * RL * * * * * * */

.RL-enter {
    -webkit-transition: 1.5s ease-out all;
    -webkit-transform: translate(100%,0);
}

.RL-enter-active {
    -webkit-transform: translate(0,0);
}
.page::before, ng-view::before {
    content:attr(class);
}


.RL-leave {
    -webkit-transition: 1.5s ease-out all;
    -webkit-transform: translate(0,0);
}

.RL-leave-active {
    -webkit-transform: translate(-100%,0);
}

JavaScript

var app = angular.module('demo', []);


/* * * * *  V I E W   R O U T I N G  * * * * */
app.config(function ($routeProvider) {
  $routeProvider
  .when('/one', {
    templateUrl:'page1.html'
  })
  .when('/two', {
    templateUrl:'page2.html'
  })
  .when('/three', {
    templateUrl:'page3.html'
  })
  .otherwise({
    redirectTo:'/one'
  });
});


/* * * * *  T R I G G E R   R O U T E   C H A N G E  * * * * */
app.controller('MainCtrl', function($scope, $rootScope, $location) {
  $scope.go = function(path) {
    $location.path(path);
  }
});


/* * * * *   L I S T E N   F O R   R O U T E   C H A N G E    * * * * */
/* * * * *  A N D   S E T   T R A N S I T I O N   C L A S S   * * * * */
app.run(function($rootScope, $window) {
     $rootScope.$on("$locationChangeSuccess", function (event, next, current) {
        // $rootScope.transitionClass = "";
     });
  $rootScope.$on("$locationChangeStart", function (event, next, current) {

    // url slug : shortening the url to stuff that follows after "#"
    current = current.slice( current.lastIndexOf('#')+1, current.length );
    next =    next.slice( next.lastIndexOf('#')+1, next.length );

    // apply transition class according to route
    switch( next ){
      // trigger "back" transition
      case $rootScope.lastPage:   $rootScope.transitionClass = $rootScope.backTransition; break;
      // trigger "regular" transitions
      case '/one':                $rootScope.transitionClass = "RL"; break;
      case '/two':                $rootScope.transitionClass = "LR"; break;
      case '/three':              $rootScope.transitionClass = "RL"; break;
    }
    
    // set "back" transition class according to currently set transitionClass
    switch( $rootScope.transitionClass ){
      case 'RL':    $rootScope.backTransition = "LR"; break;
      case 'LR':    $rootScope.backTransition = "RL"; break;
      default:      console.log("couldn't set backTransition");
    }

    // save current page slug, so we can check...