5

C'è un modo per configurare un Knockout component a sostituire l'elemento contenitore invece di nidificare il suo contenuto all'interno dell'elemento contenitore?Sostituisci elemento contenitore quando si utilizza il componente Knockout

Per esempio, se ho un componente personalizzato registrato come my-custom-element con la seguente configurazione:

<tr> 
    <p>Hello world!</p> 
</tr> 

E 'possibile utilizzare il componente come questo:

<table> 
    <tbody> 
     <my-custom-element></my-custom-element> 
    </tbody> 
</table> 

E avere il prodotto finale essere questo:

<table> 
    <tbody> 
     <tr> 
      <p>Hello world!</p> 
     </tr> 
    </tbody> 
</table> 

Invece di questo: (il modo Knockout r Enders componenti per impostazione predefinita)

<table> 
    <tbody> 
     <my-custom-element> 
      <tr> 
       <p>Hello world!</p> 
      </tr> 
     </my-custom-element> 
    </tbody> 
</table> 

Based on the answer to this question, sembra che questa funzionalità è incorporata nel motore di template, che sto assumendo è utilizzato anche durante il rendering dei modelli di componenti.

C'è un modo per specificare che un componente debba essere reso con uno di replaceNode?

Sono consapevole della sintassi "elemento virtuale", che consente ai componenti di essere definite all'interno di un commento HTML:

<table> 
    <tbody> 
     <!--ko component { name: 'my-custom-element' }--><!--/ko--> 
    </tbody> 
</table> 

ma mi piace questa sintassi - la scrittura di codice vero e proprio all'interno di un commento si sente come un hack sporco, sporco.

+1

Sembra [rendering di un modello definito] (http://knockoutjs.com/documentation/template-binding.html) è quello che state cercando. Il componente Web è, in generale, un nodo DOM, che ombreggia i suoi figli. Non è inteso per essere sostituito, dal momento che il concetto stesso è rovinato in questo caso. – mudasobwa

risposta

4

immagino la mancanza di questa opzione potrebbe essere difeso come tale, in considerazione della natura della biblioteca (lì, l'ho detto), e la filosofia della squadra dello sviluppatore:

Knockout è una libreria ed a differenza di altri che di MVC non ti obbliga a usare un modo definito dal framework per strutturare la tua applicazione. Se consideri il motore di template in Knockout rispetto a praticamente tutti gli altri motori di template JS (in Angular, underscore, baffi, ecc.), Knockout esce come l'unico non modificando il rendering nativo HTML5. Tutti gli altri usano un tag personalizzato, sia esso <% %> o {{ }} che richiede un parser JS piccolo per trasformare i tag in qualcosa di significativo (ora KO ha anche un plugin Knockout punches che include i tag stile baffi, e ammetto che KO fa 'peccato' a piccolo bit con i commenti <!-- ko -->). KO utilizza invece elementi personalizzati HTML 5, tag commento e attributo, completamente "vanilla".

Per esempio, il tipo JS/DOM di 'oggetto (e vita reale?) Gerarchia' viene utilizzato: solo i genitori possono mai aumentare la potenza sui loro figli, e quindi l'elemento bound-to non viene sostituito, ma ingrandito con bambini.Per illustrazione:

// we cannot do this in JS 
document.getElementById('elem').remove(); //implied .remove(self) 
// instead we do this 
var elem = document.getElementById('elem'); 
container = elem.parentNode.removeChild(elem); 

Successivamente, il modo preferito di associazione dati con KO, illustrata bene dalla foreach vincolante, è:

<div data-bind="foreach: myList"> 
    <span data-bind="text: $data"></span> 
</div> 

Il frammento precedente essendo una rappresentazione HTML di un JS array, la gerarchia è di nuovo visibile:

var myArr = [1,2,3,4,5]; 
// we cannot do the following without reference to the array index, 
// which is not held by the object itself,  
// but a meta-property getting meaning relative to the parent 
myArr[0].splice(0,1); //remove 

Questo porta alla visualizzazione HTML che è un ct replica dei tuoi dati JS (e sarebbe interessante vedere qualcuno costruire uno strumento che mostra i livelli di indentazione di data-binding (con with e foreach) in un documento HTML. In alcuni casi, tuttavia, sono necessari tag di commento, in modo da non interrompere il layout del codice HTML o le regole CSS (annidamento), ad esempio un componente "solo testo" (i18n) che deve essere inserito tra il testo nodi:

<p>Some predefined text with 
<!-- ko text: 'some variable text' --><!-- /ko --> 
and more predefined text</p> 

O quando non si vuole un elemento vuoto per prendere spazio quando nascosto

<!-- ko if: !hidden() --><div id="myToggleableDiv"></div><!-- /ko --> 

e poi ci sono custom tags, che sono standardizzati e un inferno di molto più chiara ; ma sfortunatamente non è ancora pronto al 100%. Scegliere prima data-bind, <!-- ko --> secondo e <custom> terzo (sarebbe più alto se completamente implementato). È così che lo vedo, comunque. Per quanto riguarda il tuo caso specifico, se il componente in possesso di un modello di lista, si potrebbe fare:

<table data-bind="{component: {name: 'custom', params {..}}"></table> 

e comprendono il tbody nel vostro VM, altrimenti se si tratta di un modello di listitem, è possibile utilizzare uno dei tre ' sintassi, ad esempio, il commento di sintassi

<table> 
    <tbody data-bind="foreach: mylist"> 
    <!-- ko component: {name: 'custom', params: $data} --><!-- /ko --> 
    </tbody> 
</table> 

O disaccoppiare il componente completamente dal requisito di essere nidificato all'interno di un genitore specifico (tabella), aderendo alla SOC principle, ad esempio:

<table> 
    <tbody data-bind="foreach: mylist"> 
    <tr data-bind="foreach: properties"> 
     <td data-bind="component: {name: 'custom', params: $data}></td> 
    </tr> 
    </tbody> 
</table> 

o con un tag personalizzato:

<table> 
    <tbody data-bind="foreach: mylist"> 
    <tr data-bind="foreach: properties"> 
     <td><custom params= "{data: myData"></custom></td> 
    </tr> 
    </tbody> 
</table> 

in questo ordine di preferenza ..

2

Good News! In Knockout 3.3.0 è stato appena introdotto il concetto di Passing markup into components. Questo viene fatto utilizzando il modello $componentTemplateNodes all'interno del componente.

Dall'esempio collegato:

<template id="my-special-list-template"> 
    <h3>Here is a special list</h3> 

    <ul data-bind="foreach: { data: myItems, as: 'myItem' }"> 
     <li> 
      <h4>Here is another one of my special items</h4> 
      <!-- ko template: { nodes: $componentTemplateNodes, data: myItem } --><!-- /ko --> 
     </li> 
    </ul> 
</template> 

<my-special-list params="items: someArrayOfPeople"> 
    <!-- Look, I'm putting markup inside a custom element --> 
    The person <em data-bind="text: name"></em> 
    is <em data-bind="text: age"></em> years old. 
</my-special-list> 
Problemi correlati