GDC
GDC

Reputation: 53

Change background color of a single mat-card in Angular

This is the HTML code of my mat-card list in my Angular application:

<div [ngClass]="verticalResultsBarStyle">
  <div class="innerDiv">
    <mat-card [ngClass]="barStyle" *ngFor="let card of obs | async | paginate: { id: 'paginator', itemsPerPage: 10, currentPage: currentPage, totalItems: totalItems }" (click)="highlightCard()">
      <mat-card-header>
        <mat-card-title>{{card[0].title}}</mat-card-title>
        <mat-card-subtitle>{{card[0].subtitle}}</mat-card-subtitle>
      </mat-card-header>
      <mat-card-content>
        <p>{{card[0].info1}}</p>
        <p>{{card[0].info2}}</p>
        <p>{{card[0].info3}}</p>
        <p>{{card[0].info4}}</p>
        <p>{{card[0].info5}}</p>
      </mat-card-content>
    </mat-card>
    <pagination-controls (pageChange)="OnPaginateChange($event)" id="paginator"></pagination-controls>
  </div>
</div>

this is the CSS:

.verticalResultsBarContainerEnabled {

  background-color: #eeeeee;
  width: 16%;
  float: right;
  overflow: visible;

}

.verticalResultsBarContainerDisabled {
  display: none;
}

.card {

  margin-left: 10px;
  margin-right: 10px;
  margin-bottom: 10px;

}

.cardHighlight {

  margin-left: 10px;
  margin-right: 10px;
  margin-bottom: 10px;
  background-color: #c12400;
  color: white;
}

.innerDiv {
  height: 755px;
  overflow: auto;
}

.paginator {
  margin: auto;
  width: 92%;
}

and finally this is a snippet of TS :

highlightCard() {
    if (this.barStyle === 'card') {
      this.barStyle = 'cardHighlight';
    } else {
      this.barStyle = 'card';
    }
  }

I would to click on a single mat card and highlight only the selected mat card, but when I click on a single card, the entire list changes color. How can I fix that?

Upvotes: 0

Views: 7417

Answers (1)

AlleXyS
AlleXyS

Reputation: 2598

You need to use index for each of your cards. Your issue is normal.

I see barStyle is one generall for all your cards. You need to update barStyle for each card, when your cards come from backend.

First, in your .ts :

service.subscribe(cards => {
let i = 0
cards.forEach(card => {
  this.barStyle[i] = // your default barStyle;
  i++;
});

If you have an id for each car, better, you can avoid to use i. then, in template:

<mat-card [ngClass]="barStyle[i]" *ngFor="let card of obs; let i = index | async | paginate: { id: 'paginator', itemsPerPage: 10, currentPage: currentPage, totalItems: totalItems }" (click)="highlightCard(i)">

I see you use async function in template. So, in ts, you expect and Observable. To update style of each card, you need to subscribe at your service and update objects. So, need to do some changes:

cards: Observable will become cards: Card[];

loadingData = true;

call the service as:

getData() {
    this.loadingData = true;
    service().subscribe(cards => {
    cards.forEach(card => {
        this.barStyle[card.id] = // your default barStyle;
        this.cards = cards;
        this.loadingData = false; // this is set false only after data is loaded
    });
}

highlightCard(id: number) {
    if (this.barStyle[id] === 'card') {
      this.barStyle[id] = 'cardHighlight';
    } else {
      this.barStyle[id] = 'card';
    }
  }

in template:

  <mat-card ***ngIf="!loadingData"** 
     [ngClass]="barStyle[card.id]" 
     *ngFor="let card of obs | async | 
        paginate: { id: 'paginator', 
                    itemsPerPage: 10, 
                    currentPage: currentPage, 
                    totalItems: totalItems }" 
     (click)="highlightCard(card.id)">

Somethimes, your template will render before to load data, so you need to use a boolean to wait for it.

**To keep clean code, for pagination you can use a variable initialized in .ts*

Upvotes: 1

Related Questions