BorisMoore / jsviews

Interactive data-driven views, MVVM and MVP, built on top of JsRender templates
http://www.jsviews.com/#jsviews
MIT License
857 stars 130 forks source link

Determine if an object is already observed and bound to a view or not #274

Closed pmxrob closed 10 years ago

pmxrob commented 10 years ago

Hey Boris!

I'm wondering if there is a quick way to determine what element a particular object/property is bound to?

I'm calling:

// somewhere else in the program (not actually using a global but will work for the example here)
window.doc = {count: 1};

// On loading some html I then do this
$.templates['#myTemplateFragementId'].link('#myViewSelectorId', window.doc);

// Then later on I do this
$.observable(window.doc).setProperty('count', 2);

This all works but what I want to be able to determine is if window.doc is actually bound to a view or not at any time during the apps execution, and if so, what view element it is bound to, something like:

var boundToElement = $.observable(window.doc).boundToElement();
// Returns boundToElement which would be the element with the id "myViewSelectorId" as linked above

Is something like that available or is there a workaround I can use?

Thanks buddy!

BorisMoore commented 10 years ago

Hi Rob,

No, that does not really exist. The link method doesn't actually bind the data to the view. For example if the template contains just text, with no data-linked elements or tags {^{... }} then nothing has been bound at all. And if there are data-linked elements or tags then there will be bindings from some data items - not necessarily the top-level data object you passed in - to the associated elements, not to the view.

(BTW bindings of callbacks to data are tracked in $.views.sub._cbBnds - and the associated elements are in the closures of the callbacks...)

If you want you can create a custom tag and include it in each of your templates:

$.views.tags("trackBoundViews", function() {
    var boundViews = this.ctx.root.boundViews = [] || this.ctx.root.boundViews;
    boundViews.push(this.tagCtx.view);
})
<script id="mytemplate" type="text/x-jsrender">
    {{trackBoundViews/}}
</script>

Then from your data get data.boundViews.

But I'm not sure how robust that will be. Views can get deleted, replaced, etc. That needs to be managed.

pmxrob commented 10 years ago

Thanks Boris.

Appreciated! :)

Irrelon commented 10 years ago

Hey again,

I've noticed that if I bind an object I get a property on the bound object called something like "jQuery11100872720101615414".

In that object I have a data.obId = 1 and on my dom element that the object was bound against I have a data-jsv="#1_".

Sometimes I notice you use script tag markers with type="jsv#2_" and a closing one to denote the "finish" point. Are these reliable ways to find out if an object is data-bound? I mean, if I take an object with a jQuery209234848324 property, look in that property and find the obId and then match that to an element with either the data-jsv or script markers then I know it is linked... is that a correct assumption?

Irrelon commented 10 years ago

And slightly on topic I've noticed those properties like "jQuery274837283723" are enumerable... is that supposed to be the case?

BorisMoore commented 10 years ago

Hi Rob,

Not sure what you mean by the jQuery expando being enumerable. In javascript, expandos show up when you do {{for var key in object}} but you can test the hasOwnProperty(). Also JSON.stringify will skip the expando if it has a toJSON method which return undefined, and that is the case for the jQuery expando.

You can look at the obId to see if it has been bound. But it may no longer be bound. If that key shows up on $.views.sub._cbBnds then it is still bound. But that still does not tell you what HTML element it is bound to... For that you need to look at the events - $._data(object).events.propertyChange - but the bound elements are part of the closure of the event handlers, so I don't think there is an easy way to get to them directly...