Can you change an item's ID in vue.js?

1.4k views Asked by At

I have a list of items, contained within a javascript array. Similar to the examples found on the vue.js documentation.

This is the workflow I'm struggling with:

  • A user clicks "Add".
  • I immediately add an item to the list (in the spot where they asked it to be)
  • I send an ajax request to the server to create the item.
  • The call returns with the database row for the new item.

I'm using the database primary key as my vue key - which I have no way of knowing up to the point the ajax call finally gets back to me. But if I simply update the ID on the object, I end up with that row transitioning out and then back in.

Is there a way to tell vue that I'm changing the ID of an item?

My ideal case would be something along the lines of:

click: function () {
    let item = {
        id: "placeholder id, possibly randomly generated"
    }
    this.array.splice(index, 0, item);
    ajax_call().complete(function (new_id) {
        // item = data.new_id
        vue.update_id_for_object(item, data.new_id)
    })
}

The commented out line is the one that causes the undesired transition.

Someone voted to close this as a duplicate of this question - as far as I can tell, it's talking about how to set ids dynamically which I'm already doing in my example. Feel free to clarify how it helps my issue though.

2

There are 2 answers

1
Harshal Patil On BEST ANSWER

By behavior key is supposed to determine the uniqueness of the item in a list. So change in the key attribute is and will always represent a different component.

Having this limitation in mind, you have two options. First is the simplest one with a compromise - just disable the animations/transitions.

The second option is to create a localized map of unique id for each existing and new item. For example,

created() {

    this.counter = 0;
    this.mappedKeys = {};

},

// Consider using this method as part of watcher
// Or API call success method.
modifiedList(list) {

    const newList = list.map((x) => {

        if (!this.mappedKeys[x.id]) {
            this.mappedKeys[x.id] = this.counter++;
        }

        return { ...x, id: this.mappedKeys[x.id] };
    });

    // Render this newList
    return newList;
}

For a newly added item, add the entry as:

const nextValue = this.counter++;
this.mappedKeys[nextValue] = newValue;

When ajax call succeeds, add another entry as:

// draftId is the id created in earlier step.
this.mappedKeys[newItem.id] = draftId;

This is the only thing you can do to map draft id to real id returned from database/API. There is not Vue.js way of doing things for this problem.

0
Shadow On

This functionality, at time of writing, is not supported by vuejs.

I have raised a feature request for it, which hopefully will result in its addition.

For now, using proxy ids (as suggested by @HarshalPatil) seems to be a good idea, but one that I'm going to skip for this specific project.


EDIT: I've been told in no uncertain terms to go away, so it's pretty safe to say that they aren't going to consider this useful functionality. Seems the only way to do it is via the proxy method described above.