nicholasfc
nicholasfc

Reputation: 185

Change Background on Table Cell based on Data in Vue

I'm currently trying to change the color of some cells on my table in a vue project. I read about class and style binding on the docs and on some other resources online but I couldn't get what I want working.

I have a table that is filled with data from firestore and based on the data I want to change the colors of some cells. The first cell is the one where it is displaying the person "rank", I want to give the .gold-star class if the person has a rank of "Gold Star", .silver-star if "Silver Star" and .bronze-star if "Bronze Star".

The second cell would be the one that shows the person total points, this cell will be based on a bunch of conditions based on the person ranks and their total points, for example if person rank is "Bronze Star" and the person has >50 points, I want do add the class .change-rank to the total cell so I know its time to change. Don't know if I made myself clear.

Here is the code so far for my table component (I trimmed it a little bit to make it easier to read).

<template>
  <div>
    <v-snackbar v-model="snackbar">
      <span>Player Added!</span>
      <v-btn color="blue" text @click="snackbar = false">Close</v-btn>
    </v-snackbar>
    <h3 class="font-weight-medium text-center pa-3 ma-3 display-1">Member List</h3>
    <template v-if="isMember || isAdmin">
      <v-simple-table fixed-header height="70vh">
        <template v-slot:default>
          <thead>
            <tr>
              <th class="text-left title">Name</th>
              <th class="text-left title">Rank</th>
              <th class="text-left title">Total</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(member, index) in members" :key="index">
              <td>
                {{member.name}}
              </td>
              <td>{{member.rank}}</td>
              <td>{{member.total}}</td>
            </tr>
          </tbody>
        </template>
</v-simple-table>
</template>

</div>
</template>

<script>
  import {
    db,
    fv,
    tstp
  } from "../data/firebaseInit";
  import firebase from "firebase/app";
  import Popup from "../components/Popup";
  export default {
    components: {
      Popup
    },
    data() {
      return {
        isAdmin: false,
        isMember: false,
        snackbar: false,
        members: []
      };
    },
    created() {
      this.fetchDb();
    },
    methods: {
      fetchDb() {
        db.collection("members")
          .orderBy("name")
          .onSnapshot(snap => {
            const members = [];
            snap.forEach(doc => {
              let newPlayer = doc.data();
              newPlayer.id = doc.id;
              members.push(newPlayer);
            });
            this.members = members;
          });
      }
    }
  };
</script>

<style scoped>
  h3 {
    text-decoration: underline;
    color: #37474f;
  }

  .gold-star {
    background-color: #ffee58;
  }

  .silver-star {
    background-color: #BDBDBD;
  }

  .bronze-star {
    background-color: #cd7f32;
  }

  .change-rank {
    background-color: #00C853;
  }
</style>

Upvotes: 3

Views: 2827

Answers (2)

AlekseyHoffman
AlekseyHoffman

Reputation: 2694

All you need to do is assign a class conditionally to each element in the loop:

<tr 
  v-for="(member, index) in members" 
  :key="index" 
  :class="{
    'gold-star': member.rank === 'Gold star',
    'silver-star': member.rank === 'Silver star',
    'bronze-star': member.rank === 'Bronze star',
  }"
>
...

Do the same thing for the points: 'change-rank': member.total > 50

You can also move this code to a method and make your HTML cleaner:

<tr 
  v-for="(member, index) in members" 
  :key="index" 
  :class="getTableClasses(member)"
>

...

methods: {
  getTableClasses(member) { 
   let color = member.rank.toLowerCase().replace(' ', '-')
   let changeRank = member.total > 50 ? 'change-rank' : ''
   return `${color} ${changeRank}`
  }
}

Upvotes: 3

Narendra Jadhav
Narendra Jadhav

Reputation: 10262

You can apply your class based on input. Simply create a object that contain class and value like below

const classes = {
  'Gold star': 'gold-star',
  'Silver star': 'silver-star',
  'Bronze star': 'bronze-star'
};

And when you doing looping just passed your rank value in above object so it will return the class name based on rank. like below

<td :class="classe[item.rank]">{{ item.rank }}</td>

You could check here with working Codepen demo.

CODE SNIPPET

<v-simple-table>
  <template v-slot:default>
        <thead>
          <tr>
            <th class="text-left title">Name</th>
            <th class="text-left title">Rank</th>
            <th class="text-left title">Total</th>
          </tr>
        </thead>
        <tbody>
         <tr v-for="(member, index) in members" :key="index">
              <td>{{member.name}}</td>
              <td :class="classe[item.rank]">{{ item.rank }}</td>
              <td>{{member.total}}</td>
            </tr>
        </tbody>
      </template>
</v-simple-table>

Upvotes: 1

Related Questions