Search code examples
javascriptvue.jstic-tac-toe

How to pass a prop to a parent component in Vue.js


I am developing a Vue-Tac-Toe application just 4 fun and i am just stuck a bit now.

Please see screenshot first to understand the context. vue-tac-toe stuck in logic


Problem: How can i pass the prop of cellRow to the component Field.vue?

What i want: Each Field should have a unique identification, for example the tile on the top left(first one) it should be recognized as cellRow: 0 & cellId: 0 because i need to have the information to simple check for a tic-tac-toe win(3 in a line etc.)


GameField.vue: We have a row and cell based layout.

<template>
  <div id="game-field">
    <div class="container">
      <template v-for="(rows, index) in 3">
        <Row :cell-row="index" />
      </template>
    </div>
  </div>
</template>

<script>
import Row from './Row.vue';

export default {
  components: {
    Row,
  },
  data() {
    return {};
  },
};
</script>

<style lang="scss" scoped>
.container {
    width: 400px;
    margin: 10% auto 0;
}
</style>

Row.Vue: Each row got 3 Fields. from 0-2.

<template lang="html">
  <div class="row">
    <Field
      v-for="(fieldId, index) in 3"
      :key="fieldId"
      :cell-id="index"
    />
  </div>
</template>

<script>
import Field from './Field.vue';

export default {
  components: {
    Field,
  },
  props: {
    cellRow: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {

    };
  },
};
</script>

<style lang="scss" scoped>
</style>

Field.vue:

<template lang="html">
  <div class="cell">
    <slot />
  </div>
</template>

<script>
export default {
  props: {
    cellId: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {};
  },
};
</script>

<style lang="scss" scoped>
  .cell {
    margin: 1px 3px -3px -1px;
    width: 100px;
    height: 100px;
    background-color: white;
    display: inline-block;
    cursor: pointer;
  }
</style>

Solution

  • If I understand the question correctly, you can pass cellRow prop of Row component further simply as a prop of Field component.

    Row (pass cellRow as a prop to Field)

    <template lang="html">
      <div class="row">
        <Field
          v-for="(fieldId, index) in 3"
          :key="fieldId"
          :cell-id="index"
          :row-id="cellRow" // passing row index to Field component
        />
      </div>
    </template>
    ...
    

    Field

    ...
    <script>
    export default {
      props: {
        cellId: {
          type: Number,
          default: 0,
        },
        rowId: {  // defining new prop type
          type: Number,
          default: 0,
        },
      },
      ...
    };
    </script>
    

    Here is a little demo:

    Vue.config.devtools = false;
    Vue.config.productionTip = false;
    
    
    Vue.component('Row', {
      template:
        `
    <div class="row">
      <Field
        v-for="(fieldId, index) in 3"
        :key="fieldId"
        :cell-id="index"
        :row-id="cellRow"
      />
    </div>
    `,
      props: {
        cellRow: {
          type: Number,
          default: 0
        }
      }
    })
    
    Vue.component('Field', {
      template:
        `
      <div class="cell">
        <p>Row Id: {{ rowId }}</p>
        <p>Cell Id: {{ cellId }}</p>
      </div>
    `,
      props: {
        cellId: {
          type: Number,
          default: 0
        },
        rowId: {
          type: Number,
          default: 0
        }
      }
    })
    
    new Vue({
      el: '#demo',
      template:
        `
    <div id="game-field">
        <div class="container">
          <template v-for="(rows, index) in 3">
            <Row :cell-row="index" />
          </template>
        </div>
      </div>
    `
    })
    .cell {
      margin: 1px 3px 3px 1px;
      width: 100px;
      height: 100px;
      background-color: gray;
      display: inline-block;
      cursor: pointer;
      color: white;
      padding: 5px;
    }
    .container {
        width: 400px;
        margin: 10% auto 0;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="demo"></div>