Chobbit
Chobbit

Reputation: 654

Vue.js update html with data at specific index value

I'm just playing with a mix of vue.js and vanilla to try and create a blackjack game. I'm storing all the cards data in the vue data(), eg:

data(){
  return {
    cards: [
      {id: 1, cardName: 'Ace of Spades', cardPic: '🂡', color: 'black', value: 1},
      {id: 2, cardName: 'Ace of Clubs', cardPic: '🃑', color: 'black', value: 1},
      {id: 3, cardName: 'Ace of Heats', cardPic: '🂱', color: 'red', value: 1},
      {id: 4, cardName: 'Ace of Diamonds', cardPic: '🃁', color: 'red', value: 1},
    ]
  }
} 

I also have a randomiser built to pick a random number that can be used to grab the card at the same index value in the data. I have then been able to manually get card data at an index value pulled in to the HTML with something like this (for the first card in index value 0):

<div class="card">
    <div class="cPic" v-bind:style="{color: cards[0].color}">{{cards[0].cardPic}}</div>
    <div class="cName">{{cards[0].cardName}}</div>
</div>

However I want to update this HTML dynamically when clicking to draw a new card, with the data from a new random index value, ie:

{{cards[3].cardPic}} or {{cards[1].cardPic}}

and I tried simply updating the HTML with this (randomised number is stored in the variable randomCard):

document.querySelector('.card').innerHTML = `
    <div class="cPic" v-bind:style="{color: cards[` + randomCard + `].color}">{{cards[` + randomCard + `].cardPic}}</div>
    <div class="cName">{{cards[` + randomCard + `].cardName}}</div>
`;

However as I half expected updating the DOM like this doesn't work and although it pulls in the random number it doesn't pull in the actual data from the Vue data(). I've not been able to work out how to actually do it another way.

Any help on how can I update the card with the new data at the randomised index value? Thanks

Upvotes: 1

Views: 76

Answers (1)

Alexander Nenashev
Alexander Nenashev

Reputation: 22802

Don't manipulate DOM in Vue (manipulate VDOM if needed) since it's overridden by Vue anyway on updates.

Use a ref for the randomly selected card:

See on Vue SFC Playground

<script setup>
import { ref } from 'vue'

const cards = [
      {id: 1, cardName: 'Ace of Spades', cardPic: '🂡', color: 'black', value: 1},
      {id: 2, cardName: 'Ace of Clubs', cardPic: '🃑', color: 'black', value: 1},
      {id: 3, cardName: 'Ace of Heats', cardPic: '🂱', color: 'red', value: 1},
      {id: 4, cardName: 'Ace of Diamonds', cardPic: '🃁', color: 'red', value: 1},
    ]

const card = ref();

pickCard();

function pickCard(){
  card.value = cards[cards.length * Math.random() | 0];
}

</script>

<template>
<div class="card">
    <div class="cPic" v-bind:style="{color: card.color}">{{card.cardPic}}</div>
    <div class="cName">{{card.cardName}}</div>
</div>
<button @click="pickCard">Pick card</button>
</template>

const { ref, createApp } = Vue;

const cards = [
      {id: 1, cardName: 'Ace of Spades', cardPic: '🂡', color: 'black', value: 1},
      {id: 2, cardName: 'Ace of Clubs', cardPic: '🃑', color: 'black', value: 1},
      {id: 3, cardName: 'Ace of Heats', cardPic: '🂱', color: 'red', value: 1},
      {id: 4, cardName: 'Ace of Diamonds', cardPic: '🃁', color: 'red', value: 1},
    ];

const App = {
  template: `
    <div class="card">
        <div class="cPic" v-bind:style="{color: card.color}">{{card.cardPic}}</div>
        <div class="cName">{{card.cardName}}</div>
    </div>
    <button @click="pickCard">Pick card</button>
  `,
  setup(props){
    const card = ref();

    pickCard();

    function pickCard(){
      card.value = cards[cards.length * Math.random() | 0];
    }
    return {
      card,
      pickCard
    }
  }
};

createApp(App).mount('#app');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script>
<div id="app"></div>

Upvotes: 1

Related Questions