A small Vue.js app

Changing an object in an array

My little Vue.js app still does what it did at the start of the previous post – except I broke it a bit in my “cleanup” by referring to a method that I haven’t written yet.

The submitTiddler() method refers to a method, updateTiddler(), which is meant to allow edits to an existing tiddler to be stored.

Goal

Here, I will add the missing updateTiddler() method.

I could choose to change properties individually, optionally checking if any changes have been made, but it’s simpler just to replace the tiddler object with currentTiddler, which holds all the changes that the user has made in the UI. If, at some point, the UI contains a way to add a new property, replacing the whole object will trigger Vue’s reactivity system, avoiding the need to use Vue.set() at that point to add the property individually.

I made the decision to store all my “tiddlers” (or notes) as objects in an array rather than as nested objects, which means they don’t have keys to identify them. Each one does have a unique created timestamp, which goes down to the millisecond. I will use the created property to tell them apart, using JavaScript’s find() array method.

Array.find() takes a callback function that checks whether the element argument passed to it satisfies some specified criterion. I need to write this so that it returns true when the argument is the tiddler that we want to update within the tiddlers array. Then I can write updateTiddler().

Breakdown

  1. Write a function for the find() array method that returns true for the object whose created time matches currentCreated

  2. Write the updateTiddler() method:

  3. Use find(), with the above function as a callback, to return the desired tiddler object from the tiddlers array

  4. Get the index of the tiddler that was returned by find()

  5. Replace the tiddler at that index with the updated version using splice()

1. Write the callback for Array.find()

I’m putting this in the methods option of the Vue instance.

The value of created was stored in currentCreated when selectTiddler() was invoked.

The criterion is that its created property should be the same as that of the currently-loaded tiddler (currentCreated):

isTheTiddler(tiddler) {
  return tiddler.created === this.currentCreated
},

2. Write the updateTiddler() method

a. Use find() on the tiddlers array to return the desired tiddler object

The callback function isTheTiddler tells find() whether each element it checks is the right one, and find() returns the actual element, which is a tiddler object.

b. Get the tiddler’s index in the tiddlers array

Even though I’m not using the index as a way of keeping track throughout the process, I haven’t found a way to manipulate objects in an array without it. So I have to get it with this.tiddlers.indexOf(tiddler).

c. Splice the updated version of the tiddler in place of the old version

this.tiddlers.splice(idx, 1, this.currentTiddler) removes the tiddler the user selected for editing and puts the edited version onto the tiddlers array in its spot. I can’t just say this.tiddlers[index] = this.newTiddler because replacing an element in an array is not detected by Vue’s reactivity system.

If there have been no changes, the tiddler gets replaced by the identical copy being held in currentTiddler.

There’s another array method, filter(), which iterates all the way through the array and returns the matching elements, but in this case, if there’s more than one match, there’s a problem, so I’ll stick with find(), which returns the first match and stops trying.

The updateTiddler() method looks like:

updateTiddler() {
  var tiddler = this.tiddlers.find(this.isTheTiddler)
  var idx = this.tiddlers.indexOf(tiddler)
  this.tiddlers.splice(idx, 1, this.currentTiddler)
},

The current code: minapp_v12.js