foreach index for striping and nested use

https://groups.google.com/d/topic/knockoutjs/cJ2_2QaIJdA/discussion

by photo_tom

HTML

<script src="https://github.com/jquery/jquery-tmpl/raw/master/jquery.tmpl.js"></script>
<script src="https://github.com/SteveSanderson/knockout/raw/master/build/output/knockout-latest.debug.js"></script>
<ul data-bind="template: { name: 'itemsTmpl', foreach: items }, stripe: items, evenClass: 'light', oddClass: 'dark'"></ul>
<button data-bind="click: addItem">Add</button>
<hr/>

<ul data-bind="template: { name: 'itemsTmpl', foreach: items }, stripe2: {watch: items, even: 'light', odd: 'dark' }"></ul>
<button data-bind="click: addItem">Add</button>
<hr/>

<ul data-bind="templateWithStripe: { name: 'itemsTmpl', foreach: items, even: 'light', odd: 'dark' }"></ul>
<button data-bind="click: addItem">Add</button>
<hr/>

<script id="itemsTmpl" type="text/html">
    <li>
        <span  data-bind="text: id"></span>
        <button data-bind="click: function() { viewModel.removeItem($data) }">Delete</button>
        {{now}}
    </li>
</script>

CSS

.light { background-color: #ddd; }
.dark { background-color: #bbb; }

JavaScript

var viewModel = {
    items: ko.observableArray([{
        id: 1},
    {
        id: 2},
    {
        id: 3},
    {
        id: 4}]),
    addItem: function() {
        this.items.push({
            id: ++this.counter
        });
    },
    removeItem: function(item) {
        this.items.remove(item);
    }
};

viewModel.counter = viewModel.items().length;

//separate options in binding
ko.bindingHandlers.stripe = {
    update: function(element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor()); //creates the dependency
        var allBindings = allBindingsAccessor();
        var even = allBindings.evenClass;
        var odd = allBindings.oddClass;

        //update odd rows
        $(element).children(":nth-child(odd)").addClass(odd).removeClass(even);
        //update even rows
        $(element).children(":nth-child(even)").addClass(even).removeClass(odd);;
    }
}

//or pass an object to the binding
ko.bindingHandlers.stripe2 = {
    update: function(element, valueAccessor) {
        var options = ko.utils.unwrapObservable(valueAccessor());
        var watch = ko.utils.unwrapObservable(options.watch); //creates the dependency
        //update odd rows
        $(element).children(":nth-child(odd)").addClass(options.odd).removeClass(options.even);
        //update even rows
        $(element).children(":nth-child(even)").addClass(options.even).removeClass(options.odd);
    }
}

//or wrap the template binding (assumes use of foreach)
ko.bindingHandlers.templateWithStripe = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        //call real template binding's update
        ko.bindingHandlers.template.update(element, valueAccessor, allBindingsAccessor, viewModel);
        var options = valueAccessor();
        var value = ko.utils.unwrapObservable(options.foreach); //creates the dependency
        //update odd rows
       ...