Reputation: 801
I get an odd issue from JQuery UI Tabs:
When i binding Data with Knockout to some Textfields, the JQuery UI Tabs don't work anymore. If I disable ko.applyBinding, then it works. If i remove then "with" or the "foreach" tag from knockout, the tabs are working fine.
But if I use the "with" tag, an i want a JQuery Tab in this area, then the Tabs stop working without any error in the jsConsole.
Some backgrounds:
Link: http://jsfiddle.net/7rPR3/23/
Codes:
<table>
<tbody data-bind="with: First">
<!-- <tbody> -->
<tr>
<td>PersoNr:</td>
<td><input data-bind="value: PersoNr" type="text" disabled /></td>
</tr>
<tr>
<td>Name:</td>
<td><input data-bind="value: Name" type="text"/></td>
</tr>
<tr>
<td>Vorname:</td>
<td><input data-bind="value: Vorname" type="text"/></td>
</tr>
<tr>
<td>Save:</td>
<td><button data-bind="click: $root.saveData">Save</button></td>
</tr>
<tr>
<td colspan="2">
<div id="StammTabs">
<ul>
<li><a href="#StammAdresseTab">Adresse</a></li>
<li><a href="#StammFunktionTab">Funktion</a></li>
<li><a href="#StammVertragTab">Vertragsdaten</a></li>
<li><a href="#StammTeamTab">Team</a></li>
<li><a href="#StammBankSozTab">Bankdaten/Sozialvers</a></li>
<li><a href="#StammKrankenversicherungTab">Krankenvers.</a></li>
<li><a href="#StammSonstigesTab">Sonstiges</a></li>
<li><a href="#StammUnterlagenTab">Unterlagen</a></li>
</ul>
<div id="StammAdresseTab">
</div>
<div id="StammFunktionTab">
<p>StammFunktionTab</p>
</div>
<div id="StammVertragTab">
<p>StammVertragTab</p>
</div>
<div id="StammTeamTab">
<p>StammTeamTab</p>
</div>
<div id="StammBankSozTab">
<p>StammBankSozTab</p>
</div>
<div id="StammKrankenversicherungTab">
<p>StammKrankenversicherungTab</p>
</div>
<div id="StammSonstigesTab">
<p>StammSonstigesTab</p>
</div>
<div id="StammUnterlagenTab">
<p>StammUnterlagenTab</p>
</div>
</div>
</td>
</tr>
</tbody>
</table>
JS:
var tabs = $("#StammTabs").tabs({
select: function (event, ui) {
alert("hallo!");
}
});
var data = [];
var stammViewModel = function() {
var self = this;
self.stammPersoNr = 'XX0000';
self.data = ko.observable(data);
self.dataArray = ko.mapping.fromJS(data);
self.First = ko.computed(function () {
return self.dataArray()[0];
});
var json = '[{"$id":"1","ID":299,"PersoNr":"TZ1155","Name":"Mustermann","Vorname":"Martin","Geschlecht":"m","Eintritt":null,"Austritt":"2999-01-01T00:00:00","Geburtsdatum":null,"Staatsangehörigkeit":null,"aktuellerStatus":8,"Intranet":false,"Bild":null,"Bemerkung":null,"User":null,"Userdatum":null,"StammAdr":[{"$id":"2","ID":205,"PersoNr":"TZ1155","Datum":"2008-01-15T00:00:00","StraßeNr":"Irgendwo. 2","PLZ":12345,"Ort":"Berlin","Tel":null,"Mobil":null,"EMail":null,"User":null,"Userdatum":null,"Stamm":{"$ref":"1"}}]}]';
alert(json);
self.loadData = function () {
if (self.stammPersoNr !== '') {
$.ajax({
type: "POST",
url: " /echo/json/",
data: {
json:json
},
cache: false,
success: function(data){
ko.mapping.fromJS(data, self.dataArray);
}
});
} else {
}
};
self.loadData();
};
ko.applyBindings(new stammViewModel());
Upvotes: 2
Views: 2436
Reputation: 3907
Thanks for interesting question. The correct answer is hidden in your experiments with foreach
and with
bindings, which both cause complete rerendering of child nodes.
Take a look how your fiddle is executed step-by-step:
tbody
content is saved somewhere and detached from DOM since observable First
is not initialized yet (normal behaviour of with
binding).First
is filled up with object.tbody
is generated by copying saved tbody
with given values.tbody
is attached to DOM (event handlers are not copied from original tbody
).The obvious solution is to intercept moment when content is rendered and somehow reinitialize tabs. foreach
binding has a build-in option afterRender
that allows to hook this moment. I guess that with
binding has not afterRender
option (I tried it but looks like the option is not working with with
).
So IMHO the best solution is to use custom binding for UI Tabs widget initializing. This approach guarantees that tabs will be initialized properly after each change of First
value. For example:
ko.bindingHandlers.uiTabs = {
init: function(el){
$(el).tabs({ select: function(){ alert("hello"); } });
}
};
and explicitly bind to #StammTabs:
<div id="StammTabs" data-bind="uiTabs: 1">
Any value is allowable in this case, but you can rewrite the custom binding to get more flexible behaviour.
Updated fiddle - http://jsfiddle.net/7rPR3/24/
Upvotes: 3