0

Clicking on the button more than one time duplicates data in UI.

What I expected on every click : * Name1 * Name2

But: * Name1 * Name1 * Name2 * Name2

<html>
<head>
  <script src="http://knockoutjs.com/downloads/knockout-3.3.0.js" type="text/javascript"></script>
</head>
<body>
  <div id="myDiv">
    <div data-bind="foreach: Data">
      * <span data-bind="text: Name"></span>
    </div>
  </div>
  <button onclick="f1()">Click Me!</button>
  <script type="text/javascript">
    function myViewModel(data){
      var self = this;
      self.Data = data;
    }    
    function f1() {
      var d = [{ "Name": "Name1" }, { "Name": "Name2" }];
      ko.cleanNode(document.getElementById('myDiv'));
      ko.applyBindings(new myViewModel(d), document.getElementById('myDiv'));
      return false;
    }
  </script>
</body>
</html>
Babak
  • 3,716
  • 6
  • 39
  • 56
  • 2
    ko.cleanNode does not remove the already added DOM elements (see https://github.com/knockout/knockout/issues/912). So after the first click your HTML will look like: `
    *Name1 *Name2
    ` so clicking on the button again repeats the already inserted nodes from the previous run. So just don't use ko.cleanNode because this is not doing what you would except: http://stackoverflow.com/questions/15063794/can-cleannode-be-used-to-clean-binding
    – nemesv May 26 '15 at 08:20
  • 1
    @nemesv good comment, I reckon it's also worthy of being an answer. – Jeroen May 26 '15 at 11:30
  • Ideally you should update your view model properties instead of dropping and recreating the binding. If you still want to do that, why don't you remove the `#myDiv` DOM element, create it from scratch and bind the new model. You can keep the HTML inside a ` – JotaBe May 26 '15 at 13:50

1 Answers1

1

You should only be calling ko.applyBindings once, the cleanup and re-apply is not best practice. Try something like this out instead:

<html>
<head>
  <script src="http://knockoutjs.com/downloads/knockout-3.3.0.js" type="text/javascript"></script>
</head>
<body>
  <div id="myDiv">
    <div data-bind="foreach: Data">
      * <span data-bind="text: Name"></span>
    </div>
  </div>
  <button data-bind="click: f1">Click Me!</button>
  <script type="text/javascript">
    // viewmodel definition with click handler
    function myViewModel(data){
      var self = this;
      self.Data = ko.observableArray(data);
      self.f1 = function() {
          self.Data([{ "Name": "Name1" }, { "Name": "Name2" }]);
      }
    }    

    // create instance of viewmodel on document ready, apply bindings
    $(function(){
      var vm = new myViewModel();
      ko.applyBindings(vm, document.getElementById('myDiv'));
    });

  </script>
</body>
</html>
dfperry
  • 2,258
  • 1
  • 14
  • 22