1

I am using knockout binding.

After initially creating the table and setting the binding, I am trying to add a new row or update an existing entry, and then update the table.

But when data gets updated, KnockOut is giving me the error message "You cannot apply bindings multiple times to the same element".

Here is my code

 ko.applyBindings(viewModel);
 $('.tree').treegrid();
Joshua Briefman
  • 3,783
  • 2
  • 22
  • 33
Dipali Wagh
  • 85
  • 1
  • 11
  • Possible duplicate of http://stackoverflow.com/q/17710788/2585788 – Joshua Briefman Jan 06 '17 at 08:46
  • I have already tried this. But still its not working – Dipali Wagh Jan 06 '17 at 09:07
  • What about "StopBindings"? Referenced in the comment to that question: http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html – Joshua Briefman Jan 06 '17 at 09:14
  • When I'm calling ko.applyBindings(viewModel); again, its throwing same error – Dipali Wagh Jan 06 '17 at 09:39
  • Are you able to provide any additional debug/trace level information about that element and the actions taking place against it? – Joshua Briefman Jan 06 '17 at 09:40
  • when i'm debugging it, its redirecting to knockout.js, which has below code : var m = a.a.e.get( b, q ); if ( !c ) { if ( m ) throw Error( "You cannot apply bindings multiple times to the same element." ); a.a.e.set( b, q, !0 ) } – Dipali Wagh Jan 06 '17 at 09:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/132473/discussion-between-dipali-wagh-and-joshua-briefman). – Dipali Wagh Jan 06 '17 at 09:46
  • Instead of chatting about this, please provide a complete, minimal, self-contained, runnable example that reproduces the error. The code you show in your question is not enough to help you. – Tomalak Jan 06 '17 at 17:06

2 Answers2

1

Per the error, re-binding an already bound element is not possible. Clearing the existing bindings and then re-binding is also not the ideal way to do updates.

Based on our chat last night, I believe you are trying to update the table and then show that reflective update.

Instead, please consider the following example to update an existing KnockOut table.

It isn't using jQuery or TreeGrid, but adding them shouldn't be too much work. I feel removing them simplifies this example to make it more clear.

Otherwise, this should be a pretty good example of adding, removing, and changing table entries dynamically (and not just on initialization).

Code

// Function to create KnockOut view
var ViewModel = function() {
var self = this;

// This is row 0.
self.rows = ko.observableArray([
    {name:'DefaultEntry', number:-1}
]);
}

// Function to create a row entry
var Row = function(name, number) {
var self = this;
self.name = ko.observable(name);
self.number = ko.observable(number);   
};

// Create the view and apply bindings.
vm = new ViewModel();
ko.applyBindings(vm);

// Add more rows live
vm.rows.push(new Row('OldTest',10)); // Row 1, Row 0 was defined earlier.
vm.rows.push(new Row('Sam',1010));
vm.rows.push(new Row('Max',1523));

// Change a specific entry ("OldTest" -> "NewTest")
// Note: vm.rows() returns an array of rows in the table, and [1] selects the index number of Row 1.
// vm.rows()[1] returns the index which KO can reference of row 1
vm.rows.replace(vm.rows()[1], new Row('NewTest',9999));

// Remove last entry
vm.rows.pop();

// Remove all rows
vm.rows.removeAll();

// Add new row
vm.rows.push(new Row('Bob',2000));
vm.rows.push(new Row('Tom',3000));
vm.rows.push(new Row('Sally',4000));
vm.rows.push(new Row('Lou',5000));
vm.rows.push(new Row('Zack',6000));

// Remove all rows where name == 'Tom'
vm.rows.remove( function (person) { return person.name() == "Tom"; } )

// Remove row 2-3 (Lou and Zack)
garbageData = vm.rows.splice(2,3);

// In the above example, garbageData contains an array of the removed rows.
// Splice also works as "vm.rows.splice(2,3);"
// You do not need to save the array returned by splice.

// Final output:
// Bob   2000
// Sally 4000
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>


<table>
<thead>
    <tr>
        <th>Name</th>
        <th>Number</th>
    </tr>
</thead>
<tbody data-bind="foreach: rows">
    <tr>
        <td><input class="input-small" data-bind="value: name"/></td>
        <td><input class="input-small" data-bind="value: number"/></td>
    </tr>
</tbody>
</table>

I'm also adding the KnockoutJS site which shows additional methods which are available to manipulating those rows: KnockoutJS - Observable Arrays

Joshua Briefman
  • 3,783
  • 2
  • 22
  • 33
  • but for this, again I need to call applyBinding. – Dipali Wagh Jan 09 '17 at 06:03
  • But only once, don't call it more than that. You'll note I update the table after applybindings is called. – Joshua Briefman Jan 09 '17 at 16:26
  • I tried this. Its working, but old records remain as it is. I'm not able to delete old records. Its appending old records. tell me if old records are 5 and new records are only 2 then how to replace 5 records with 2 records. – Dipali Wagh Jan 10 '17 at 04:42
  • I've updated my answer to include additional remove examples. Now that I know what exactly what you were trying to do, I am able to provide the specific example for your use-case :-) – Joshua Briefman Jan 10 '17 at 05:38
  • @DipaliWagh I haven't heard from you in a little while. Did my latest update help or are you still having issues? – Joshua Briefman Jan 13 '17 at 01:51
  • your code is updating new data, but the tree structure is not showing, so I'm reloading the page and applying binding. Its not a good way but no other option. Side by side I'm searcing how to unbind a node? – Dipali Wagh Jan 13 '17 at 04:12
  • Looking over the example I provided, and how Treegrid is typically implemented it appears the issue is that Treegrid needs to be implemented within the KnockOutJS ViewModel, and not applied after binding (so it can be updated alongside table updates). I'll see if I can find time to put an example together later this weekend. – Joshua Briefman Jan 13 '17 at 05:51
  • I found an example of that particular implementation. This should help to show how to implement this design. It's not the same kind of table you are using but the important part is where the TreeGrid is applied: http://www.igniteui.com/tree/bind-tree-with-ko – Joshua Briefman Jan 13 '17 at 05:55
0

You should clean the node first and apply the knockout bindings.

ko.cleanNode($('#html-element-id')[0]);
ko.applyBindings(new ViewModel(modelData{}), $('#html-element-id')[0]);
Distnie Manuel
  • 131
  • 1
  • 3