Vue Meteor Tracker Deep Copy

I would like to create a deep copy of data computed in the meteor object. I am trying this, but the mounted hook, threads is an empty object with an Observer and the subscription this.$subReady.threads is undefined.

data() {
  return {
    threadsCopy: null,
  }
},
meteor: {
  $subscribe: {
    'threads': []
  },
  threads () {
    return Threads.find({}, {
      sort: {date: -1}
    })
  },
},
mounted() {
  this.$set(this, 'threadsCopy', JSON.parse(JSON.stringify(this.threads)));
}

Is there a way I can wait on the threads property to be initialized in my mounted function?

In your example, this.threads will keep itself updated, but in the mounted hook the subscription wont be ready so this.threadsCopy will be empty.

If you really want a deep copy of this.threads then you have two options:

1) The expensive but proper way - put a deep watcher on this.threads:

watch: {
    threads: {
        deep: true;
        handler(threads) {
            this.$set(this, 'threadsCopy', JSON.parse(JSON.stringify(threads)));
        },
        ...

2) The efficient but frowned upon way:

meteor: {
    ...
    threads: {
        const threads = Threads.find({}, {
            sort: {date: -1}
        })
        this.$set(this, 'threadsCopy', JSON.parse(JSON.stringify(threads.fetch())));
        return threads;
    },

Note that when doing JSON.parse(JSON.stringify(...)) any date objects will be convered to strings…

If you have the EJSON package, which comes default, you can use that to deep copy an object. I have found it works extremely well.

Thank you!
The second option definitely seems more efficient. Can you expand upon why it’s frowned upon?
In terms of memory efficiency, is there any difference between using a watcher and setting it inside the meteor object?

Didn’t know about the EJSON package, thanks for that. However, I’m not a big fan of adding entire packages to accomplish something I can do quite easily myself:

JSON.parseWithDates = function(string) {
	return JSON.parse(string, (key, value) => (typeof value == 'string' && value.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}/)) ? new Date(value) : value);
}
const cloneObject = JSON.parseWithDates(JSON.stringify(objectWithDates));

Properties defined within the meteor: {} block are effectively computed properties, and “side-effects” (changing other properties within a computed property) are definitely frowned upon because they are not intuitive when trying to understand/debug code.

However, despite being frowned upon this method comes at zero cost and shorter code.

Whereas the “proper” watcher version must have some memory and computation overhead, but to be honest I’m not sure how much and it depends on how big the object is and how often it changes. From the user’s perspective it’s probably negligible difference, so if you don’t mind the extra code you should probably use the watcher method.