Search code examples
loopsvue.jspushslicev-for

Push and splice not updating or deleting in vue.js


I am trying to make a form repeater using an array and Vue v-for loop. but I could not able to push or slice anything in my array. I got some warning. TypeError: Cannot read property 'items' of undefined

Here is my code

<template>
  <b-form @submit.prevent="repeateAgain">
     <b-row
      v-for="(item, index) in items"
      :id="item.id"
      :key="item.id"
     >
       <b-col>
         <b-form-group>
           <b-form-input
            placeholder="Email"
           />
        </b-form-group>
      </b-col>
      <b-col>
        <b-form-group>
          <b-form-input placeholder="Email" />
        </b-form-group>
      </b-col>
      <b-col>
        <b-form-group>
           <b-form-input placeholder="Email" />
        </b-form-group>
      </b-col>
      <b-col>
        <b-form-group>
          <b-button
           variant="outline-danger"
            @click="removeItem(index)"
           >
            <i class="feather icon-x" />
             <span class="ml-25">Delete</span>
           </b-button>
         </b-form-group>
       </b-col>
     </b-row>
        <hr>
     <b-form-group>
       <b-button
         variant="primary"
         @click="repeateAgain"
        >
         <i class="feather icon-plus" />
         <span class="ml-25">Add</span>
       </b-button>
     </b-form-group>
  </b-form>
</template>

<script>
import {
  BForm, BFormGroup, BFormInput, BRow, BCol, BButton,
} from 'bootstrap-vue'

export default {
  components: {
    BForm,
    BRow,
    BCol,
    BButton,
    BFormGroup,
    BFormInput,
  },
  data: () => ({
    items: [{
      id: 1,
      title: 'Do the dishes',
    },
    {
      id: 2,
      title: 'What to do ?',
    }],
    newTodoText: '',
    nextTodoId: 2,
  }),
  methods: {
    repeateAgain: () => {
      this.items.push({
        id: this.nextTodoId += +this.nextTodoId,
        title: this.newTodoText,
      })
      this.newTodoText = ''
    },
    removeItem: index => {
      this.items.splice(1)
      console.log(index)
    },
  },
}
</script>

I also try to delete a particular row using the slice method but it not work. What am I forgetting??


Solution

  • You shouldn’t use arrow functions for data or methods in Vue, because arrow functions have their own context (this)

    repeateAgain: () => {
          this.items.push({
    
    

    In an occasion when repeateAgain method is called, this context is undefined - that’s why the error occurs ** TypeError: Cannot read property 'items' of undefined (this)**

    You should modify it like this:

    repeateAgain() {
          this.items.push({
    
    

    Update

    @submit.prevent="repeateAgain" - this is what I meant by “occasion”. Since the method is not bound to the methods: { object, but bound to relative context (none here - undefined) on the other hand, if it’s within a class, the class instance would be the context.

    E.g: (only for demonstration, do not use this pattern)

    In the following example,this context is an instance of MyWrappedCmp

    
    import {
      BForm, BFormGroup, BFormInput, BRow, BCol, BButton,
    } from 'bootstrap-vue'
    
    class MyWrappedCmp {
      getComponent(){
        return {
          methods: {
            repeateAgain: () => {
              // “this” context is an instance of MyWrappedCmp
              // ...
             }
          }
        }
    }
    
    const myWrapped = new MyWrappedCmp()
    
    export default myWrapped.getComponent()