KnockoutJS – Creating a Comma-Delimited List of Values

KnockoutJS LogoI’ve been building a lot of great stuff with KnockoutJS lately. It seems that it can enable many – if not all – of the development requirements I have these days, whether I’m building a single-page application (SPA) or just adding a snippet of content to an existing page. I can even build KnockoutJS-enabled “Web Parts” by dropping  a Content Editor Web Part [CEWP] into a page. It doesn’t matter what version of SharePoint it is.

The KnockoutJS documentation is generally very good, but sometimes I find the examples lacking a bit. It’s always tempting to make examples show off too much, which often leads to showing off too little. (I have this same problem with my SPServices documentation and examples.)

A common use case is wanting to display a set of values in a comma-delimited list. Let’s take this example. Say I have an observable array of Ticker objects, like so:

self.Tickers = ko.observableArray([
  {lookupId: 1, lookupValue:"SPLS"},
  {lookupId: 2, lookupValue:"APPL"},
  {lookupId: 3, lookupValue:"GOOG"}
]);

Because I’m pulling data from SharePoint, I want to hang onto the lookupId value along with the text value, which is what I want to display. Because of this a simple Tickers.join(“, “) doesn’t cut it.

I’d like to display the list of tickers like this:

SPLS, APPL, GOOG

Pretty simple, right? But after a little Binglage, I couldn’t find a concise example, thus this post.

If you check the KnockoutJS documentation for foreach, you’ll see that there is a variable available called $index. The $index variable gives you the zero-based index of the current array item.

So if I use foreach on Tickers:

<div data-bind="template: { name: 'Ticker', foreach: Tickers }"></div>

I can use the $index to determine if I should emit a comma. We don’t want to see a comma after the last value, so it requires this small bit of finesse.

<script type="text/html" id="Ticker"><span data-bind="visible: $index() > 0">, </span><span data-bind="text: lookupValue"></span></script>

It’s a little bit bass-ackward, but if the $index value is greater than zero – which it is for all values except the first one, where the index is zero – then we *prepend* a comma to the value.

Yes, I’m using a separate template to emit the tickers. That’s mainly because in my case I’m doing a little bit more than what I’m showing here. However, by creating a separate template, I have a reusable piece of markup. that I can use in many places.

I hope someone out there finds this useful!

References

1 Comments

  1. To avoid the consternation of putting the comma before the text in the template, you can create a custom bindingHandler that post-processes the HTML after foreach has done its thing:

    ko.bindingHandlers.replace = {
    update: function (element, valueAccessor) {
    var cfg = valueAccessor();
    var s = element.innerHTML;
    if (cfg.text)
    {
    if (cfg.eraseLast == true) {
    var last = s.lastIndexOf(cfg.text);
    s = s.substring(0, last) + s.substring(last + cfg.text.length);
    }
    s = s.split(cfg.text).join(cfg.with);
    }
    element.innerHTML = s;
    }

    Then use it like this: (this example separates the items with a comma)

    %comma%

    Reply

Have a thought or opinion?