Add striped styling to a list of items

﹥>﹥吖頭↗ 提交于 2019-12-02 19:00:44

There was a topic for this on the KO forums a while back here: https://groups.google.com/d/topic/knockoutjs/cJ2_2QaIJdA/discussion

The solution that I had was a custom binding. There were a couple variations on it, but it basically would look like:

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);;
    }
}

and be used like:

<ul data-bind="template: { name: 'itemsTmpl', foreach: items }, stripe: items, evenClass: 'light', oddClass: 'dark'"></ul>

Sample here with 3 variations of this binding:

http://jsfiddle.net/rniemeyer/HJ8zJ/

I've found a function that returns an index when iterating with foreach, so you can apply even and odd classes in a reasonably compact way, for example:

<tr data-bind="css: { 'even': ($index() % 2 == 0) }">

One easy way to do this is to add a computed observable that adds an index to each element, e.g.

    self.logLines = ko.observable(logLinesInput);

    self.enhancedLogLines = ko.computed(function() {
        var res = [];
        $.each(self.logLines(), function(index, ll) { 
             res.push(new LogLine(index, ll)); 
        });
        return res;
    }, self);

In my case LogLine() creates an object with an index field and the other fields that were in the original object.

Now you can easily add zebra stripes to your output:

            <tr data-bind="css: { odd: (index % 2 == 1), even: (index % 2 == 0) }">

Thanks for the helpful posts. I wanted to mention that css can do a good job of striping but the embedded 'if' only seems to function after the row has been rendered. Therefore, using $index or the css odd/even capabilities don't yield the desired results. Without using a template I found that you can wrap the KO logic around the row so that the logic occurs before the row is counted.

<tbody data-bind="foreach: viewModel.configuration().items()"">
    <!-- ko if: $data.part() != '' -->
    <tr>
            <td data-bind="text: $index"></td><td  data-bind="text: $data.part()"></td>
    </tr>
    <!-- /ko -->
</tbody>
neebz

You could use the {{if}} and {{else}} conditional statements inside the template to set the class of the div.

Also you will need to extend your View Model to include a function which returns the index of your current item, which would tell you whether it's odd or even. (Something like this)

netlyonel

here is a full example :

<ul class="pickupPointHours" data-bind="foreach: Items">
 <li data-bind="css: { lineEven: ($index()%2 === 0), lineOdd: ($index()%2 === 1)}">
  <span class="pickupPointDay" data-bind="text: TextProperty"></span>
 </li>
</ul>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!