Steve Wash
Steve Wash

Reputation: 986

Determine if an item is the first item in an observableArray

I have a template that its bound to a knockout observableArray. I'm trying to get a something to display only on the first item in the array. When the first item is deleted, the next item that becomes the first should then display this section. It should work similar to the following code. The key is the isFirst function.

HTML

<div data-bind="template: { name: 'my-template', foreach: people }"></div>
<script type="text/html" id="my-template">
    <div>
        <span data-bind="visible: isFirst">The first person is </span>
        <span data-bind="text: name"></span>
    </div>
</script>
<button data-bind="click: removeFirst">Remove First</button>

ViewModel

function Person(p,name,age) {
   this.parent = p;
   this.name = name;
   this.age = age;
   this.isFirst = ko.computed(function(){
       return this.parent.people.indexOf(this) === 0;
   });
}
var viewModel = function() {
   var self = this;
   self.people = ko.observableArray();
   self.people.push(new Person(self, 'Fred', 25));
   self.people.push(new Person(self, 'Joe', 15));
   self.people.push(new Person(self, 'Sally', 21));
   self.people.push(new Person(self, 'Ann', 37));
   self.people.push(new Person(self, 'Jack', 52));

   self.removeFirst = function () {
          people.splice(0, 1);
      }
   };   
};

Upvotes: 1

Views: 789

Answers (1)

Origineil
Origineil

Reputation: 3118

Since you are within the context of a foreach binding you can take advantage of the $index property detailed within the link under "Note 2 : Using $index, $parent, and other context properties"

You have a couple different options.

  1. Use a containerless if binding to only render markup for the first element similar to the discussion within this question

    <!-- ko if: $index()=== 0 -->
     <span>The first person is</span>
    <!-- /ko -->
    
  2. Continue to use the visible binding to render markup for each element but only be visible on the first item

    <span data-bind="visible: $index() == 0">The first person is </span>
    

For this particular case, option #1 is the more suitable approach.


Edit: Keeping it in the viewmodel:

I'd move isFirst into $root, and then change the binding. Since, we already have $index you could pass that in

<!-- ko if: $root.isFirst($index) -->

-

 self.isFirst = function(index){
  return 0 === index();
}

Alternatively and similar to your original approach:

<!-- ko if: $root.isFirst($data) -->

-

self.isFirst = function(item){
  return 0 === self.people.indexOf(item);
}

Upvotes: 2

Related Questions