2

I've been trying to solve this for a couple days now, but couldn't make it work. In replacing old flash brands-we-sell-like-banner at some e-commerce site we run, for a Javascript and mobile-friendly solution, I'm trying to catch up with this requirements:

  • Get brand list and settings (i.e. max items per slide) thru AJAX (done).
  • Use bootstrap carousel (done).
  • Dynamic carousel content rendering, using Knockout

The issue is on the latter, as I can't find a way to draw contents per-slide. A non-dynamic rendering (straight html based), of what I'm trying to achieve, can be seen in this SO question (with jsfiddle companion).

I'm having troubles with the KO foreach binding, in order to render multiple-items per slide.

Some insights on the following code...

  • brands: the brand structure List. An observableArray, containing non-observable structures representing brands (name, image-url, etc.)
  • $parent.isFirst(): returns if a new slide must be drawn, given the max amount of items per slide
  • $parent.defineItemClass: returns the class for the slide (it only marks the first one with 'active item', the rest are only 'item'
  • $parent.drawTail: tells if the contained html must be drawn or not

The template...

<script type="text/html" id="brand-widget-template">
<div class="container-fluid">
    <div class="row-fluid">
        <div class="carousel slide" id="brands-carousel">
            <div class="carousel-inner" data-bind="foreach: brands">
                <!-- ko if: $parent.isFirst() -->
                <div data-bind="css: $parent.defineItemClass($index)">
                    <ul class="thumbnails">
                <!-- /ko -->
                    <li class="span1">
                        <div class="caption">
                            <h5 data-bind="text: Name"></h5>
                        </div>
                        <div class="thumbnail">
                            <img src="#" alt="">
                        </div>
                    </li>
                <!-- ko if: $parent.drawTail() -->
                    </ul>
                </div>
                <!-- /ko -->
            </div>
        </div>
    </div>
</div>

I must have a misunderstanding on the way the rendering gets done. In debugging, I notice that $parent.drawTail, never gets called. Any ideas?

Here's a fiddle on wich I isolated the most important pieces from the project.

Thanks! Luigi

Community
  • 1
  • 1
Luigi
  • 100
  • 2
  • 10
  • Take this for example: [link](http://stackoverflow.com/questions/15421332/twitter-bootstrap-carousel-displaying-multiple-thumbnails?rq=1). This PHP on the server side, takes care of the per-slide-items with a foreach. I'm trying to assemble both the 'slide' and 'per-slide-items' on a single run, using a ko foreach and some conditionals. – Luigi Mar 16 '13 at 13:52
  • Please let me know if this wasn't clear enough. Would it be better to abandon Knockout for a server-side solution on this one? – Luigi Mar 19 '13 at 12:45

1 Answers1

0

I think it would be better to have a computed observable that breaks up the main list into a nested list so you can use nested for each loops. This puts the view logic back in the viewmodel as opposed to having it in the template.

So something like this for the view model:

 self.brands_in_fours = ko.computed(function () {
        var outer_array = [];

        _.each(self.brands(), function (item, index) {
            if (index % 4 == 0) {
                outer_array.push(ko.observableArray([item]));
            } else {
                outer_array[outer_array.length - 1]().push(item);
            }
        });
        return outer_array;
    });

(I use underscore.js to loop over the self.brands array)

Template:

<div class="carousel-inner" data-bind="foreach: brands_in_fours">
    <div class="item" data-bind="css: {'active': $index()==0}">
        <ul data-bind="foreach: $data">
            <li class="span3">
                <div class="caption">
                    <h5 data-bind="text: Name"></h5>
                </div>
                <div class="thumbnail">
                    <img src="http://placehold.it/260x180" alt="" />
                </div>
            </li>
        </ul>
    </div>
</div>

Also I think you're overcomplicating the addition of the 'active' class to the first element - you can just check the index and add it if its equal to 0.

I've attached a jsfiddle

teddy777
  • 661
  • 8
  • 20