Daniel Hardt
Daniel Hardt

Reputation: 801

JQuery UI Tabs Issue with Knockout binding of observableArray

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

Answers (1)

Rango
Rango

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:

  1. UI Tabs are initialized within #StammTabs element
  2. Your model initializes
  3. tbody content is saved somewhere and detached from DOM since observable First is not initialized yet (normal behaviour of with binding).
  4. Model loads data.
  5. Observable First is filled up with object.
  6. New tbody is generated by copying saved tbody with given values.
  7. New tbody is attached to DOM (event handlers are not copied from original tbody).
  8. Tabs looks styled but event handlers are not reassigned (tabs do not work).

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

Related Questions