jQuery .post does deep copy of jQuery expando on objects #99

Closed
crimar opened this Issue Aug 9, 2012 · 9 comments

Comments

Projects
None yet
2 participants

crimar commented Aug 9, 2012

[Title updated, to match the remaining issue here, and for tracking of this jQuery ticket]

The initial rendering of a template can use properties on the data's prototype, but changes on these properties are not propagated to the DOM later.

Interestingly the event itself is propagated among the prototype chain, up and down.

Owner

BorisMoore commented Aug 9, 2012

If you want them to propagate you have to change them 'observably'. You should be able to call $(object).setProperty("foo", newValue) where foo is on the prototype (or not) and the data-link="foo" will pick up the change. If not, can you give more details, or create a jsfiddle to show the problem?

crimar commented Aug 10, 2012

http://jsfiddle.net/ReXfa/ shows the problem. If you uncomment the registration of the empty handler, it works...

Owner

BorisMoore commented Aug 10, 2012

I think that in this case your inheritance mechanism is something you own in your app, so I would suggest you make the objects listen for changes in their prototypes, rather than us building some automatic chaining of listeners - since dynamically modifying prototypes will not be a common scenario, and adding listeners adds complexity and impacts perf.

A possible approach is as follows:

    function createNode(parent, constructor) {
        if (parent) {
            constructor.prototype = parent;
        }
        var component = new constructor();
        if (parent) {
            $(parent).on("propertyChange", function(ev, eventArgs){
                $.observable(component).setProperty(eventArgs.value);
            })
        }
        return component;
    }

The reason the events are propagating is because jQuery stores the event handlers on a 'cache' which is an expando on the object, and it uses the existing cache if it finds one. Adding a handler to the prototype puts a cache object on the prototype, and it therefore shows up on the instances too. So all the instances end up sharing the same event registrations with the prototype. Not a great story. You probably need to investigate whether your model is workable given this event registration pattern in jQuery.

I am considering switching to using a simple mechanism than jquery events for the property and array change observability events. If that happens this issue may possibly go away at that point, depending on the details of the new implementation...

crimar commented Aug 16, 2012

I'm fine with that and will try to implement the solution you suggest. Thanks!

Btw., another problem with these jQuery event handler caches is, that jQuery's .post() does serialize them...

Owner

BorisMoore commented Aug 24, 2012

I looked into the issue with jQuery post, and you are right, they are including the jQuery expando property in the deep clone.
A quick fix is to change line 326:

if ( target === copy ) {

to

if ( target === copy || copy && copy.toJSON && !copy.toJSON()) {

It would be really great if you could register a bug for this issue with jQuery. Would you feel able to do that...?

Owner

BorisMoore commented Aug 27, 2012

Great, thanks... I added a comment to the ticket, and changed the title of this issue, to track, since the original issue above is covered....

crimar commented Sep 10, 2012

What makes the expando story worse is that 'for in' iterates over it when on an array.

Owner

BorisMoore commented Apr 8, 2013

Closing, since this is not an issue directly on JsViews

BorisMoore closed this Apr 8, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment