Reputation: 1624
For my directive I'm trying to use the animate service:
$animate.addClass(clickedCard, "translate-to-player-spot-1", function () {
alert('wooo!');
});
But this fires the alert right away and the animation isn't taking place! I need to perform functions at the end of the animations.
Update I changed the Angular version to 1.3.6 and now get the error:
TypeError: Cannot read property 'parentNode' of undefined
at http://192.168.0.102/CardGame/js/angular-animate.min.js:20:254
at http://192.168.0.102/CardGame/js/angular-animate.min.js:8:69
at k.$digest (http://192.168.0.102/CardGame/js/angular.min.js:124:43)
at k.scopePrototype.$digest (chrome-extension://ighdmehidhipcmcojjgiloacoafjmpfk/dist/hint.js:1468:23)
at k.$apply (http://192.168.0.102/CardGame/js/angular.min.js:126:58)
at k.scopePrototype.$apply (chrome-extension://ighdmehidhipcmcojjgiloacoafjmpfk/dist/hint.js:1478:22)
at HTMLDivElement.<anonymous> (chrome-extension://ighdmehidhipcmcojjgiloacoafjmpfk/dist/hint.js:797:25)
at HTMLDivElement.c (http://192.168.0.102/CardGame/js/angular.min.js:32:285)
The CSS looks like:
.translate-to-player-spot-1 {
transform: translate(0px,-270px);
transition: transform 50s linear;
}
If I add ng-class="card.moveTo"
to the HTML and set in the directive:
clickedCard.moveTo = 'translate-to-player-spot-1'
Then it does actually go through the animation and all kinds of angular classes get added:
ng-animate translate-to-player-spot-1-add translate-to-player-spot-1 translate-to-player-spot-1-add-active
I have a feeling I'm not understanding the animation in AngularJS - can someone please shed some light?
Thanks!
The HTML:
<div id="{{card.id}}" ng-class="card.moveTo" class="card-wrap card-art card-art-{{card.back}} ready-to-move-{{card.readyToMove}}" ng-click="click()" ng-repeat="card in cardsCtrl.cards">
<div ng-class="card.name" class="card-art">
<div class="card"></div>
</div>
</div>
Relevant directive:
app.directive('playerHandTemplate', function(PlayerHand, PlayerPlayed) {
return {
restrict: 'E',
templateUrl: 'templates/card.html',
scope:{},
link: function(scope, element, $animate) {
element.on('click', function() {
scope.$apply(function() {
$animate.addClass(element, 'translate-to-player-spot-1');
})});
},
controller: function($scope, $animate) {
this.cards = PlayerHand.getHand();
$scope.click = function() {
var clickedCard = this.card;
if (clickedCard.readyToMove === true) {
$animate.addClass(clickedCard, "translate-to-player-spot-1", function () {
alert('wooo!');
});
} else {
PlayerHand.changeReadyToMove(clickedCard);
}
}
},
controllerAs: 'cardsCtrl'
};
});
PlayerHand is a service and getHand() just returns an array of objects.
Upvotes: 2
Views: 2955
Reputation: 38490
You get the error TypeError: Cannot read property 'parentNode' of undefined
because in the following code clickedCard
is not a DOM element:
$animate.addClass(clickedCard, "translate-to-player-spot-1", function () {
alert('wooo!');
});
In your link
function you have the following:
element.on('click', function() {
scope.$apply(function() {
$animate.addClass(element, 'translate-to-player-spot-1');
});
});
This will not work as expected.
Consider the following simplified example of the rendered HTML:
<player-hand-template>
<card></card>
<card></card>
<card></card>
</player-hand-template>
The element
passed to the link
function will be player-hand-template
, not a single card.
What you can do instead is the following:
Change your ng-click
to the following: ng-click="click(card, $event)"
And in your controller:
$scope.click = function(card, event) {
var clickedElement = event.currentTarget;
}
Now you have access to both the object representing the card and the associated DOM element and can for example do:
$scope.click = function(card, event) {
if (card.hasMoved) return;
card.hasMoved = true;
var clickedElement = event.currentTarget;
var promise = $animate.addClass(clickedElement, 'translate-to-player-spot-1');
promise.then(function() {
console.log('Done.');
});
};
As you see above, in Angular 1.3, $animate.addClass
does not take a callback function as an argument but instead returns a promise.
Demo: http://plnkr.co/edit/5Gf2ApyxEKgGQAs98IjG?p=preview
Note that in this case you could as well move the click logic into the link
function. If you actually should move it or not is hard to say without seeing the full picture. Usually you use controller
when you want to expose an API to other directives (since they can inject the controller), otherwise you use link
.
Upvotes: 2