Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dataFor / contextFor not honoring controlsDescendantBindings #2148

Merged
merged 2 commits into from Apr 8, 2017

Conversation

mbest
Copy link
Member

@mbest mbest commented Dec 17, 2016

mrtristan:

so in my initial research, the common check to see if an element was bound that people do is something along the lines of !!ko.dataFor(someElement)... this at the surface seems like exactly what i need for my usecase, however there seems to be one issue: this does not take in to account controlsDescendantBindings. I have areas of my application that i need to separately bind and ideally i'd like to be able to ask ko if that has happened... i utilize controlsDescendantBindings to power this separation of concerns and am looking for a solution to check if applyBindings has occured and dataFor seems to traverse up the DOM and look for some parent binding. i'm expecting null and getting data for an unbound div.

thoughts? this seems like a deficiency in that dataFor / contextFor logic.

Thanks.

@mrtristan mrtristan changed the title detecting if applybindings has occured for a given area of an app dataFor / contextFor not honoring controlsDescendantBindings Nov 1, 2016
@brianmhunt
Copy link
Member

This is really a support question, as it looks like there are ways to achieve the desired outcome without modifying knockout – I suggest you pop over to gitter.im/knockout or ask on Stackoverflow.

I will close the issue on that basis, but if there is room for an improvement please post and we can re-open.

Cheers

@brianmhunt brianmhunt closed this Nov 2, 2016
@mrtristan
Copy link
Author

i can't disagree with your statement that there are potential ways to know that the binding has occurred since i clearly don't know how utilizing knockout alone, but are you saying that the described behavior of dataFor / contextFor is intended? i'd like this to be treated as a bug report if not and not so much a 'how do i' type of question.

thanks

@mbest
Copy link
Member

mbest commented Nov 2, 2016

Knockout currently doesn't maintain a foolproof way of determining if an element has been bound or not. We can know that an element has been bound, but not that it hasn't been bound. In other words, it's possible that Knockout will treat an element that has been bound as if it hasn't.

@mrtristan
Copy link
Author

mrtristan commented Nov 2, 2016

appreciate the input. As it relates to the behavior of those two mentioned functions and controlsDescendantBindings, what is your perception of that result that i'm experiencing?

check out this other explanation of the behavior i'm describing. specifically in the comments:

Just wanted to add that ko.dataFor() will look up the DOM hierarchy and return parent data even if a part of the page was never really bound. It is entirely possible that some part of the page has been deliberately marked with controlsDescendantBindings: true. So it is available for binding despite the fact that ko.dataFor() will return parent data.```

@mbest
Copy link
Member

mbest commented Nov 2, 2016

Given an example like this (where allowBindings has been defined per http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html).

<div id="1" data-bind="visible: isVisible">
    <span id="2">Some text</span>
    <div id="3" data-bind="allowBindings: false">
        <input id="4" data-bind="value: someValue">
    </div>
</div>

Knockout will know that elements 1 and 3 were bound, but it will think that element 2 was not bound because it has no bindings. Currently Knockout marks an element as bound only if it has a binding.

@mrtristan
Copy link
Author

thanks for the link.

so to be clear, the issue that i'm describing is that given this example, if i were to do ko.dataFor($('#4').get(0)) i would receive the model that was bound to element 1 where i would expect to receive null or some other indication that it was not bound. this issue is really around checking with you guys to see if that response is a bug or not, and if not, what the rational is behind it not responding with what i expected.

@mrtristan
Copy link
Author

and if you take a look at the console here, you'll see your example with a log showing what i'm talking about. i would expect that console.log to return null.

@chrisknoll
Copy link

You'd expect a null when the value set in the 4's data-bind="value: someValue" was non-null? If someValue came from bound data, why wouldn't dataFor() return the data?

@mrtristan
Copy link
Author

hey there, welcome to the party! lol. so i'm expecting null due to the allowBindings: false above it stopping descendant bindings from occurring so my expectation is that there is nothing bound to it...

@chrisknoll
Copy link

Ok, thanks for the warm welcome :) I guess the way I'd interpret this is that the allowBindigns thing doesn't remove the context, and when you do dataFor() I am guessing it pulls the $data from the active context, which has been set at a higher level. So, if that's the case, maybe the allowBindings would need to reset the context to a new context with an empty $data.

@mrtristan
Copy link
Author

right so the trick that the allowBindings concept is used for in my use case is stopping applyBindings from affecting children nodes at some arbitrary point in the dom so i can applyBindings separately to those children. prior to doing applyBindings on that child node i would expect that i could confirm that there is zero ko context at all on that node.

per what you're saying, the active context would then be completely different after this second applyBindings hit, so i would expect null -> new context to make more sense than fake parent context -> new context (of course assuming that thought process makes any sense itself)

@chrisknoll
Copy link

Right, If i'm undersatnding the allowBindings custom binding, it's setting controlDescendtantBindings: true/false depending on the observable value that's being passed into the allowBindings databind. This custom binding by itself doesn't establish a new context (i'm making this assumption, but this is what I expect) so therefore ko.forData() will find whatever the parent context is (I wouldn't call this a 'fake parent context' it's actualy the current context!). if you alter allowBindigns to reset the context to something empty, that would get what you want. after you call apply bindings, you'd have to do it on a new dom element that is under the element you put the allowBindings databinding on because the dom element with allowBindings on it has been databound to!. But any dom element you can find using a jquery selector or whatever under that element is fair game to bind to, and I believe that apply bindings will establish a new binding root level (meaning there will be no parent context of this context created by calling applyBindings(). that might be some other issue for you, i don't know your complete use case.

@mrtristan
Copy link
Author

totally. so i typically only utilize this stopBindings concept as a virtual element so as to have that clear distinction in what is bound... i see your thought process here regarding the context continuing down despite it not taking any action... my only issue with your workaround process is that it seems that in order to change the context, it seems that that involves performing a binding again with that new context and i need another area of logic to be able to step in and perform that binding when it is ready, and not within the stopBindings bindingHandler. not only that but my ability to call ko.applyBindings on that child element means to me that it has not 'been bound' so i should not see data when querying that element with ko.dataFor

at the end of the day, it feels like a bug to me that the parent data/context is present on an element that is itself wrapped in controlDescendtantBindings:true

can any of you KO guys weigh in on if this is by design or perhaps a flaw? thanks!

@mbest
Copy link
Member

mbest commented Nov 3, 2016

As I've explained, Knockout doesn't currently have any way to tell you that an element hasn't been bound. I'll reopen this as a request to add that feature.

@mbest mbest reopened this Nov 3, 2016
@brianmhunt
Copy link
Member

Could this be as simple as adding a Symbol to the DOM node?

@mbest mbest modified the milestone: Not assigned Dec 2, 2016
…en if they are descendants of a bound element.
@mbest
Copy link
Member

mbest commented Dec 17, 2016

This topic has been around a while. See #905. I've attached the fix.

@mbest mbest merged commit ccec0fc into master Apr 8, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants