Bry
Bry

Reputation: 15

VueJS Components inside a loop act as one

UPDATE Was able to make it work, but got one last problem. Updated code is here: VueJs not working on first click or first event

-----------------------------------------------------------

I've been trying to find out a way for the components inside a loop to not act as one.

I have a loop (3 divs), and inside the loop, I have 2 textboxes. But whenever I enter a value in any of them, the value is populated to everyone.

Can anyone help me separate those components?

I'm trying to make the parent div (1st loop) dynamic. So the children components (2nd loop) should be acting separately with their own grandparent components (textbox).

Here's my code:

<div id="app">
    <div v-for="(ctr, c) in 3" :key="c">
      <button @click="input_add">1st</button>
      <div>
        <div v-for="(input, act) in inputs" :key="act.id">
          <input type="text" v-model="input.name"> 
          <input type="text" v-model="input.time">
          <button @click="input_remove(act)">Delete</button>
          <button @click="input_add">Add row</button>
        </div>
      </div>
      {{ inputs }}  
    </div>
  </div>
const app = new Vue({
    el: "#app",
    data: {
    inputs: [],
    counter: 0,
  },

  methods: {
    input_add() {
      this.inputs.push({
        id: this.counter + 1,
        day: null,
        name: null,
        time: null,
      })
      this.counter += 1
    },
    input_remove(index) {
      this.inputs.splice(index,1)
      this.counter -= 1
    }
  }
});

Result:

Result Screenshot

Upvotes: 1

Views: 3279

Answers (2)

yvl
yvl

Reputation: 670

as I mentioned in the comment, you should create a component for the iterated item.

parent component:

<div v-for="(item, index) in array" :key="index">        
    <child :item="item" />
</div>

Now you sent the item as prop. Let's catch it in child.

child components:

<div>
    <input type="text" v-model="input.name"> 
    <input type="text" v-model="input.time">
    <button @click="input_remove(act)">Delete</button>
    <button @click="input_add">Add row</button>
</div>
{{ inputs }}  

props: [item], // I am not sure you need it or not, BUT just showing how to do it.
data() {return { // your datas };},
methods: {
 // your methods...
},
//and else...

Now each iterated item can control self only. I am hope it make sense now.

then build the buttons an input in child component. After that you can apply the events for just clicked item.

Upvotes: 1

Reinier68
Reinier68

Reputation: 3324

You should use Array of Objects. Here's a codesandbox. This way everytime you add a new object to the array, a new index is created with a new name and time ready to be filled in.

<template>
  <div id="app">
    <img width="25%" src="./assets/logo.png">
    <div v-for="item in basic" :key="item.id">
      <button @click="addRow">Add row</button>
      <input type="text" v-model="item.name">
      <input type="text" v-model="item.time">
      {{ item.name }} - {{ item.time }}
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      id: 1,
      basic: [{ name: "", time: "" }]
    };
  },
  methods: {
    addRow() {
      console.log("added");
      this.id += 1;
      this.basic.push({
        name: "",
        time: ""
      });
    }
  }
};
</script>

Upvotes: 0

Related Questions