stacknist
stacknist

Reputation: 587

Default text for null value with knockout bindings

I am using the same observable for display and edit views as follows. I would like a default text ('-') to appear in the display view whenever the return value is null, but I do not want that in the edit view. How could that be achieved?

function ViewModel() {
  var self = this;
  self.txt1 = ko.observable();
  self.txt2 = ko.observable();
}
// View Mode
<span data-bind="text:txt1"></span>
<span data-bind="text:txt2"></span>

// Edit Mode
<input type="text" data-bind="value:txt1" />
<input type="text" data-bind="value:txt2" />

Upvotes: 0

Views: 3485

Answers (3)

Andrea Casaccia
Andrea Casaccia

Reputation: 4971

This might not be the most paradigmatic Knockout.js solution but it's working well and it's very quick. Instead of the <span> you could use an HTML <input />, with placeholder="-" readonly="readonly". You may want also to style it so that you hide borders.

<input class="readonly" data-bind="value:txt1" readonly placeholder="-" />
<input class="readonly" data-bind="value:txt2" readonly placeholder="-" />
.readonly {
    border: 0;
}

http://jsfiddle.net/Lbf3uxqe/

Upvotes: 1

James Thorpe
James Thorpe

Reputation: 32202

An alternative approach to computeds as per my other answer is to write an entire new custom binding handler. This means you only have the one observable on your view model, with the logic contained within the binding handler instead. Note that you need to change the view to use this binding handler, rather than the text binding it was using:

ko.bindingHandlers.textdefault = {
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    var v = valueAccessor();
    var d = allBindings.get('defaultIfBlank') || '-';
    element.innerText = (v() == null || v() == '') ? d : v();
  }
};

function ViewModel() {
  var self = this;
  self.txt1 = ko.observable();
  self.txt2 = ko.observable();           
}

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
// View Mode<br />
<span data-bind="textdefault:txt1"></span><br />
<span data-bind="textdefault:txt2, defaultIfBlank: '$'"></span><br />
<br />
// Edit Mode<br />
<input type="text" data-bind="value:txt1" /><br />
<input type="text" data-bind="value:txt2" /><br />

Note that in this approach, we can also customise the handler through the allBindings variable - in the above I have added a parameter to allow customising of which character is displayed if the entry is blank.

Upvotes: 0

James Thorpe
James Thorpe

Reputation: 32202

You can use a computed observable to return a value for the view mode, using it to check the value currently stored and return - if necessary:

function ViewModel() {
  var self = this;
  self.txt1 = ko.observable();
  self.txt2 = ko.observable();

  self.viewtxt1 = ko.computed(function() {
    if (self.txt1() == null)
      return '-';

    return self.txt1();
  });

  self.viewtxt2 = ko.computed(function() {
    //txt2 is checked for null or blank, use whichever is appropriate
    if (self.txt2() == null || self.txt2() == '')
      return '-';

    return self.txt2();
  });
                              
}

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
// View Mode<br />
<span data-bind="text:viewtxt1"></span><br />
<span data-bind="text:viewtxt2"></span><br />
<br />
// Edit Mode<br />
<input type="text" data-bind="value:txt1" /><br />
<input type="text" data-bind="value:txt2" /><br />

In the above there are two different checks. txt1 is checked just for null, and so if you edit it and delete all characters, the blank value will persist in the view. txt2 is checked for both null and blank, so removing all characters will reset the view back to -. Use whichever one is appropriate to you.

Upvotes: 1

Related Questions