below the belt: Knockout.js and the last array item in a navigation menu

I've been working on a web-based luthier tool for a friend of mine and typically, with these projects I work on from home, I try to incorporate something new – so that I can learn something new.

For this project, I decided to use Knockout and also do some light responsive design since I could see a luthier using the tool to make fret distance calculations on their smartphone – although I eventually see people printing out the results to paper for use in their workshop. At least, I certainly see my luthier friend Jim doing that – and he's my "customer" in the sense that I'm making the tool for him first and foremost.

I'm pretty happy with Knockout and I really like that, for me, it puts jQuery in it's place because I see jQuery more as an effects rack, to use an electric guitar analogy, and not a tool for dynamically parsing/creating HTML elements. I think JavaScript MVC frameworks like Knockout are the better choice for that.

Anyway, I'm mainly I'm using Knockout to dynamically create a navigation menu from an array and one of the issues I struggled with last week was this:

… basically, I wanted to iterate through each array item and create a navigation link per item and place a vertical "|" character in between all elements. But I didn't want to see the pipe after the last menu item.

In other words, I wanted this for a hypothetical navigation array with items "foo", "bar", and "baz":

foo | bar | baz

and not this:

foo | bar | baz |

Trying to find a solution was a matter of scouring through site like Stack Overflow and beating my head against a wall, but I seem to have found something that works. I'm sure the Stack Overflow solutions are fine, but I was just learning Knockout last weekend, so I guess I wasn't ready to do it the way suggested. I wasn't getting it and it wasn't working.

So what I did was was create a computed observable called "last_item" that returned the value of the last array element as "last":

var viewModel = {

  navigation_options: ko.observableArray([
  {option: "home"},
  {option: "calculator"},
  {option: "demo"},
  {option: "api"},
  {option: "about"}
  ]),
};
 
last_item: ko.computed(function () {
    options = viewModel.navigation_options();
    last = options[options.length-1]["option"];
    return last;
  }, viewModel);
 
ko.applyBindings(viewModel);

And then I was able to do this in my HTML file:

<div id="desktop_navigation" data-bind="foreach: navigation_options">
  <a href="" data-bind="click: function(data, event) { fader(option) }">
    <span data-bind="text: option"></span>
  </a>
  <span data-bind="if: option != last">
    <span> | </span> 
  </span>
</div>

Anyway, that seems to be working for me. And it was easy enough to do and for me to understand.

I guess that's all for now.

--------------

Related Content:

2 Comments

  1. ebohlman

    Putting a separator after all items but the last is the same thing as putting it before all items but the first, and testing for the first item is easier than testing for the last since it doesn't depend on the length. Just move the span with the separator to before the anchor and change the binding to "if: $index"; you can then get rid of the computed value.

    Reply
    1. nitin (Post author)

      Thanks for the tip!

      Reply

Leave a Comment

Your email address will not be published. Required fields are marked *

*