So I’ve been scratching this mental itch and was checking out how to handle change listeners to arrays without using Observables or external libraries.
The main idea is that I have a .json
file which is basically an array of objects (of type Rent
) and I’ll use that file as my DB. I want to trigger a write to the file whenever the rentCollection
array is changed.
With the help of search engines and SO, I landed on this answer, and I’ve managed to implement something similar that seems to work as intended with a notable exception:
- The callback function doesn’t receive any arguments, even if they’re being passed and I’m a bit at a loss as to why so I’m looking for you help.
Given the following piece of code
const rentsFile = __dirname + "/data/rents.json";
export let rentCollection: Rent[] = [];
const populateRents = () => {
let rents = fs.readFileSync(rentsFile, { encoding: "utf8" });
rentCollection = JSON.parse(rents);
}
export const initDb = () => {
populateRents();
listenChangesinArray(rentCollection, writeFile);
}
/* @arr array you want to listen to
@callback function that will be called on any change inside array
*/
const listenChangesinArray = (arr: any, callback: any) => {
// Add more methods here if you want to listen to them
['pop', 'push', 'reverse', 'shift', 'unshift', 'splice', 'sort'].forEach((m: any) => {
arr[m] = (arg: any) => {
var res = Array.prototype[m].apply(arr, arg); // call normal behaviour
callback.apply(arr, arg); // finally call the callback supplied
return res;
}
});
}
const writeFile = (arg: any) => {
console.log("Write Arg: " + arg); // <== This argument is always undefined. Why???
try {
console.log(JSON.stringify(rentCollection, null, 2)); // <== I never see the new item in this collection. Why???
fs.writeFileSync(bloqsFile, JSON.stringify(rentCollection, null, 2), 'utf8');
console.log('Data successfully saved to disk');
} catch (error) {
console.log('An error has occurred ', error);
}
}
whenever I do a rentCollection.push(Rent)
, it will trigger the listenChangesinArray
method, and I can see/log the arg as being the passed Rent
object, and then call the writeFile
method too. However, when getting to writeFile
the argument is always undefined
. Why?? Is the way to handle the changes listener not right?
Appreciate any insight you can give. Thanks!
2
Answers
The second argument of
apply
should be an array, but you pass it the argument that you provided to the array method, such as topush
, if any.Fix this by getting all arguments in an array. So change this:
to:
Now
arg
will be an array, and so the second argument to both calls ofapply
will have the correct type.The answer given by trincot is pretty much valid and works well…
But I would like to add some hints to you.
...args
instead of...arg
to make it clear thatargs
is a list/array.writeFile
function should also be changed to...args
and properly adjusted (it will be receiving...args
, but only reads the first?).listenChangesinArray
overridesort
andreverse
methods and any other like those. Instead, execute them before or after any new write to the array. Else, if you sort then add a new item (or do the other way around), the array will be saved twice in a row… Depending on your service this can avoid some extra charges for resource consumption and save your storage lifespan…PS.: Most storage systems have a lifespan measured in cycles of writings. If you’re doing double writes, then your storage lifespan will be cut in half.