Search code examples
vue-componentvuejs3prop

Vue 3: Append to child component prop


I am creating a little puzzle game to learn Vue 3 and got stuck, when trying to append values to an array in a child component.

This is the parent:

<template>
  <div class="home">
    <Puzzle :guess="puzzleGuess" />
  </div>
</template>

This is the child component 'Puzzle':

<template>
    <div>
        <div class="row">
            <img :src="require(`@/assets/${imgPath}`)" alt="Puzzle image" class="puzzleImage" >
        </div>
        <div class="row puzzleIcon" :key="i" v-for="(char, i) in word">
            <span v-if="hasGuessedChar(char)">{{char}}</span>
            <span v-else>
                <i class="large material-icons">remove</i>
            </span>
        </div>
    </div>
</template>

<script>
    export default {
        name: 'Puzzle',
        props: {
            word: Array,
            imgPath: String,
            guess: Array,
        },
        methods: {
            hasGuessedChar(char) {
                if(char == '') return false;

                if(this.guess.indexOf(char) > -1) return true;
           
                return false;
            }
        }
    }    
</script>

Basically, I would like to push a char to the guess array property of the child component, whenever the prop puzzleGuess is updated in the parent component. With the current posted code, I just keep on overwriting the guess variable instead of appending to it.


Solution

  • Inspired by the suggested answer from @MohKoma, I arrived at this solution (unsure if it is the same as @Mohkoma suggested):

    Parent component:

    <template>
      <div class="home">
        <Puzzle :guess="puzzleGuess" />
        <hr />
        <div class="letters-container">
            <Letters @clickLetter="clickLetter" />
        </div>
      </div>
    </template>
    
    <script>      
    export default {
      name: 'Home',
      components: {
        Letters,
        Puzzle
      },
      data() {
        return{          
          puzzleGuess: []
        }
      },
      methods: {
        clickLetter(letter) {
          this.puzzleGuess.push(letter.val.toLowerCase());
        }
      }
    }
    </script>
    

    ...and child component remains unchanged:

    <template>
        <div>
            <div class="row puzzleIcon" :key="i" v-for="(char, i) in word">
                <span v-if="hasGuessedChar(char)">{{char}}</span>
                <span v-else>
                    <i class="large material-icons">remove</i>
                </span>
            </div>
        </div>
    </template>
    
    <script>
        export default {
            name: 'Puzzle',
            props: {
                word: Array,
                guess: Array,
            },
            methods: {
                hasGuessedChar(char) {
                    if(char == '') return false;
    
                    if(this.guess.indexOf(char) > -1) return true;
                    
                    return false;
                }
            }
        }    
    </script>
    

    So basically, instead of trying to push a value to the array in the child component, I push the value to a local array and then pass that array down to the child component