Question

i'm using ng-animate to slide the app views, so each route slides own view , this is my simple code:

html:

<div ng-view ng-animate class="slide"></div>

css:

/*Animations*/
.slide{
  left:0;
}
.slide.ng-enter{
  transition:0.15s linear all;
  position:fixed;
  z-index:inherit;
  left:-100%;
  height:inherit;
}
.slide.ng-leave{
  transition:0.15s linear all;
  position:fixed;
  z-index:9999;
  right:0;
}
.slide.ng-leave-active{
  transition:0.15s linear all;
  position:fixed;
  right:-100%;
  left:100%;
}
.slide.ng-enter-active{
  transition:0.15s linear all;
  left:0;
  position:relative;
}

Now, i'm wondering , is there anyway to exclude the home page (main "/" route) from sliding?

In other terms: Any way to exclude a route from ng-animate?

Was it helpful?

Solution

That's what ng-class is for.

You can set a application-wide variable $rootScope.path whenever path changes.

app.run(function ($rootScope, $location) {
  $rootScope.$on("$locationChangeStart", function (event, next, current) {
    $rootScope.path = $location.path();
  });
});

Then, you decide to set your animation class by that variable

If you want to set class slide only if path is not /, do like this

<div ng-view ng-class="{slide: path !== '/' }"></div>

By doing this way, you don't need to touch any of your controller.

Full demo is here, http://plnkr.co/edit/rmu8oc7ycKzRaA2zv5JN?p=preview

By the way, this uses currant angularJS version, 1.2.7

------- Edit (animate after visit main page) ------

app.run(function ($rootScope, $location) {
  $rootScope.$on("$locationChangeStart", function (event, next, current) {
    if (!$location.path().match(/^\/?$/) && !$rootScope.mainVisitedOnce) {
      $rootScope.mainVisitedOnce = true;
    }
  });
});

and

<div ng-view ng-class="{slide: mainVisitedOnce }"></div>

http://plnkr.co/edit/QpDFkdKH1kk6ZXy07G5X?p=preview

OTHER TIPS

Demo http://plnkr.co/edit/sMUM48?p=preview

Explain

No need to create separate controller, directive or change any business logic. Just use .animation method to add conditional animation to .slide.

Listen to $routeChangeSuccess event on $rootScope. This is event will be triggered before animation start, so you have time to set toRoot and fromRoot flag accordingly. If target view is not a "/" view, a enable-animation class will be added to ng-view element, so css transition defined will be performed.

If target view if a "/" view, no animation will be performed.

HTML

<ng-view class="slide"></ng-view>

CSS

.slide {
  position: absolute;
  top: 0;
  width: 100%;
}
.slide div {
  margin: 10px;
  background: red;
}

.slide.enable-animation.ng-enter,
.slide.enable-animation.ng-leave {
  transition: all 10s;
  z-index: 1;
}

.slide.enable-animation.ng-enter {
  left: -100%;
  opacity: 0;
}

.slide.enable-animation.ng-enter.ng-enter-active,
.slide.enable-animation.ng-leave {
  left: 0;
  opacity: 1;
}

.slide.enable-animation.ng-leave.ng-leave-active {
  left: 100%;
  opacity: 0;
}

JavaScript

app.animation('.slide', function($rootScope, $animate) {

  var toRoot = false;
  var fromRoot = false;

  $rootScope.$on('$routeChangeSuccess', function(event, current, old) {
    toRoot = (current.$$route.originalPath === '/');
    fromRoot = (old.$$route.originalPath === '/');
  });

  return {
    enter: function(element, done) {
      if (!toRoot) {
        element.addClass('enable-animation');
      }
      done();
    },

    leave: function(element, done) {
      if (!fromRoot) {
        element.addClass('enable-animation');
        done();
      } else {
        // set 1000ms timeout to sync with CSS animation
        // otherwise leaving ng-view element will be removed before entering ng-view is in position
        setTimeout(done, 1000);
      }
    }
  }
});

Update 1

If you just want to exclude a route only when the first time app loads, you basically don't have to do anything, just define your css animation like normal. The first loaded route won't trigger any animation.

Demo http://plnkr.co/edit/uRZyZA?p=preview

Borrowing from @allenhwkim, get path in your rootScope.

app.run(function ($rootScope, $location) {
  $rootScope.$on("$locationChangeStart", function (event, next, current) {
    $rootScope.path = $location.path();
  });
});

Then have this as your element:

<div ng-view ng-animate ng-class="{slide: path !== '/' }"></div>

.slide will be added to your container element when the path being loaded isn't /.

Here's a working Plunker.

Why don't you simply add a root class like class="not-animated" and class="animated" to the controllers you don't want or want to be animated?
In this way you could use the .not-animated and .animated class to play with your animation in different controllers.

You can set your controller like this:

<body ng-controller="MainCtrl" ng-class='isAnimated'>
  <div ng-controller="FirstCtrl" ng-class='isAnimated'>Foo</div>
  <div ng-controller="SecondCtrl" ng-class='isAnimated'>Bar</div>
</body>

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
  $scope.isAnimated = 'not-animated';
});

app.controller('SecondCtrl', function($scope) {
  $scope.isAnimated = 'animated';
});  

This will result in:

<body ng-controller="MainCtrl" ng-class="isAnimated" class="ng-scope not-animated">
    <p class="ng-binding">Hello World!</p>
    <div ng-controller="FirstCtrl" ng-class="isAnimated" class="ng-scope not-animated">Foo</div>
    <div ng-controller="SecondCtrl" ng-class="isAnimated" class="ng-scope animated">Bar</div>   
</body>

DEMO

You can build a controller that listens for route changes and sets a class accordingly. You will then be able to target the correct animation using CSS.

<body ng-controller="TranisitionCtrl" ng-class="currentRoute">
  <div ng-view ng-animate></div>
</body>

app.controller('TranisitionCtrl', function($scope) {
  $scope.$on('$routeChangeStart', function(ev, next, current) { 
    $scope.currentRoute = current.name;
  });
}); 

Please note $routeChangeStart has been changed to $locationChangeStart for more recent versions of angular.

I've answered another similar question here Two different animations for route changes

One way to exclude a specific route from the animation is to use a JS animation wrapper that will take over setting of the animation class for your ng-view. You need one additional class to handle the non-animated ng-leave when you are going back to the non-animated route.

Here is a sample JS wrapper that check for a custom animate attribute in your route to decide if a route is animated or not:

app.animation('.slider', function($log, $route) {
  return {
    //call done when the animation is over
    enter : function(element, done) {
      if ($route.current.animate) {
        element.addClass("slide ng-enter");
      }
      done();
    },
    leave : function(element, done) {
      if ($route.current.animate) {
        element.addClass("slide ng-leave");
      } else {
        // Need to add non-animated version of ng-leave
        element.addClass("slide ng-leave-noanimation");
      }
      done();
    }
  }
});

Here is the working plunker:
http://plnkr.co/edit/ldCy9Cfz2lJWNuLzDIbp?p=preview

As far as i understand you, what you want is, that no animation happens if the user hits your site. But after that the animations should happen all the time. This is the shortest solution i know:

Use the module run method to disable all animations:

app.run(function($animate){
    $animate.enabled(false);
});

In your controller that is bound to / reenable the animations, but delayed for one digest cycle:

.controller('rootController', function($timeout, $animate){
    $timeout(function(){
        $animate.enabled(true);
    });
})
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top