KnockoutJS “with” binding before model is available

独自空忆成欢 提交于 2019-12-11 09:07:02

问题


I have an ASP.NET MVC4 SPA web application using KnockoutJS, which is a bit awkward because, as I understand it, when the page initially loads in an SPA there is generally no data until an AJAX call retrieves it. When I try to bind all sorts of data inside a block with an attribute like data-bind="with: myData", the whole DOM inside that node is emptied out until myData becomes valid, which makes me nervous if certain script might be relying on having those elements available to attach script to or something. It also looks bad to have chunks of the page disappearing and reappearing during the load process. So I've devised a variation of the with binding that will prevent descendant bindings if the value is empty, which currently looks like this:

ko.bindingHandlers.safeWith = {
    'init': ko.bindingHandlers.with.init,
    'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if ((value != undefined) && (value != null))
            ko.bindingHandlers.with.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
    }
};

Then I simply use safeWith instead of with to make sure my DOM doesn't go away while waiting for myData to be populated.

My questions are:

  1. Is this a common problem with SPAs using knockout, and if so, how is it normally dealt with?
  2. Is my way of dealing with this safe or do I risk duplicate events/bindings being applied somehow or some risk I'm not aware of?
  3. I'm surprised in my roaming about the web learning about knockout and related technologies I haven't run across this. Are there good reasons to prefer having sections of the DOM to go away when the object to which they're bound is empty; am I making a mistake by trying to keep it around?

回答1:


I have implemented a custom bindIf binding handler that improved our results significantly by postponing binding logic until the observable has a valid value inside it:

ko.bindingHandlers.bindIf = {
    'init': function (element, valueAccessor) {
        return { 'controlsDescendantBindings': true };
    },
    'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        if (!$(element).data("bindIfPassed") && valueAccessor()) {
            $(element).data("bindIfPassed", true);
            ko.applyBindingsToDescendants(bindingContext, element);
        }
    }
}

Applied to a high level node like this:

<div data-bind="bindIf: myObservable()">



回答2:


I can see reasons why you would not want the DOM inside a with-bound element to disappear, but they are very few. Pretty much all of them involve DOM manipulation that requires certain timing. For example, setting the focus to the first input field when a view is shown. Sometimes, the workaround for such problems isn't pretty, in which case a binding like yours would definetly help a lot.

In general,

  1. I suppose this is somewhat of a common problem. You mention a few problems: Scripts relying on the presence of those elements: in general, I would respond that your scripts are wrong. Now that's a bit harsh, but I do feel it's a bit of a code smell that your scripts would come crashing down if a certain DOM element isn't available. Second, you feel that parts of the dom disappearing and reappearing is not such a good thing. In this case, maybe you should 'reset' the observable in your with binding to something else than 'null'. Create a 'blank' instance of whatever object normally goes into the observable, and use that instead of null, so your DOM remains intact. If this is not an option, then your scenario is not really a use case for the with-binding (and your own binding would indeed be a helpful one for such scenarios).
  2. I'm not entirely sure. I tried to look into the with-binding, but for some reason I can't spot it in the Knockout code. It's tested easily though, just set up an event binding within the with binding, then change the observable's value a few times. It does seem a bit worrying that you never update the with-binding when the value is undefined/null though: I can imagine this can easily lead to binding errors further down the DOM.
  3. There are certainly good reasons for this, especially in a Single Page Application. I'm doing a pretty huge application with Knockout as an SPA. By proper use of the with-binding and cleaning up my viewmodels when a view is unloaded, I can manage memory (of which DOM nodes are a big part) pretty easily, even though views are cached on the frontend. The application would run extremely slowly if we didn't have a mechanism for unloading DOM nodes when the relevant data is not present. This is a data-driven approach I really enjoy: the parts of the DOM that are shown are the parts that are relevant, because the data is there.


来源:https://stackoverflow.com/questions/21415232/knockoutjs-with-binding-before-model-is-available

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!