Tracker.nonreactive on localCollection.update()


#1

I would like to update a local (client-only) collection without triggering reactivity on cursors depending on it. Is there a way?

A tried this, but it doesn’t seem to work (reactivity occurs):

				Tracker.nonreactive(function() { localCollection.update(id, { $set: fields }); });

#2

Haven’t tested this but you could try adding an option to your Collection.find() query such as:

Collection.find({}, {reactive: false});

Found in the docs


#3

Thanks @zachdixon.

Sadly, {reactive: false} is of no help here. The update operation I am talking about modifies specific fields in my Collection and is executed at a specific time (I have some other updates, which I want to be reactive). If I put {reactive: false} on my cursors, I end up with no reactivity at all, which is not what I want.

Why I don’t understand is why Tracker.nonreactive(function() { localCollection.update(id, { $set: fields }); }); doesn’t work. It is a purely local and synchronous operation (isn’t it?).
Might this be a bug?


#4

Tracker.nonreactive makes the reactive variables in the function you passed to it non reactive, so they don’t causes any re-runs to a function passed to Tracker.autorun, so it doesn’t work like you want/think. But I agree with @zachdixon; set the reactive option to false. If you need reactivity for some of the fields, use two calls to find (one reactive, and one non reactive).


#5

@Peppe_LG, thanks for the explanation about Tracker.autorun, it is clearer now.
Regarding your suggestion, while I can see how to combine two calls to findOne to build a single result, I am not sure you can do the same with two calls to find


#6

I’m not sure either. I guess the optimal solution for this depends on the context. Can you show us where you use the find that should be partly reactive and partly non reactive?


#7

I found a solution in my specific context, but it is less elegant than what I wanted.

My context is text edition: I have a list of textareas corresponding to Collection records. While user is typing, I want to update the Collection at fixed interval, but I cannot afford to refresh the DOM otherwise textarea focus and caret are lost.


#8

Can something like this work?

Template.name.helpers({
	textareas: function(){
		var options = {
			fields: {
				name: 1 // And all other reactive fields...
			},
			transform: function(doc){
				
				// Add the non reactive fields.
				var options = {
					reactive: false
				}
				doc.value = Textareas.findOne(doc._id, options).value
				
				return doc
				
			}
		}
		return Textareas.find({}, options)
	}
})

#9

Thanks for thinking about it.

This is what I have implemented in the past, although with findOne in a helper rather than in transform. However, it seems having a reactive cursor returning hundreds of texteareas, each one having its own individual reactive cursors, lead to poor performance. I didn’t measure it precisely, though.

I tried another solution: mirroring my collection in a local collection using observeChange. This allows avoiding the copy of the non-reactive fields over to the local collection, hence preventing reactivity. It seemed better in terms of performance, but the mirroring logic is delicate and error-prone (avoiding to copy a field over is easy, but the problem is to decide when you finally want to copy it over so that your local collection is up to date).

So right now I entirely removed the feature.