2012-12-17 2 views
5

Mi piacerebbe rendere dinamicamente righe e colonne usando knockout. L'idea è che mi piacerebbe popolare ogni riga con alcune celle e aggiungere dinamicamente più righe se necessario. lascia supporre che il numero totall di cellule è uguale il numero 4 * di righe, poi ho provato:Come renderizzare tr condizionalmente in knockout.js foreach binding

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

ma funziona come se fosse:

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

da non rendendo tutta la fila con i contenuti, è possibile con knockout per rendere tutte le celle e aggiungere righe solo quando necessario?

Per risolvere il problema, penso a foreach annidato, ma richiederebbe che il mio modello passasse da una dimensione monodimensionale a una bidimensionale che sembra strana.

+2

Sei sicuro che si desidera utilizzare una tabella HTML per questo? Se disponi di un elenco di elementi come i tuoi dati, non puoi semplicemente renderli come div e usare i CSS per farli scorrere naturalmente all'interno di un contenitore, 4 in tutto? –

+0

Sì, sono i dati tabulari e le tabelle sono per la visualizzazione di dati tabulari utilizzando div sarebbe soluzione alternativa non una soluzione – 0lukasz0

risposta

14

Aggiungi un'altra proprietà computerizzata che le strutture i dati in righe:

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

con il codice:

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 cool ... salvati giorno – dreamerkumar

+0

Proprio quello che stavo cercando, grazie ... – ShaneBlake

3

La sintassi non funzionerà con il motore di template predefinito knockout solo perché utilizza DOM. Se devi fare ciò, usa un motore di template esterno basato su stringhe (tratterà il template come stringa e userà regex e manipolazioni di stringhe, così sarai in grado di fare questo trucco con il rendering condizionale del tag start/end). Il vostro esempio utilizzando JS sottolineatura:

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 (questo include sottolineare l'integrazione di misura descritto qui - 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 .: ma Bett er avoid using tables for html layout. Il tuo esempio può essere reso utilizzando gli elementi di blocco in linea con un codice molto più pulito.

+0

+1 per DOM vs modelli di testo, ma non voglio usare un altro motore di template – 0lukasz0