javascriptmeteorreactive-programmingmeteor-tracker

How to run a Tracker computation only if a specific field of a reactive document changes?


I am using Tracker.autorun to call a function in my Meteor app when a collection document is changed. The Tracker is working, however I only want it to run when a specific property of the document is changed :

Tracker.autorun(() => {
  let _x = Site.MyCollection.findOne(this._id).myProperty;

  if (_x) {
    this._myMethod(_x);
  }
});

I only want the computation to invalidate when the value of 'myProperty' changes, however it's called whenever any property of the collection is updated.

I can't use Session variables in this case, because the value of myProperty could be updated by another connected client.

How can I achieve this?


Solution

  • Well, myProperty isn't reactive. The object on which it is defined is.
    If you want to keep a nice reactivity then you could use a ReactiveVar to store the value of myProperty, then use a computation to update its value.

    var myProperty = new ReactiveVar();
    
    Tracker.autorun(function() {
      //Reactivity kicks in with findOne
      myProperty.set(
        Site.MyCollection.findOne(this._id).myProperty
      )
    })
    

    You can then run a reactive computation on myProperty.

    Note that while the above code sets myProperty all the time and thus may seem to trigger reactivity each time, it will actually ignore the cases in which the old value is === to the new value.
    If you find this behaviour undesirable you can forcefully invalidate registered dependencies :

    //'_dependentsById' is an array-like object lacking an iterator, fallback on _
    _.each(myProperty.dep._dependentsById, 
      (dep) => dep.invalidate()
    )