I write an angular directive called 'cardViewer', which can show images inside it with animation.
When you press "prev" button, image slides left. When you press "next" button, image slides right.
I try to do this with ng-switch
, which only supports .ng-enter
and .ng-leave
animation class. But I need two ways to enter(enter from left and right), two ways to leave(leave to left and right).
So I try ng-class
to solve this problem. I hope it can add toLeft
class before it switch, so it can apply specific css animation.
But it seems not working properly. When I press "next" button twice, it works fine. but when I press "next", then press "prev", new image enter in right direction, but old image leave in wrong direction.
My directive template:
<h1>hahaha</h1>
<div>
<button ng-click='prev()'>prev</button>
<button ng-click='next()'>next</button>
</div>
<div>current Card Index: {{displayCard}}</div>
<div class="card-container" ng-switch="displayCard">
<img class="card"
src="http://i.imgur.com/EJRdIcf.jpg" ng-switch-when="1"
ng-class="{'toLeft': toLeft, 'toRight': toRight}"/>
<img class="card"
src="http://i.imgur.com/StaoX5y.jpg" ng-switch-when="2"
ng-class="{'toLeft': toLeft, 'toRight': toRight}"/>
<img class="card"
src="http://i.imgur.com/eNcDvLE.jpg" ng-switch-when="3"
ng-class="{'toLeft': toLeft, 'toRight': toRight}"/>
</div>
directive:
angular.module('app', ['ngAnimate'])
.directive('cardViewer', function() {
return {
templateUrl: 'cardViewer.html',
link: function(scope, element, attr) {
scope.toLeft = false;
scope.toRight = false;
scope.displayCard = 1;
//when press prev, card slide to left
scope.prev = function() {
scope.toLeft = true;
scope.toRight = false;
if (scope.displayCard == 1) {
scope.displayCard = 3
} else {
scope.displayCard -= 1;
}
};
//when press prev, card slide to right
scope.next = function() {
scope.toLeft = false;
scope.toRight = true;
if (scope.displayCard == 3) {
scope.displayCard = 1
} else {
scope.displayCard += 1;
}
};
}
}
});
css:
.card-container {
position: relative;
height: 500px;
overflow: hidden;
}
.card {
width: 100%;
position: absolute;
}
.card.ng-animate {
transition: 1s linear all;
}
.card.ng-enter.toLeft {
left: 100%;
}
.card.ng-enter-active.toLeft {
left: 0;
}
.card.ng-leave.toLeft {
left: 0;
}
.card.ng-leave-active.toLeft {
left: -100%;
}
.card.ng-enter.toRight {
left: -100%;
}
.card.ng-enter-active.toRight {
left: 0;
}
.card.ng-leave.toRight {
left: 0;
}
.card.ng-leave-active.toRight {
left: 100%;
}
Here is my plunker: cardViewer
What's wrong with my code? What's the right way to make ng-switch enter/leave in more than one way?
The problem is that ngSwitch
is destroying the scope of the current image before ngClass
has a chance to execute and change that image's class from toRight
to toLeft
(or vice versa) before the animation starts.
ngSwitch creates a new scope and executes at priority level 1200, while ngClass executes at priority level 0.
To make it work, you just need to update your next
and prev
methods so they set the displayCard
property in a $timeout
, after toLeft
and toRight
are set, so ngClass
has an opportunity to act on the new toLeft
/toRight
settings before ngSwitch
destroys that scope.
So your next
method, for example, would look like this:
scope.next = function() {
scope.toLeft = false;
scope.toRight = true;
// need to do this in a $timeout so ngClass has
// chance to update the current image's class based
// on the new toLeft and toRight settings before
// ngSwitch acts on the new displayCard setting
// and destroys the current images's scope.
$timeout(function () {
if (scope.displayCard == 3) {
scope.displayCard = 1
} else {
scope.displayCard += 1;
}
}, 0);
};
Here's a fork your plunk showing it working. Open the console to see log messages for when ngClass
adds your classes and ngSwitch
destroys and creates the scopes.
I left your original "next" and "prev" buttons there and just added "next (fixed)" and "prev (fixed)" buttons so you can compare the log messages and see how, using the original buttons, ngSwitch
destroys the scope before ngClass
executes, while in the fixed versions ngClass
executes before ngSwitch
destroys the scope.