ngAnimate - Sliding both ways
Asked Answered
P

1

9

I'm struggling with an issue: I have a menu with x-amount of items. In this example, I have three items.

Each item has a content section, so by clicking on the menu item, the content should slide in.

What I have achieved so far, is that when you're starting from "item 1" and changing to "item 2" will do the animation (sliding from right to left, like a powerpoint slide)

But I'd like the reverse effect as well, so it would slide from right to left when going from "item 2" to "item 1". I just can't figure it out how to do this for both ways.

So what I'm asking for is some kind of carousel with ngAnimate, so I won't have to revert back to jQuery for these kind of animations. I'd like to cut out jQuery from my project while using AngularJS.

console.clear();
var _app = angular.module("animate", ['ngAnimate']);

_app.directive("animate", [function() {
  return {
    scope: {},
    template: '<div class="header">' +
      '		<ul>' +
      '			<li data-ng-repeat="item in items" data-ng-click="move($index)">' +
      '				<div>{{item}}</div>' +
      '			</li>' +
      '		</ul>' +
      '</div>' +
      '<div class="wrapper" style="position: relative; margin-top: 20px;">' +
      '		<div data-ng-if="index == 0" class="slide slide-left">Content 1</div>' +
      '		<div data-ng-if="index == 1" class="slide slide-left">Content 2</div>' +
      '		<div data-ng-if="index == 2" class="slide slide-left">Content 3</div>' +
      '</div>',
    link: function(scope, elem, attr) {
      scope.items = ["Item 1", "Item 2", "Item 3"]
      scope.index = 0;

      scope.move = function(index) {
        scope.index = index;
      }
    }
  }
}]);
body {
  font-family: Arial, Sans-Serif;
}

.header {
  width: 100%;
  height: 50px;
  background-color: lightblue;
  position: relative;
}

.header ul {
  padding: 0;
  height: inherit;
}

.header ul li {
  display: inline;
  width: 33%;
  height: inherit;
}

.header ul li div {
  float: left;
  width: 33%;
  text-align: center;
  height: inherit;
  border: 1px solid black;
}

.slide {
  -webkit-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
  -moz-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
  -o-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
  transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 2s;
  position: absolute;
}

.slide-left.ng-enter {
  left: 100%;
}

.slide-left.ng-enter.ng-enter-active {
  left: 0;
}

.slide-left.ng-leave {
  left: 0;
}

.slide-left.ng-leave.ng-leave-active {
  left: -100%;
}

.slide-right.ng-enter {
  left: -100%;
}

.slide-right.ng-enter.ng-enter-active {
  left: 0
}

.slide-right.ng-leave {
  left: 0;
}

.slide-right.ng-leave.ng-leave-active {
  left: 100%;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-animate.js"></script>
<div ng-app="animate">
  <animate></animate>
</div>
Pressing answered 1/3, 2017 at 21:17 Comment(0)
F
4

In order to have a carousel effect, you need to switch the slide class based on the index you are transitioning to, so you use ngClass and change the class from slide-left to slide-right when moving to a lower index and vice-versa.

However, for the disappearing element the ngIf hides the element before the class is updated, so you need to delay the transitions to make sure ngClass is executed first. One way to do that is by using the $timeout function, which needs to be injected into your directive.

Your code becomes:

_app.directive("animate", ['$timeout', function($timeout) {
  return {
    scope: {},
    template: '<div class="header">' +
      '     <ul>' +
      '         <li data-ng-repeat="item in items" data-ng-click="move($index)">' +
      '             <div>{{item}}</div>' +
      '         </li>' +
      '     </ul>' +
      '</div>' +
      '<div class="wrapper" style="position: relative; margin-top: 20px;">' +
      '     <div data-ng-if="index == 0" class="slide" ng-class="slideClass">Content 1</div>' +
      '     <div data-ng-if="index == 1" class="slide" ng-class="slideClass">Content 2</div>' +
      '     <div data-ng-if="index == 2" class="slide" ng-class="slideClass">Content 3</div>' +
      '</div>',
    link: function(scope, elem, attr) {
      scope.items = ["Item 1", "Item 2", "Item 3"]
      scope.index = 0;
      scope.slideClass = 'slide-left';

      scope.move = function(index) {
        scope.slideClass = index < scope.index
                         ? scope.slideClass = 'slide-right'
                         : scope.slideClass = 'slide-left';

        $timeout(function() {
          scope.index = index;
        });
      }
    }
  }
}]);

Check this sample.

Also, if you already have UI Bootstrap you might want to try their carousel component.

Finstad answered 7/3, 2017 at 23:20 Comment(3)
Doesn't do what I expected :/ sliding from content 1 to content 2 goes from left to right, not really what a carousel would do. But I appreciate the answer, I'll have a look into the UI Bootstrap when I get the time to do so :)Pressing
@Pressing please take a look at the edited answer, I guess it now works the way you wanted.Finstad
Yes! That's what I wanted. Thank you so much, I could not figure it out and got stuck on this for so long. Reading your code now, it seems so easy ..Pressing

© 2022 - 2024 — McMap. All rights reserved.