Knockout default text when `foreach` is empty

Brian M. Hunt picture Brian M. Hunt · May 31, 2013 · Viewed 11.4k times · Source

Bearing in mind that similar questions have been answered here, I was wondering how one might go about having default text or HTML display inside a Knockout data-bind='foreach: list' whenever the list is empty.

The solutions on the linked page don't quite seem to line up with this, and in any case I thought of another way to try to accomplish this with a custom binding like this:

text.default = {
  update: function (element, valueAccessor) {
      var $e = $(element),
          obs = valueAccessor();

      function _check_blank() {
         // the element has content - so we do nothing
         if ($e.text().trim()) {
            return;
         }
         // the element is empty;
         $e.text("Default Text")
      }
      // we use setTimeout to ensure that any other bindings complete 
      // their update
      setTimeout(_check_blank, 0);
  }
}

This seems to work reasonably well with simple observables but it does not work with the foreach binding, though in any case I think the extender suggestion in the above link is probably preferable for a few reasons -- the above code would have a number of caveats. Nevertheless, I threw this example in here because it somewhat highlights an alternative and food for thought.

All that being said, I would like to know what options there might be for providing a default in lieu of foreach content.

One is to provide a wrapper in a simple if, like this:

<!-- ko if: xyz().length -->
   // foreach
<!-- /ko -->
<!-- ifnot: xyz().length -->
   // default text
<!-- /ko -->

However this is not particularly elegant -- lots of code clutter.

Answer

Tom Blodget picture Tom Blodget · May 31, 2013

Knockout gives you if and ifnot bindings. You just have to step back a bit from the element with foreach; Its insides are just for each element, so when there are none, there aren't any insides.

<div data-bind="if: pets().length > 0">These are the pets:</div>
<div data-bind="if: pets().length == 0">There aren't any pets. To add a pet...</div>
<div data-bind="foreach: pets">

Editorial: Your question is important because empty lists are an opportunity to say something instead of showing a blank slate.