2016-06-24 15 views
7

Używam Angular 2-rc3 i mam Component i chcę zastosować transclusion, tylko w nieco inny sposób. Oto mój komponent:Komponent transclude with inline template

import { Component, Input } from '@angular/core'; 

@Component({ 
    selector: 'my-list', 
    template: `<ul> 
     <li *ngFor="let item of data"> 
      -- insert template here -- 
      <ng-content></ng-content> 
     </li> 
    </ul>` 
}) 
export class MyListComponent { 
    @Input() data: any[]; 
} 

i używam go tak:

<my-list [data]="cars"> 
    <div>{{item.make | uppercase}}</div> 
</my-list> 

Jak widać, próbuję zdefiniować szablon inline, który będzie używany przez mojego składnika. Teraz to idzie strasznie źle. Po pierwsze, wyjątek dotyczący wiązania danych, który mówi: can't read property 'make' of undefined. Próbuje odczytać item.make z mojego otoczenia, a nie z MyListComponent. Ale nawet jeśli tymczasowo wyłączyć to teraz:

<my-list [data]="cars"> 
    <div>{item.make | uppercase}</div> 
</my-list> 

Potem pojawia się drugi problem:

-- insert template here -- 
-- insert template here -- 
-- insert template here -- 
-- insert template here -- 
{item.make | uppercase} 

Więc kątowa faktycznie nie skopiować szablon do użytku w *ngFor, to po prostu wiąże elementy i kojarzą się z ostatnim elementem.

Jak to działa?

Miałem ten sam problem z AngularJS, gdzie petebacondarwin posted a solution to manipulate the DOM through compile, który był świetny. Mam tę opcję również w Angular 2, wstrzykując ElementRef w moim komponencie, ale! Jedną z dużych różnic jest to, że compile w AngularJS zakończyło się przed databindingiem, co oznacza, że ​​nie było problemów z użyciem szablonu w szablonie {{item.make}}. W przypadku Angular 2 wygląda na to, że nie można przejść od razu, ponieważ {{item}} jest analizowany wcześniej. Więc jaki jest najlepszy sposób, aby to osiągnąć? Używanie nieco innej notacji [[item]] i ciąg zastępujący całą rzecz nie wydaje się najbardziej eleganckim sposobem ...

Z góry dziękuję!

// Edytuj: Oto Plnkr, który odtwarza problem.

+0

Byłoby wspaniale mieć Plunkera, który pozwala na odtworzenie, gdzie wszystko jest na miejscu, w jaki sposób chcesz z niego korzystać. Ciężko mi, na przykład, dowiedzieć się, co znaczy "wstawić szablon tutaj". –

+0

Dodano! Dzięki. –

+0

@JPtenBerge Miałem podobny problem i [znalazłem rozwiązanie] (http://stackoverflow.com/questions/38174837/how-to-create-a-component-witha-a-dynamic-template-component-transclude- z in-in) – Ross

Odpowiedz

1
  • <ng-content> wewnątrz *ngFor nie działa, dlatego

    <li *ngFor="let item of data"> 
        -- insert template here -- 
        <ng-content></ng-content> 
    </li> 
    

niczego sensownego nie zrobi. Wszystko zostanie przeniesione do pierwszego, aby rozwiązać niektóre z Twoich wymagań.

+1

Problem z GitHub opisuje dokładnie to, czego potrzebuję, ale jest obecnie w stanie "Needs Design" bez kamienia milowego, więc nie oferuje mi zbyt wiele. Pierwszy link wydaje mi się dokładnie tym, czego potrzebuję, ale działa z już przestarzałą wersją Angular (beta 8): odwołanie do 'TemplateRef' i wywołanie' setLocal() 'już nie działają. To rozwiązanie wydaje się obiecujące i zauważyłem twój komentarz na temat 'setLocal()', z którym zamierzam się jeszcze trochę pobawić. –

4

do wyjaśnienia sposobu ngForTemplate (. Ponieważ kątowa 4 element obecnie nazywa się <ng-template>)

  1. Użyj <template> znacznika w obydwu zewnętrznych i wewnętrznych elementów składowych zamiast <ng-content>.

  2. <li> przesuwa się html app.component i <template> tego składnika ma szczególne „let-” cechy, która odwołuje się do zmiennej powtórzyć w wewnętrznej części:

    <my-list [data]="cars"> 
        <template let-item> 
        <li> 
         <div>{{item.make | uppercase}}</div> 
        </li> 
        </template> 
    </my-list> 
    
  3. element wewnętrzny ma <template> jak i wykorzystuje wariant ngFor tak:

    <ul> 
        <template #items ngFor [ngForOf]="data" [ngForTemplate]="tmpl"> 
         -- insert template here -- 
        </template> 
    </ul> 
    
  4. 'Tmpl' zmiennej przypisane do atrybutu ngForTemplate musi być pobrana w kodzie składnika:

    export class MyListComponent { 
        @Input() data: any[]; 
        @ContentChild(TemplateRef) tmpl: TemplateRef; 
    } 
    
  5. @ContentChild i TemplateRef kątowe są bity, więc muszą być importowane

    import { Component, Input, ContentChild, TemplateRef } from '@angular/core'; 
    

Patrz widelec twojego plunkra z tymi zmianami tutaj plnkr.

To nie jest najbardziej satysfakcjonujące rozwiązanie dla zadeklarowanego problemu, ponieważ przekazujesz dane na listę, możesz równie dobrze mieć ngFor na zewnątrz. Dodatkowo, dodatkowa zawartość (literał "- wstaw tutaj szablon -") zostaje usunięta, więc chciałeś pokazać, że musi to być również na zewnętrznym szablonie.

Widzę, że może się przydać, gdy iteracja jest zapewniona w wewnętrznym komponencie (powiedzmy od zgłoszenia serwisowego), i być może zrobić trochę manipulacji szablonem w kodzie.

+0

dziękuję bardzo za tę odpowiedź i plunkr. Chociaż wydaje się, że działa, w moim przypadku, gdy mam listę dynamiczną, nic nie jest wyrenderowane na liście. Chociaż jeśli sprawdzę DOM, widzę, że istnieją powiązania szablonów. Masz pojęcie, co się dzieje? – sohel101091

+0

Nie jestem pewien scenariusza - mogę dodawać samochody do listy na runtine za pomocą przycisku i kliknij moduł obsługi zdarzeń, a one pojawią się na liście. –

+0

Spędziłem wiele godzin w sierpniu, aby znaleźć rozwiązanie. Ta odpowiedź jest bardzo pomocna. Po prostu działa.Wielkie dzięki!!! – Vil