Cut multiple bindings for nested dom elements

I was able to sort out a bit with the project I am working on.

Initially the site has one page that uses Knockout and other pages use jQuery. Due to some issues with the Foundation module being placed at the root of the body element, I ended up applying the viewmodel bindings for that page to the body element.

Fast forward 4 months and without foreseeing the problem I am now, I went and rebuilt our Knockout shopping cart. The shopping cart is visible on every page and is enabled with a partial ZF2.

Going back to the page I was working on 4 months ago, it is completely broken with an error message in the console:

Uncaught Error: You cannot apply bindings multiple times to the same element.

      

Here's some code to display my layout:

<html>
    <head>
        <title>My Website</title>
    </head>
    <body> // 4 month old SPA bound here
        <nav>
            <div id='shopping-basket'> // Shopping basket bound here
                ...
            </div>
        </nav>
        <div id='my-app'>
           ...
        </div>
    </body>
</html>

      

JavaScript:

var MyAppViewModel = function() {
   // logic
};

var ShoppingBasketViewModel = function() {
    //logic
};

ko.applyBindings(new MyAppViewModel(), document.body);
ko.applyBindings(new ShoppingBasketViewModel(), document.getElementById('shopping-basket');

      

If I had time, I could go back and rework the original application to sit in its own div container that will sit next to the shopping cart, but unfortunately this is not an option.

Another option is to discard the last bit of work I did in the shopping cart and replace it with jQuery, but that would mean lost work within a week.

Is there ever when I use bindings that can have both models working side by side, being nested in the Dom and remaining independent of each other?

+3


source to share


1 answer


I had a similar problem. I needed to apply anchor to specific nested elements and start with anchor in the document first. Same problem. My solution was to add some part of the ignore element and link the specific element manually.

1) Add a custom binding so you can skip binding to a specific shopping cart:

ko.bindingHandlers.stopBinding = {
    init: function() {
         return { controlsDescendantBindings: true };
    }
};
ko.virtualElements.allowedBindings.stopBinding = true;

      

2) Add a custom anchor to your html (surround your cart):

<html>
<head>
    <title>My Website</title>
</head>
<body> // 4 month old SPA bound here
    <nav>
        <!--  ko stopBinding: true -->
        <div id='shopping-basket'> // Shopping basket bound here
            ...
        </div>
        <!--  /ko -->
    </nav>
    <div id='my-app'>
       ...
    </div>
</body>

      



3) Apply your bindings as you already did:

ko.applyBindings(new MyAppViewModel(), document.body);
ko.applyBindings(new ShoppingBasketViewModel(), document.getElementById('shopping-basket');

      

4) The first binding will skip the shopping cart because of your custom binding handler, and your second binding will explicitly bind the shopping cart.

I haven't tested the code above with your specific example, but it should point in the right direction.

+2


source







All Articles