Alan
Alan

Reputation: 3745

knockout.js visible binding to table cell contents not working

I'm using knockout.js (v2.2.1) for the first time, and am trying to build a table where elements toggle between text and input fields based on an "IsReadOnly" property in the view model. This is accomplished using "visible" on span and input tags within the table cells.

Here's the table:

<table>
 <tr>
   <td colspan="2">
     <button id="btnEditSave" data-bind="text: btnEditSave, click: doEditSave" style="float:right;" />
   </td>
 </tr>
 <tr>
  <td>Server Name: </td>
  <td>
   <span data-bind="text: Server.ServerName, visible: IsReadOnly() == true" />
   <input data-bind="value: Server.ServerName, visible: IsReadOnly() == false" maxlength="50" style="width:400px;" />
  </td>
 </tr>
</table>

and the model:

var ServerViewModel = function () {
    // Data
    var self = this;
    self.IsReadOnly = ko.observable(true);       // the form's input mode
    self.btnEditSave = ko.observable("Edit");    // the Edit/Save button text
    self.Server = ko.observable({});             // the Server object

    // Operations
    self.doEditSave = function () {
        var flag = self.IsReadOnly();
        if (flag) {
            // switch to Edit mode
            self.btnEditSave("Save");
            self.IsReadOnly(false);
        }
        else {
            // will eventually save the form data here...

            // switch back to readOnly
            self.btnEditSave("Edit");
            self.IsReadOnly(true);
        }
    }
}

Everything toggles as expected, except that the input field is not displayed. I've tried various forms of the input tag's "visible" expression, yet nothing works. What am I missing?

Upvotes: 1

Views: 1697

Answers (3)

Matt Burland
Matt Burland

Reputation: 45135

Try:

 <span data-bind="text: Server.ServerName, visible: IsReadOnly"></span>
 <input data-bind="value: Server.ServerName, visible: !IsReadOnly()" maxlength="50" style="width:400px;" />

Edit: good catch by Warappa on the self-closing span. Knockout don't like 'em.

Upvotes: 0

David Rettenbacher
David Rettenbacher

Reputation: 5120

I think you should write ...value: Server().ServerName,... and ...text: Server().ServerName,... as Server is an observable.

Everything else seems pretty right to me.

BTW: A jsfiddle would help alot.

EDIT:

I just set up a jsfiddle: http://jsfiddle.net/GRShn/1/

The problem is that you write a self-closing span - which cannot be selfclosing. Just write <span ...></span> instead of <span ... /> and your initial version works!

Upvotes: 2

Alan
Alan

Reputation: 3745

I couldn't determine why my first example didn't work, but I did find a solution: use another property "IsEditable" which is the opposite of "IsReadOnly" so my expressions only test for true.

The table row is now:

<tr>
  <td>Server Name: </td>
  <td>
   <input data-bind="value: Server.ServerName, visible: IsEditable" maxlength="50" style="width:400px;" />
   <span data-bind="text: Server.ServerName, visible: IsReadOnly" />
  </td>
 </tr>

and the model is:

var ServerViewModel = function () {
    // Data
    var self = this;
    self.IsReadOnly = ko.observable(true);       // the form's input mode
    self.IsEditable = ko.observable(false);      // <<--- the workaround
    self.btnEditSave = ko.observable("Edit");    // the Edit/Save button text
    self.Server = ko.observable({});             // the Server object

    // Operations
    self.doEditSave = function () {
        var flag = self.IsReadOnly();
        if (flag) {
            // switch to Edit mode
            self.btnEditSave("Save");
            self.IsReadOnly(false);
            self.IsEditable(true);
        }
        else {
            // switch back to readOnly
            self.btnEditSave("Edit");
            self.IsReadOnly(true);
            self.IsEditable(false);
        }
      }
    }

Upvotes: 0

Related Questions