6
<template>
  <div class="container">
    <div class="gameboard">
      <div v-for="item in boardfields" :key="item.number">
        {{ item.number }}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  components: {},

  data() {
    return {
      boardfields: [
        { number: 1, isclicked: false },
        { number: 2, isclicked: false },
        { number: 3, isclicked: false },
        { number: 4, isclicked: false },
        { number: 5, isclicked: false },
        { number: 6, isclicked: false },
      ],
    };
  },

As you can see I have a few similar objects in the 'boardfields' array. I have to make around 50 of those. Is there a way to create a loop that creates a certain amount of this object with a different number and pushing it to the array so I don't have to copy and paste it and manually change the numbers?

I think in JS it would be something like

var i;
for (var i = 0, i > 50, i++){
  this.boardfields.push({number: i, isclicked: false});
}

3 Answers 3

4

I think @Boussadjra's answer is correct, but wanted to add some context.

The functional [...Array(50)].map()...etc is the popular way to go these days. You can populate the value on data definition or onmount or oncreate, there are some nuances that might be worthwhile considering.

Note that if you are using:

const initialBoard = []
for (var i = 1; i <= 50; i++) {
  initialBoard.push({number: i, isclicked: false});
}

export default {
  name: "App",
  components: {},

  data() {
    return {
      boardfields: initialBoard
    };
  },
}

The value of initialBoard is persistent. The objects are created on first run and are populating the array which is re-used. That means if you create two components, they may share the values of the objects inside the array. IMHO, this is a a side effect you want to avoid unless you explicitly looking for that functionality, even if you only use one instance of the component.

B's solution...

export default {
  name: "App",
  components: {},

  data() {
    return {
      boardfields: [],
    };
  },
  mounted() {
    this.boardFields=[...Array(50)].map((_,i)=>({number: i+1, isclicked: false}))
  }
}

Is safer in that regard, since it generates a new array with new objects every time it is mounted. My preference would be to use created, because it will make the data available on the first draw, but because the variable is preset to an empty array, it's not going to cause errors (like an error in your template if the variable had .length on undefined or null)

Here is an example that illustrates the difference. Not that when the component is remounted or recreated (doesn't make a difference which on here) the data is lost, but the (top) two components don't share the data., whereas the bottom two do.

const app = Vue.createApp({
  data: function() {
    return {
      cKey: 1
    }
  }
})

const prepArr = [...Array(5)].map((_, i) => ({
  name: 'item-' + i
}))

app.component("my-component", {
  data: function() {
    return {
      myArr: []
    }
  },
  created: function() {
    this.myArr = [...Array(5)].map((_, i) => ({
      name: 'item-' + i
    }))
  },
  template: `<div class="h">Component Using created<ul>
    <li v-for="item in myArr">{{ item.name }} <button  @click="()=>{item.name = item.name +'!'}">+</button></li>
  </ul></div>`
});


app.component("persistent-component", {
  data: function() {
    return {
      myArr: prepArr
    }
  },
  template: `<div class="h">Component using persistent<ul>
    <li v-for="item in myArr">{{ item.name }} <button  @click="()=>{item.name = item.name +'!'}">+</button></li>
  </ul></div>`
});


app.mount('#app')
.h{display: inline-block; width: 49%;}
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>

<div id="app">
  <div><button @click="()=>{cKey++}">regenerate</button></div>
  <my-component :key="cKey"></my-component>
  <my-component :key="cKey"></my-component>
  <persistent-component :key="cKey"></persistent-component>
  <persistent-component :key="cKey"></persistent-component>
</div>

Sign up to request clarification or add additional context in comments.

Comments

3

You could achieve this by using [...Array(50)] which returns 50 items with undefined values then map this array to return your objects array, this is done in the mounted lifecycle hook :

export default {
  name: "App",
  components: {},
  data() {
    return {
      boardfields: [],
    };
  },
  mounted(){
    this.boardFields=[...Array(50)].map((_,i)=>({number: i+1, isclicked: false}))
  }
}

Comments

2

You can run any valid javascript code inside the <script> tag, so this will work

<script>

const initialBoard = []
for (var i = 1; i <= 50; i++) {
  initialBoard.push({number: i, isclicked: false});
}

export default {
  name: "App",
  components: {},

  data() {
    return {
      boardfields: initialBoard
    };
  },

@Daniel - thanks for the clarification. Upvote for Boussadjra Brahim's answer which is better.


Use a "factory" function to create the data if you wish to have independent boardfields per component.

<script>

const initializeBoard = () => {
  const initialBoard = [];
  for (var i = 1; i <= 50; i++) {
    initialBoard.push({number: i, isclicked: false});
  }
  return initialBoard;
}

export default {
  name: "App",
  components: {},

  data() {
    return {
      boardfields: initializeBoard()
    };
  },

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.