| Page 1 of 1 | [ 5 posts ] |
|
I have just solved a problem that appeared to be difficult to solve using the documented API, and I wonder whether it is a new use case, or perhaps I am doing something stupid.
Here's the situation: I have a widget, and it has a data attribute containing a lot of complex data, including very long arrays. I like the luxury of change events fired when I set the attribute, but I cannot afford the duplication of my huge data object in newVal and prevVal. Because it is unlikely that my data attribute will change entirely, the newVal-prevVal pair does not really represent the change. Instead, I can use subAttrName to indicate where the change has occurred, but when the event fires, the facade object presents two deep-copied versions of the entire data object. I am concerned with the waste of resource this operation involves. This is how the problem is created: Code: data = widget.get('data'); data.subAttr = newValue; widget.set('data.subAttr', data) When the dataChange event fires, the listener gets two complete copies of the attribute, although it is also correctly informed about the change limited to in data.sbuAttr (and by the way, in this case, I don't need the old value). The solution: Code: data = widget.get('data'); data.subAttr = newValue; widget._fireAttrChange('data', 'data.layout', data, data); This works exactly as I need, but as with all solutions requiring poking around under the hood, I am convened with this solution's viability. Also, it makes me wonder wether I've got into this situation my making a wrong turn somewhere. But if it is a legitimate use case, why not provide a method for it? In other words, I've often found myself wanting to decouple attribute setting and event firing, and I want it both ways. I have situations when I want to set the attribute value just once without firing the change event (I can unsubscribe all listeners for that one instant, but doing so can be painful), and there are situations when firing the change event without going through the vast ramifications of set() may be the right thing to do. |
|
Hey,
It seems like the basis of your analysis is this statement: > I like the luxury of change events fired when I set the attribute, but I cannot afford the > duplication of my huge data object in newVal and prevVal. IIRC, I don't think there is a huge duplication cost, *unless you use the subAttr set*, in which case we need to isolate the original value from the new one, and there's definitely a cost there [1]. The attribute code will just put the current value in "newVal" and the old value in "prevVal". There's no duplication really. They will however be the same values [if updated by reference as shown below]. That is, it seems like this will get you what you need, without creating new infrastructure, and without silencing events [2]: var data = this.get("data"); data.subAttr = newValue; widget.set("data", data, {modified:["subAttr"]}); Listeners can use "e.modified" to pick up only the modified data if required, or e.newVal for the whole object. Anything where you wan't the newVal to be different from the prevVal, will require a clone for objects - but it sounds like you want to avoid that. Hope that helps, Satyen [1] Which I've tried to remove but don't have a backwards compatible way to do so. We could get rid of the clone but it would mean changing the way subAttrs work. [2] Regarding separating events from sets - I don't think silencing events in general is a safe strategy. In a complex system, updating state without firing the events is likely to lead to fragility, with observers not reflecting the updated state accurately. |
|
Thank you very much Satien,
All your recommendations are very helpful. Rejecting the event in the listener based on a payload parameter is a much better way than silencing it at the source. I did not realise I could mark the change events with a payload parameter to set() until I started poking around in the code yesterday. Somehow I missed it in the docs. |
|
Its documented here:
http://yuilibrary.com/yui/docs/api/clas ... method_set But, for some API doc generation reason, it isn't revealing itself in Attribute [the AttributeCore version does], even though Attribute @uses AttributeCore, AttributeEvents which is probably why you missed it. I'll look into the doc generation issue. |
Bruce Wallace
|
I need a different sort of decoupling of setting attributes and event firing...
I need to be able to set several different attributes as a group before the change events fire for any one of them. In other words, someone subscribing to the change event for A should be able to see the newly updated values of attributes A,B,C in the update event callback (because I set A,B,C as a "group"). The syntax of setAttrs() is what I want, but it fires a change event as each item in the group is set, whereas I need all items in the group set before then firing events for each item in the group. I need this because it is my understanding that I can't subscribe to update events for subvalues foo.A or foo.B or foo.C; i.e. I can only subscribe to foo as a whole. Therefore I have made A,B,C separate ATTRs. PLUS, even if I could, sometimes the A,B,C are so unrelated that it wouldn't make sense to cram them into a single foo ATTR. |
| Page 1 of 1 | [ 5 posts ] |
| You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum |
© 2006-2013 Yahoo! Inc. All rights reserved.
All code on this site is licensed under the BSD License unless stated otherwise.
About This Site · Security Contact Info
Powered by phpBB® Forum Software © phpBB Group