2012-12-17 3 views
5

Chciałbym renderować dynamicznie wierszy i kolumn przy użyciu nokautu. Chodzi o to, że chciałbym wypełnić każdy wiersz niektórymi komórkami iw razie potrzeby dynamicznie dodać więcej wierszy. pozwala przypuszczać, że liczba totall komórek równa numer 4 * wierszy, potem próbowałem:Jak renderować tr warunkowo w knockout.js foreach wiążące

<table> 
    <tbody data-bind="foreach: model"> 
     <!--ko if: $index() % 4 == 0--><tr><!--/ko--> 
     <td> 
       <label data-bind="text: Value"></label> 
     </td> 
     <td> 
       <input type="checkbox" data-bind="checked: IsChecked"/> 
     </td> 
     <!--ko if: $index() % 4 == 0--></tr><!--/ko--> 
    </tbody> 
</table> 

ale działa tak jak to było:

<table> 
    <tbody data-bind="foreach: model"> 
     <!--ko if: $index() % 4 == 0--> 
     <td> 
       <label data-bind="text: Value"></label> 
     </td> 
     <td> 
       <input type="checkbox" data-bind="checked: IsChecked"/> 
     </td> 
     </tr><!--/ko--> 
    </tbody> 
</table> 

przez nie czyniąc cały rząd z treści, to jest możliwe z nokautem do renderowania wszystkich komórek i dodawania wierszy tylko w razie potrzeby?

Jako obejście, myślę o zagnieżdżonym foreach, ale wymagałoby to zmiany mojego modelu z jedno-wymiarowego na dwuwymiarowy, co wydaje się dziwne.

+2

Czy na pewno chcesz użyć tabeli HTML dla tego? Jeśli masz płaską listę pozycji, ponieważ Twoje dane nie mogą po prostu renderować ich jako elementów div i używać CSS, aby przepływały naturalnie wewnątrz kontenera, 4 w poprzek? –

+0

Tak, to dane tabelaryczne i tabele służą do wyświetlania danych tabelarycznych za pomocą elementu div byłoby obejściem, a nie rozwiązaniem – 0lukasz0

Odpowiedz

14

Dodaj inną właściwość obliczoną że struktury danych do wierszy:

<table> 
    <tbody data-bind="foreach: rows"> 
     <tr> 
      <!-- ko foreach: $data --> 
      <td data-bind="text:$index"></td> 
      <td data-bind="text:fname"></td> 
      <td data-bind="text:lname"></td> 
      <!-- /ko --> 
     </tr> 
    </tbody> 
</table> 

z kodem:

var vm = { 

    people: ko.observableArray([ 
     { fname: 'fname', lname: 'lname' }, 
     { fname: 'fname', lname: 'lname' }, 
     { fname: 'fname', lname: 'lname' }, 
     { fname: 'fname', lname: 'lname' } 
    ]) 
}; 

vm.rows = ko.computed(function() { 

    var itemsPerRow = 3, rowIndex = 0, rows = []; 

    var people = vm.people(); 
    for (var index = 0; index < people.length; index++) { 
     if (!rows[rowIndex]) 
      rows[rowIndex] = []; 

     rows[rowIndex].push(people[index]); 

     if (rows[rowIndex].length == itemsPerRow) 
      rowIndex++; 
    } 

    return rows; 
}, vm); 

$(function() { 
    ko.applyBindings(vm); 
}); 
+0

super fajne ... zapisane dzień – dreamerkumar

+0

Właśnie tego szukałem, dzięki ... – ShaneBlake

3

Twoja składnia nie będzie działać z domyślnym silnikiem szablonów knockout tylko dlatego, że używa DOM. Jeśli chcesz to zrobić, użyj zewnętrznego silnika szablonowego opartego na ciągach znaków (potraktujesz szablon jako łańcuch i użyjesz regex i manipulacji łańcuchami, więc będziesz w stanie zrobić tę sztuczkę z warunkowym renderowaniem tagu start/end). Twój przykład stosując underscore.js:

http://jsfiddle.net/2QKd3/5/

HTML

<h1>Table breaking</h1> 
<ul data-bind="template: { name: 'peopleList' }"></ul> 

<script type="text/html" id="peopleList"> 
    <table> 
    <tbody> 
    {{ _.each(model(), function(m, idx) { }} 
     {{ if (idx % 4 == 0) { }} 
      <tr> 
     {{ } }} 
     <td> 

       <label>{{= m.Value }}</label> 
     </td> 
     <td> 
      <input type="checkbox" data-bind="checked: m.IsChecked"/> 
     </td> 
     {{ if (idx % 4 == 3) { }} 
     </tr> 
     {{ } }} 
    {{ }) }} 
      </tbody> 
      </table> 
</script> 

JavaScript (w tym podkreślenia integracja to opisano tutaj - http://knockoutjs.com/documentation/template-binding.html

_.templateSettings = { 
    interpolate: /\{\{\=(.+?)\}\}/g, 
    evaluate: /\{\{(.+?)\}\}/g 
}; 

/* ---- Begin integration of Underscore template engine with Knockout. Could go in a separate file of course. ---- */ 
    ko.underscoreTemplateEngine = function() { } 
    ko.underscoreTemplateEngine.prototype = ko.utils.extend(new ko.templateEngine(), { 
     renderTemplateSource: function (templateSource, bindingContext, options) { 
      // Precompile and cache the templates for efficiency 
      var precompiled = templateSource['data']('precompiled'); 
      if (!precompiled) { 
       precompiled = _.template("{{ with($data) { }} " + templateSource.text() + " {{ } }}"); 
       templateSource['data']('precompiled', precompiled); 
      } 
      // Run the template and parse its output into an array of DOM elements 
      var renderedMarkup = precompiled(bindingContext).replace(/\s+/g, " "); 
      return ko.utils.parseHtmlFragment(renderedMarkup); 
     }, 
     createJavaScriptEvaluatorBlock: function(script) { 
      return "{{ " + script + " }}"; 
     } 
    }); 
    ko.setTemplateEngine(new ko.underscoreTemplateEngine()); 
/* ---- End integration of Underscore template engine with Knockout ---- */ 

var viewModel = { 
    model: ko.observableArray([ 
     { Value: '1', IsChecked: 1 }, 
     { Value: '2', IsChecked: 0 }, 
     { Value: '3', IsChecked: 1 }, 
     { Value: '4', IsChecked: 0 }, 
     { Value: '5', IsChecked: 1 }, 
    ])   
}; 

ko.applyBindings(viewModel); 

P.S .: ale Bett er avoid using tables for html layout. Twój przykład można wyrenderować za pomocą elementów wbudowanego bloku o znacznie czystszym kodzie.

+0

+1 w przypadku szablonów DOM i tekstowych, ale nie chcę używać innego silnika szablonów. – 0lukasz0