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
-
Write a function for the
find()
array method that returnstrue
for the object whosecreated
time matchescurrentCreated
-
Write the
updateTiddler()
method: -
Use
find()
, with the above function as a callback, to return the desired tiddler object from thetiddlers
array -
Get the index of the tiddler that was returned by
find()
-
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