So I have an object that I initialize on entering a view, but it can also be populated by the user “loading” an existing object in (see loadMagicObject()).
I have a load of form controls that all end up reference the reactive Session object, which is fine, other than that every time I change a single field, all the fields are going to get recalculated.
Surely there is a better way to achieve this?
Template.example.created = function () {
resetMagicObject();
};
var resetMagicObject = function () {
Session.set('magicObject', {
name: '',
owner: '',
age: 0
});
};
Template.example.events({
'keyup .js-magic-name': function (event, template) {
var magicObj = Session.get('magicObject');
magicObj.name = $(event.target).val();
Session.set('magicObject', magicObj);
}
});
Template.example.helpers({
selectedObject: function () {
return Session.get('magicObject');
},
loadMagicObject: function () {
var magicObj = MagicObjects.findOne();
Session.set('magicObject', magicObj);
}
});
If your question is “how do I store an object in Session and avoid triggering reactivity everywhere when only one field is modified”, then I can suggest 2 solutions:
Split your object into its fields:
var name = $(event.target).val();
Session.set('magicObjectName', name);
Use the old but still extremely useful package isolate-value:
Ok first of, you do not have to use jQ to get the value. The event variable is a jquery event already, so you can do:
event.currentTarget.value
```
You can use `target` only, but [as per the docs][1] - "Most events bubble up the document tree from their originating element." So watch out for that ;)
Now to your original question: Since you are binding and event to the `keyup` you'll always update **ALL the fields**- why? - simple - Sessions are reactive and you are updating the Session with each keyup event, which re-renders the template.
To sum it up - breakup the session to smaller pieces so you can update them separately, use the `name` attribute at inputs so you can be more DRY.
```
Template.example.events({
'keyup .js-magic': function (event) {
var name = event.target.name,
value = event.target.value;
Session.set('magic-' + name, value);
}
});
```
**OR**
Do not bind the Session the the input value! That will update the input every time the Session changes!
I would suggest something like this:
```
Template.example.helpers({
selectedObject: function () {
var object = MagicObjects.findOne();
if(_.isObject(object)) { //lets use underscore here to see if the response is an object
return object;
} else {
return '';
}
}
```
Hope it helped ;)
[1]: http://docs.meteor.com/#/full/eventmaps
Why is that Solarc? Even the Atmosphere page you linked says that the ONLY difference is that it does not survive hot code pushes. Please correct me if I am wrong.
Splitting my objects into it’s fields was certainly an option, however as @solarc mentions later, I’d probably use a ReactiveDict to achieve this rather than the Session object (although I’d loose the data on a hot-code push).
I’d not heard of the isolate-value package and it looks very interesting, although the fact it hasn’t been modified for almost 2 years makes me a little hesitant to make any code rely to heavily on it… Also was it abandoned because it was considered a bit of a “hack”?
Thanks for pointing out that the events are already jQuery events, saves me a lot of wrapping in a lot of places… Whoops!
the target vs. currentTarget point was something I hadn’t realised at all, again, thanks for the tip.
Essentially your first suggestion is the same as Steve’s first suggestion, but with a bit more reusability in the code. I like it, however it still feels very clunky… (Like a ReactiveObject class is just missing…)
Your last point brings me onto a final thought…
If the object is either a document loaded from the database, or one awaiting to be saved into the database. Can I create a new document in the client collection only which I bind everything too (I think that would then be reactive on a per-field level), and then tell it to save it to the server when the users actually wants to save it?
Hmm yeah, perhaps that isn’t a good idea at all then!
Perhaps I’ll take a closer look at isolate-value, but I think for the time being I’ll probably end up using a system like @davethe0nly suggested, as it’s easier for someone else to understand what it’s doing & how.