Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VueJs: How to Edit an Array Item

Simple Todo-App. Please excuse my ignorance for making a rather basic question.

But how would you go about and edit a certain item on an array?

Normally I would try to bind the value of my input to a new property on my data object and then assign this new property to the old property on click throuch Vue's two way databinding.

Like this: http://jsfiddle.net/z7960up7/

Well in my case I use the v-repeat directive, which loops through my data array but I can't use the v-model directive to use the two way databinding, because the values of the properties get corrupted if I do so. (See here: http://jsfiddle.net/doL46etq/2/)

And now I wonder, how I would go about updating my array of tasks:

My idea is to pass the VueObject (this) through my method on click, and then define the index on my event handler and then updating the tasks array, using the index, like this:

HTML:

<input v-el="editInputField" type="text" value="{{ task.body }}" v-on="keyup: doneEdit(this) | key 'enter'"/>

<button v-on="click: editTask(this)">
     Edit
</button>

JS:

methods: {
    editTask: function (task) {
        var taskIndex = this.tasks.indexOf(task.task);

        this.tasks[taskIndex] = {
            'body': document.querySelector('input').value,
            'completed': false
        };

        console.log(task.task.body);
    },
}

Here is my fiddle about it:

http://jsfiddle.net/doL46etq/3/

But the data object is not updated at all and I wonder how I would go about it and update it.

What is the best way to edit an element on the array, using Vue?

Edit: An easy way, would just be to delete the element, and add the new to the array, using the push method, but I really want just to update the element, because I like to keep the dataobject in sync with my backend.

like image 919
LoveAndHappiness Avatar asked Aug 09 '15 00:08

LoveAndHappiness


1 Answers

The short answer: Use a component in an extended constructor, then pass the index to that component in HTML as property and use computed properties to link back and forth to your data.

But don't be satisfied with just the short answer. Here is the long one:

Situation: I am using your JSFiddle as base for this answer.

in HTML you have:

<td>{{ task.body }}</td>
                <td>
                    <div>
                        <input v-el="editInputField" type="text" value="{{ task.body }}" v-on="keyup: doneEdit(this) | key 'enter'" v-model="newEdit"/>
                    </div>
                </td>
                <td>
                    <button v-on="click: editTask(this)" class="mdl-button mdl-js-button mdl-button--icon"> <i class="material-icons">create</i>

                    </button>
                </td>

We want to replace this code with the component. Using this component allows us to identify the index/row we are working on in your set of data.

<td v-component="listitem" index="{{$index}}"></td>

Next step: defining the component.

In order not to cloud our instance with the component, we will create a separate constructor for the vue object, so we can assign the new element to our new object.

This is done using extend.

window.newVue =  Vue.extend({
components:
{
    'listitem': {

        props: ['index'],

        computed: {
        // both get and set
        body: {
          get: function () {

            return this.$parent.tasks[this.index].body;
          },
          set: function (v) {
            this.$parent.tasks[this.index].body = v
          }
        }
      },
        template: '<td>{{ body }}</td><td><div><input type="text" v-model="body" value="{{ body }}"/></div></td><td></td>',
    }
}

});

Since we can't define our data properly using an extend, we'll just assume the data already exists while writing the component.

Step 3: defining the actual data: Instead of using Vue as our object constructor, we'll now use our newly created instantiator.

new newVue({
el: '#todoapp',

data: {
    tasks: [{
        'body': 'Eat breakfast',
        'completed': false
    }, {
        'body': 'Drink milk',
        'completed': false
    }, {
        'body': 'Go to the store',
        'completed': false
    }],

    newTask: '',
},

});

That's it!

In case you couldn't follow what happened: Here's the Fiddle!

PS: More information about the working of these code can be found on vuejs.org

like image 126
Sangun Avatar answered Sep 30 '22 04:09

Sangun