2016-07-27 3 views
4

То, что я пытаюсь достичь, - это общий компонент, связанный с массивом произвольных объектов, который позволяет динамически добавлять и удалять строки, когда представление каждой строки также произвольно определяемый компонентами с помощью основного компонента, который его использует.Создание динамического ретранслятора с переходом содержимого ng с помощью Angular2

Отметьте, что MasterComponent - это произвольный компонент, который будет реализован для разных страниц и предназначен для автономного использования и не определяется никакими метаданными или внешним источником.

То, что я до сих пор являются следующие компоненты:

шаблон RepeaterComponent:

<input type="button" value="Add" (click)="addRow()"> 
<div class="repeater" *ngFor="let row of repeaterArray"> 
    <div class="repeaterRow"> 
     <input type="button" value="Remove" (click)="removeRow(row.rowId)"> 
     <ng-content select="row"></ng-content> 
    </div> 
</div> 

шаблон MasterComponent:

<repeater [repeaterArray]="repeaterObj"> 
    <row> 
     <field-textbox [data]="row.name" [label]="'Name'"></field-textbox> 
     <field-textbox [data]="row.description" [label]="'Description'"></field-textbox> 
    </row> 
</repeater> 

<field-textbox> компонент представляет собой пользовательский компонент, который Я использую для инкапсуляции простых входов который содержит некоторые дополнительные данные, которые мне нужно использовать.

MasterComponent содержит объект, который для этого экземпляра выглядит следующим образом:

repeaterObj = [ 
{ 
    "rowId": 1, 
    "name": "First brand", 
    "description": "First description" 
}, 
{ 
    "rowId": 2, 
    "name": "Second brand", 
    "description": "Second description" 
}, 
{ 
    "rowId": 3, 
    "name": "Third brand", 
    "description": "Third description" 
} 
]; 

Этот подход имеет два вопроса, которые я не могу показаться, чтобы найти решение.

  1. НГ-контент селектор одинаков для всех строк, когда ngFor дублирует шаблон, который оставляет меня только с одной точкой ng-content включения после рендеринга.
  2. Ссылка на строку не указана в объявлении ngFor в директивах, передаваемых в <field-textbox>, поэтому я не могу привязать данные правильно.

Есть ли лучший подход к реализации RepeaterComponent, который дал бы мне наименьшее количество усилий, чтобы создать больше новых MasterComponents различных произвольных структур и различных шаблонов?

ответ

7

Для достижения этой цели вы можете использовать ngTemplateOutlet.

Ниже приведены шаги в реализации динамического ретранслятор:

Первый шаг является создание TemplateRef в качестве дочернего элемента RepeaterComponent:

<repeater [repeaterArray]="repeaterObj"> 
    <ng-template> 
    ... 
    </ng-template> 
</repeater> 

Второй шаг является запрос этот шаблон в пределах RepeaterComponent через ContentChild:

export class RepeaterComponent { 
    @ContentChild(TemplateRef) itemTemplate: TemplateRef<any>; 
    ... 

Третий шаг является использование ngTemplateOutlet, чтобы сделать его шаблон:

@Component({ 
    selector: 'repeater', 
    template: ` 
    <input type="button" value="Add" (click)="addRow()"> 
    <div class="repeater" *ngFor="let row of repeaterArray"> 
     <div class="repeaterRow"> 
      <input type="button" value="Remove" (click)="removeRow(row.rowId)"> 
      <ng-template <== this line 
        [ngTemplateOutlet]="itemTemplate" 
        [ngTemplateOutletContext]="{ $implicit: row }"> 
       </ng-template> 
     </div> 
    </div>` 
}) 
export class RepeaterComponent { 
    @Input() repeaterArray: Array<any>; 
    @ContentChild(TemplateRef) itemTemplate: TemplateRef<any>; 
    ... 
} 

Четвертый шаг заключается в использовании ссылки на ряд внутри TemplateRef в MasterComponent (только обратно на наш первый шаг):

<repeater [repeaterArray]="repeaterObj"> 
    <template let-row> 
    <field-textbox [data]="row.name" [label]="'Name'"></field-textbox> 
    <field-textbox [data]="row.description" [label]="'Description'"></field-textbox> 
    </template> 
</repeater> 

Примечание: мы передаем объект ngOutletContext как объект с $implicit.

используя ключ $, неявный в контексте объекта, будет устанавливать его значение как по умолчанию.

Он работает следующим образом:

[ngTemplateOutletContext]="{ $implicit: row }" ==> <template let-row> 

[ngTemplateOutletContext]="{ item: row }"  ==> <template let-row="item"> 

ngOutletContext является availlable только с angular2 версия 2.0.0-РК-2

Вы можете попробовать соответствующий plunkr (обновлена ​​5.0 .0)

+0

Похоже, это именно то, что я искал, спасибо! Единственная вещь, которая, кажется, работает не так, как ожидалось, является двусторонней привязкой к компоненту field-textbox с [(ngModel)]. Следующий [Plunker] (https://plnkr.co/edit/59vALT3ugZX1jIsMSOn6?p=preview) демонстрирует проблему, когда вы пытаетесь изменить два разных поля ввода с тем же связыванием. В шаблоне компонента приложения вы можете видеть, что обычная '' привязка работает по назначению, а также обновляет объект, но изменение текстового поля не применяет привязку к объекту. – VRuter

+0

Попробуйте использовать «EventEmitter» для достижения двусторонней привязки, например https://plnkr.co/edit/XpEDWD75bfnEtibKDKW7?p=preview – yurzui

+0

Да, это работает. Я ожидал бы, что привязка будет корректно распространяться без необходимости выполнять двустороннюю привязку в компоненте , но видя, что привязка работает при использовании за пределами шаблона с помощью [ngTemplateOutlet]. – VRuter

Смежные вопросы