1

I created a custom knockout binding that wraps a given div in an expander. My custom binding moves the given content div to the contant-container div of the expander. After moving the content, the knockout bindings of the content child nodes would not work any more (e.g. click binding for a button inside the content div). Therefore I have to reapply the knockout bindings.

This works in most cases. However, If the content div contains for example a knockout foreach binding, reapplying the bindings means that some content is duplicated.

Example usage of the expander binding:

<div    
    data-bind="expander: { title: 'dataCollectionForms'}">
<div>
  <div class="expander-content">
    <button     
      data-bind="click: $root.addAction, text: 'Hinzufügen'"></button>
    <div
      data-bind="foreach: listOfButtons">
      <button       
        data-bind="click: $root.buttonClickAction"> 
      </button>
    </div>
  </div>
</div>
</div>

My code for moving the content div:

function moveExpanderContentToContentContainer($contentContainer, expanderContent) {
  try {

    //Move the expander content to the content container
    //The content will not be cloned but moved. For more info see:
    //https://api.jquery.com/append/
    var $expanderContent = $(expanderContent);
    $contentContainer.append($expanderContent);
    $contentContainer.addClass('expander-content-container panel-body');
    $expanderContent.addClass('expander-content');

    ko.applyBindingsToDescendants(bindingContext, expanderContent); 

  } catch (appendException) {
    var errorMessage = 'Could not append expander-content to expander-content-container.';
    logger.logError(errorMessage, appendException, self, true);
  }

}

  • If I remove the line

ko.applyBindingsToDescendants(bindingContext, expanderContent);

the click actions of my three buttons do not work any more: enter image description here

  • If I keep the line, the click actions work but the buttons are duplicated: enter image description here

=> How can I update the bindings of the moved content in a way that fixes the click bindings and does not duplicate my buttons?

=> If this moving work flow does not work at all, what is a better way to create a custom knockout binding that wraps a given content in a collapsable expander?

I could find some related articles but no solution to my specific issue:

Community
  • 1
  • 1
Stefan
  • 10,010
  • 7
  • 61
  • 117
  • I think it will be helpful for you to try to make a minimal reproduction of the problem. I don't see any reason that simply moving a div would invalidate bindings unless you're expecting the move to change the context for the bindings. It is possible you want to use a template instead. – Roy J Jan 28 '16 at 12:40

2 Answers2

1

I solved the issue by not moving the content div at all but building the expander around it.

My original strategy was to have a reusable expander view + view model and to move the content div from the original location to the newly composed expander view. Moving around the already bound content was no good idea, I guess.

The new strategy adapts the already existing divs and composes only the header for the expander.

Nevertheless thank you for your thoughts.

Stefan
  • 10,010
  • 7
  • 61
  • 117
0

I use following code for recreating content of the passed DOM element (having view model + template selector):

function renderIntoElement(element, viewModel, templateSelector) {
    templateSelector = templateName || "#myTemplateId";
    var $element = $(element);
    var templateHtml = $(templateSelector).text(),

    $element.children().remove();
    $element = $element.append(templateHtml),

    ko.applyBindings(viewModel, $element.children()[0]);
}

Hope this helps.

TSV
  • 7,538
  • 1
  • 29
  • 37