In Angular 1.x
this following code works as I want to to click and flip a card inside an ng-repeat
<div class="card" ng-repeat="let card of cards">
<div class="flipcard" ng-class="{'flipped':isflipped}" ng-click="isflipped = !isflipped">
</div>
</div>
However in Angular 2
when clicked, it flipped every "card" inside the ngFor loop... how do I bind the ngClass condition to the element itself only?
<div class="card" *ngFor="let card of cards">
<div class="flipcard" [ngClass]="{'flipped': isflipped }" (click)="isflipped = !isflipped;">
</div>
</div>
Change it to:
<div class="card" *ngFor="let card of cards">
<div class="flipcard" [ngClass]="{'flipped': card.isflipped }" (click)="card.isflipped = !card.isflipped;">
</div>
</div>
Why does it work with AngularJS (1.x) ?
ng-repeat
create a new scope for each iterated element, so the isFlipped
property is set on the iterated element scope (unique for each element):
ngRepeat
The ngRepeat
directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index
is set to the item index or key.
Why is it not working with Angular (2+) ?
Angular has no scope anymore, so when you set the isFlipped
property, it is on the current component, not anything related to the iterated element.
If card
elements are Objects :
For your particular case, it seems that every card is an Object, so you can just add a a property isFlipped
to every card
element like @Harry Ninh suggests it. Think to declare this property inside the class or interface that defines card
elements otherwise AOT compilation might fail.
If you don't want to add a contextual property onto your class/interface, see the "If there can be more than one flipped card(...)" part.
If there can be only one flipped card :
If you can only have one single flipped card, you can add a property currentCard
to your component and compare the iterated card to the current one inside your template :
component :
export class MyComponent{
// (...)
currentCard:Card;
// (...)
}
template :
<div class="card" *ngFor="let card of cards">
<div class="flipcard" [ngClass]="{'flipped': card===currentCard }" (click)="currentCard = card">
</div>
</div>
If there can be more than one flipped card and card
elements are not objects or can be null.
Well in this case you need to maintain the state flipped/ not flipped of each item, like using an array of boolean or an Object with card
value as key and boolean values
component :
export class MyComponent{
// (...)
cards: Card=[];
private flipped: boolean[];
flip(index:number){
this.flipped[index]=!this.flipped[index]
}
// (...)
}
template :
<div class="card" *ngFor="let card of cards: let i= index">
<div class="flipcard" [ngClass]="{'flipped': flipped[i] }" (click)="flip(i)">
</div>
</div>