2

I have a custom directive called "sortable" but I ran into a problem with the DOM. The problem is when I dragged and dropped an item the array is changed but the DOM isn't.

This is my custom directive:

 Vue.directive('sortable', {
    bind: function(el, binding, vnode) {
        // Initialize sortable
        this.sortable = Sortable.create(el, {});
        console.debug("Sortable initialized");

        this.sortable.option("onUpdate", function(event) {
            binding.value.move(event.oldIndex, event.newIndex);
            var updated = binding.value;
            Vue.set(tasks, updated);
        });
    }
});

And this is how I create my Vue instance:

app = new Vue({
    el: "#app",
    data: {
        subtotal: 0,
        tasks: [
            {name: '', quantity: '', rate: 80, costs: ''}
        ]
    },
    methods: {
        newTask: function() {
            this.tasks.push({name: '', quantity: '', rate: 80, costs: ''})
        },
        deleteTask: function(index) {
            this.tasks.splice(index, 1);
            this.calculateTotal();
        },
        calculateCosts: function(event, value, index) {
            this.tasks[index].costs = event.target.value * value;
            this.calculateTotal();
        },
        calculateTotal: function() {
            this.subtotal = 0;
            _.forEach(this.tasks, $.proxy(function(task) {
                this.subtotal += task.costs;
            }, this));
        }
    }
});

In my template I use: v-for="(task, index) in tasks". Did I something wrong?

1
  • when You drag and drop an item, which method is getting called?
    – Saurabh
    Commented Dec 22, 2016 at 3:42

2 Answers 2

17

As per the documentation, the following methods will trigger view updates. The wrapped methods are:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

However I see you are also doing this assignment in calculateCosts method, which will not trigger the mutation, due to caveats in vue:

this.tasks[index].costs = event.target.value * value;

This can be replaced with the following to trigger the mutation and update the view with the help of Object.assign and Vue.set:

var newVal = Object.assign({}, this.tasks[index], {costs: event.target.value * value})
Vue.set(this.tasks, index, newVal)
2
  • 2
    Thanks for your reaction. I placed this exact same question on the Laravel forum and it is fixed now. The only problem was that I forget the :key=tasks inside of the DOM. But thanks anyways. Commented Dec 22, 2016 at 8:00
  • 1
    I had a similar issue, and it was bugging me for a while. But I got it fixed because of your comment. So thank you! For future readers, it's actually :key=task instead of :key=tasks.
    – Daniel R.
    Commented Dec 1, 2018 at 23:32
1

To make vue recept it, use a proper unique key from the array value, not the array index:

<!-- use value.id in :key, not index -->
<div v-for="(value, index) in values" :key="value.id"> .... </div>

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.