开发者

Add striped styling to a list of items

开发者 https://www.devze.com 2023-03-15 00:52 出处:网络
What would be the best way to stripe a list with KnockoutJS? The class on the div below should be even or odd depending where it is in the list, and update when adding or removing items.

What would be the best way to stripe a list with KnockoutJS? The class on the div below should be even or odd depending where it is in the list, and update when adding or removing items.

<div class="Headlines loader" 
     data-bind="css: { loader: headlines().length == 0 }, 
                       template: { name: 'recentHeadlinesTemplate',
                                   foreach: beforeHeadlineAddition, 
                                   beforeRemove: function(elem) { $(elem).slideUp() },
                                   afterAdd: slide开发者_JAVA百科Down }">
</div>

<script type="text/html" id="recentHeadlinesTemplate">
    <div class="even">
        ${Title}
    </div>  
</script>


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


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/


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>


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)


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>
0

精彩评论

暂无评论...
验证码 换一张
取 消