[Vuejs]-VUE b-editable-table data model is returning old value upon editing

1👍

This is a result of console.log showing objects as ‘live’ data vs individual data properties that will log their value at the time of the actual console.log statement. This is further explained in the MDN documentation for console.log.

Don’t use console.log(obj), use console.log(JSON.parse(JSON.stringify(obj))).

This way you are sure you are seeing the value of obj at the moment you log it. Otherwise, many browsers provide a live view that constantly updates as values change. This may not be what you want.

Technically your first console.log should be showing the old productPrice value for some (extremely) short amount of time, same as your other console logs, but then the log updates itself to show the new value almost instantaneously.

To get the updated value of a table cell

Because of the way b-editable-table is designed, we can’t get the updated cell value from an event handler on a cell v-slot that isn’t the cell being updated. One way to do what you want is to listen to the input-change event emitted from the table itself. This passes a data variable that contains the updated values of whatever row was just updated. From this you can assign the updated row data to a new data property on your component. This property will have the information you need when a user clicks the icon in your #cell(edit) slot

<b-editable-table
  bordered
  class="editable-table"
  v-model="items"
  :fields="fields"
  @input-change="handleInput"
>
data() {
    return {
      fields: [ ... ],
      items: [ ... ],
      updatedRow: {} // <-- new property to hold updated row data
},
methods: {
  handleInput(data) {
      if (Object.keys(this.updatedRow).length === 0) {
        this.updatedRow = {
          ...this.items[data.index],
          [data.field.key]: data.value,
        };
      } else {
        this.updatedRow = { ...this.updatedRow, [data.field.key]: data.value };
      }
    },
  // method called by `#cell(edit)` slot
  handleSubmit(data, update) {
      this.rowUpdate = {
        edit: false,
        id: data.id,
        action: update ? "update" : "cancel",
      };
      console.log("this.updatedRow.productPrice", this.updatedRow.productPrice);  // <-- shows latest productPrice
      this.updatedRow = {}
    },
}

An explanation for:

this.updatedRow = {...this.items[data.index], [data.field.key]: data.value};

This line exists because the data object passed in by the event contains only pieces of the updated value that we still must manually construct into a row object. This is the format of the passed in data object (unimportant properties removed):

{
  index: 0
  field: {
    key: "productPrice"
    label: "Product Price"
     ...
  }
  value: "11.63"
  ...
}

So we have these properties:

  1. index (the row updated)
  2. field.key (the cell updated)
  3. value (the new cell value)

At this point, we still have nothing giving us the full updated row object.
Our v-model this.items is still not updated! We have to construct this updated row object ourselves. The code that does this uses object destructing.

{ ...this.items[data.index] } gives us all the current (old) key-values of this.items[row]

adding [data.field.key]: data.value as another property will update the relevant key-value pair that was just updated by the user.

together, this.updatedRow = {...this.items[data.index], [data.field.key]: data.value}; gives us the row from this.items but with the absolute latest values from the row that was just updated by the user.

👤yoduh

Leave a comment