Home > Net >  Vue throws error on accessing a field in an array of object
Vue throws error on accessing a field in an array of object

Time:07-29

So I have the following structure:

    rules:[
    0:{
      subrule1:'',
      subrule2:'',
      subrule3:''
    },
    
    1:{
      subrule1:'',
      subrule2:'',
      subrule3:''
    }   
   ]

and I loop through this structure like this:

<div v-for="(fields, index) in rules" :key="index">

    <div>
      <button @click.prevent="addMore()">
        Add Rules
      </button>
    </div>

    <div>
       <button @click.prevent="deleteSubrule(index)">
          Delete
       </button>    
    </div>

      <input
        name="subrule1"             
        :value="getAdditionalIndex(index, 'subrule1')"
       />

      <input
        name="subrule2"             
        :value="getAdditionalIndex(index, 'subrule2')"
       />

      <input
        name="subrule3"             
        :value="getAdditionalIndex(index, 'subrule3')"
       />

</div>

here are the methods:

   getAdditionalIndex(index, field) {
      return this.rules[index][field];
   },

  addMore(){
    const fields = {
        subrule1:'',
        subrule2:'',
        subrule3:''
      };

    this.rules.push(fields)
  },

  deleteSubrule(index){
    this.$delete(this.rules, index)
  }

It won't bind and it throws error on deletion. I did some searching and most people say that deep watchers however their utilization of deep watchers are usually used with child components and not on v-for. Is there a way to utilize deep watchers in this way?

here's a runnable snippet:

  
<html>
<div id="app">

    <div>
      <button @click.prevent="addMore()">
        Add Rules
      </button>
    </div>

    <div>
     <button @click.prevent="showStates()">
        Show state results
      </button>
    </div>
  <div v-for="(fields, index) in rules" :key="index">
    <div>
       <button @click.prevent="deleteSubrule(index)">
          Delete
       </button>    
    </div>

      <input
        name="subrule1"             
        :value="getAdditionalIndex(index, 'subrule1')"
        @input="inputChange"
       />

      <input
        name="subrule2"             
        :value="getAdditionalIndex(index, 'subrule2')"
        @input="inputChange"
       />

      <input
        name="subrule3"             
        :value="getAdditionalIndex(index, 'subrule3')"
        @input="inputChange"
       />

      </div>
</div>

<!-- Don't forget to include Vue from CDN! -->
<script src="https://unpkg.com/vue@2"></script>
<script>
  new Vue({
    el: '#app', //Tells Vue to render in HTML element with id "app"
    data() {
      return {
         rules:[],
         test:''
      }
    
    },
    
    methods:{ 
       addMore(){
          const fields = {
            subrule1:'',
            subrule2:'',
            subrule3:''
          };
        this.rules.push(fields)
      },
      
       deleteSubrule(index){
       this.$delete(this.rules, index)
       },
       
       
      getAdditionalIndex(index, field) {
      return this.rules[index][field];
      },
      
      inputChange(event){
        return event.target.value
      },
      
      
      showStates(){
        alert(JSON.stringify(this.rules))
      }
      
      
      
       
       
      
      
      
    }
  });
</script>
</html>

CodePudding user response:

Instead of passing the term additional, you should be passing the index to the getAdditionalIndex method

<html>
<div id="app">

    <div>
      <button @click.prevent="addMore()">
        Add Rules
      </button>
    </div>
  <div v-for="(fields, index) in rules" :key="index">
    <div>
       <button @click.prevent="deleteSubrule(index)">
          Delete
       </button>    
    </div>

      <input
        name="subrule1"             
        :value="getAdditionalIndex(index, 'subrule1')"
       />

      <input
        name="subrule2"             
        :value="getAdditionalIndex(index, 'subrule2')"
       />

      <input
        name="subrule3"             
        :value="getAdditionalIndex(index, 'subrule3')"
       />

</div>
</div>

<!-- Don't forget to include Vue from CDN! -->
<script src="https://unpkg.com/vue@2"></script>
<script>
  new Vue({
    el: '#app', //Tells Vue to render in HTML element with id "app"
    data() {
      return {
         rules:[]
      }
    
    },
    
    methods:{ 
       addMore(){
          const fields = {
            subrule1:'',
            subrule2:'',
            subrule3:''
          };
        this.rules.push(fields)
      },
      
       deleteSubrule(index){
       this.$delete(this.rules, index)
       },
       
       
      getAdditionalIndex(index, field) {
      return this.rules[index][field];
      },
       
       
      
      
      
    }
  });
</script>
</html>

But I would suggest you to use v-model in the input fields to prevent it from getting emptied as you add new rows, therefore you no longer need the getAdditionalIndex method

<html>
<div id="app">

    <div>
      <button @click.prevent="addMore">
        Add Rules
      </button>
    </div>
  <div v-for="(fields, index) in rules" :key="index">
    <div>
       <button @click.prevent="deleteSubrule(index)">
          Delete
       </button>    
    </div>

      <input
        name="subrule1"             
        v-model="fields.subrule1"
       />

      <input
        name="subrule2"             
        v-model="fields.subrule2"
       />

      <input
        name="subrule3"             
        v-model="fields.subrule3"
       />

</div>
</div>

<!-- Don't forget to include Vue from CDN! -->
<script src="https://unpkg.com/vue@2"></script>
<script>
  new Vue({
    el: '#app', //Tells Vue to render in HTML element with id "app"
    data() {
      return {
         rules:[]
      }
    
    },
    
    methods:{ 
       addMore(){
          const fields = {
            subrule1:'',
            subrule2:'',
            subrule3:''
          };
        this.rules.push(fields)
      },
      
       deleteSubrule(index){
       this.$delete(this.rules, index)
       },     
    }
  });
</script>
</html>

  • Related