1

Here's a simplified version of my code :

    <template>

        /* ---------------------------------------------------------- 
         *  Displays a list of templates, @click, select the template
        /* ----------------------------------------------------------
        <ul>
            <li 
                v-for="form in forms.forms" 
                @click="selectTemplate(form)" 
                :key="form.id" 
                :class="{selected: templateSelected == form}">
                <h4>{{ form.name }}</h4>
                <p>{{ form.description }}</p>
            </li>
        </ul>

        /* -------------------------------------------------------- 
         *  Displays the "Editable fields" of the selected template
        /* --------------------------------------------------------
        
        <div class="form-group" v-for="(editableField, index) in editableFields" :key="editableField.id">                                       
            <input 
                    type="text" 
                    class="appfield appfield-block data-to-document" 
                    :id="'item_'+index" 
                    :name="editableField.tag" 
                    v-model="editableField.value">
        </div>                    
    </template>
            
    <script> 
        export default {                        
            data: function () {
                return {
                    editableFields: [],
                }
            },
            methods: {
                selectTemplate: function (form) {

                    /* ------------------ 
                    *  My problem is here
                    */ ------------------

                    for (let i = 0; i < form.editable_fields.length; i++) {                                         
                        this.editableFields.push(form.editable_fields[i]);              
                    }
                }
            }
        }
    </script>

Basically I want to update the array EditableFields each time the user clicks on a template. My problem is that Vuejs does not update the display because the detection is not triggered. I've read the documentation here which advise to either $set the array or use Array instance methods only such as splice and push.

The code above (with push) works but the array is never emptied and therefore, "editable fields" keep pilling up, which is not a behavior I desire.

In order to empty the array before filling it again with fresh data, I tried several things with no luck :

this.editableFields.splice(0, this.editableFields.length);

for (let i = 0; i < form.editable_fields.length; i++) {
    this.editableFields.push(form.editable_fields[i]);                   
}

==> Does not update the display

for (let i = 0; i < form.editable_fields.length; i++) {                 
    this.$set(this.editableFields, i, form.editable_fields[i]);
}

==> Does not update the display

this.editableFields = form.editable_fields;

==> Does not update the display

Something I haven't tried yet is setting a whole new array with the fresh data but I can't understand how I can put that in place since I want the user to be able to click (and change the template selection) more than once.

I banged my head on that problem for a few hours now, I'd appreciate any help. Thank you in advance :) !

2 Answers 2

1

I've got no problem using splice + push. The reactivity should be triggered normally as described in the link you provided.

See my code sample:

new Vue({
  el: '#app',
  data: function() {
    return {
      forms: {
        forms: [{
            id: 'form1',
            editable_fields: [{
                id: 'form1_field1',
                value: 'form1_field1_value'
              },
              {
                id: 'form1_field2',
                value: 'form1_field2_value'
              }
            ]
          },
          {
            id: 'form2',
            editable_fields: [{
                id: 'form2_field1',
                value: 'form2_field1_value'
              },
              {
                id: 'form2_field2',
                value: 'form2_field2_value'
              }
            ]
          }
        ]
      },
      editableFields: []
    }
  },
  methods: {
    selectTemplate(form) {
      this.editableFields.splice(0, this.editableFields.length);
      for (let i = 0; i < form.editable_fields.length; i++) {
        this.editableFields.push(form.editable_fields[i]);
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
    <ul>
        <li v-for="form in forms.forms" 
            @click="selectTemplate(form)" 
            :key="form.id">
            <h4>{{ form.id }}</h4>
        </li>
    </ul>

    <div class="form-group"
        v-for="(editableField, index) in editableFields"
        :key="editableField.id">
            {{ editableField.id }}:
        <input type="text" v-model="editableField.value">
    </div>
</div>

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

1 Comment

Thanks, you're totally right, an unrelated part of my code was causing the error.
0

Problem solved... Another remote part of the code was in fact, causing the problem.

For future reference, this solution is the correct one :

this.editableFields.splice(0, this.editableFields.length);

for (let i = 0; i < form.editable_fields.length; i++) {
    this.editableFields.push(form.editable_fields[i]);                   
}

Using only Array instance methods is the way to go with Vuejs.

2 Comments

You can also do this.editableFields = [ ] which sets back the array to an empty one
Thanks ! This is shorter !

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.