Как динамически добавить клонированный узел в angular2 (эквивалент cloneNode)

В Angular2 в некоторых случаях мне нужно дублировать узел, а не перемещать его. Этот узел имеет свойства angular2, поэтому cloneNode не работает. Как мне это сделать?

*что не работает

    let el = <HTMLElement>document.getElementById(divId);
    if ((<HTMLElement>el.parentNode).id == 'itsMe')
        el = <HTMLElement>el.cloneNode(true);
    document.getElementById(anotherId).appendChild(el);

* что будет работать, из Angular2: компонент клонирования/элемент HTML и это функциональность

@Component({
  selector: 'my-app',
  template: `
    <template #temp>
        <h1 [ngStyle]="{background: 'green'}">Test</h1>
        <p *ngIf="bla">Im not visible</p>   
    </template>
    <template [ngTemplateOutlet]="temp"></template>
    <template [ngTemplateOutlet]="temp"></template>
    `
})

export class AppComponent {
    bla: boolean = false;
    @ContentChild('temp') testEl: any;
} 

Но как добавить шаблон динамически?


person GWorking    schedule 29.01.2017    source источник
comment
Вы пытались использовать ngFor?   -  person yurzui    schedule 29.01.2017
comment
Зачем? Я хочу сделать это динамически   -  person GWorking    schedule 29.01.2017


Ответы (1)


Для иллюстрации воспользуемся следующей разметкой:

<p>Paragraph One</p>
<p>Paragraph Two</p>   <!-- Let's try to clone this guy -->
<p>Paragraph Three</p>

Вариант 1. Вручную оберните элемент для клонирования внутри тега <template>

Это в основном то, что вы сделали, только вместо того, чтобы распечатать шаблон с помощью ngTemplateOutlet, возьмите ссылку на него в классе вашего компонента и обязательно вставьте ее с помощью createEmbeddedView().

@Component({
    selector: 'my-app',
    template: `
      <p>Paragraph One</p>
      <template #clone>
        <p>Paragraph Two</p>
      </template>
      <p>Paragraph Three</p>

      <button (click)="cloneTemplate()">Clone Template</button>

      <div #container></div>
    `
})
export class AppComponent{
    // What to clone
    @ViewChild('clone') template;

    // Where to insert the cloned content
    @ViewChild('container', {read:ViewContainerRef}) container;

    constructor(private resolver:ComponentFactoryResolver){}

    cloneTemplate(){
        this.container.createEmbeddedView(this.template);
    }
}

В этом примере я вставляю «клон» в определенное место разметки (<div #container></div>), но вы также можете добавить его внизу шаблона текущего компонента.

Также обратите внимание, что исходный <p>Paragraph Two</p> больше не виден.

Вариант 2. Используйте структурную директиву

Если вы хотите клонировать элемент в его текущем местоположении, в результате получится:

<p>Paragraph One</p>
<p>Paragraph Two</p>   <!-- Original paragraph -->
<p>Paragraph Two</p>   <!-- Cloned paragraph   -->
<p>Paragraph Three</p>

Затем вы можете создать структурную директиву *clone и применить ее к абзацу для клонирования, например:

<p>Paragraph One</p>
<p *clone>Paragraph Two</p>
<p>Paragraph Three</p>

Интересно, что структурная директива заключает элемент, к которому она применяется, внутрь тега <template>. Очень похоже на то, что мы сделали в варианте 1, только в этом случае у нас НЕТ КОНТРОЛЯ над местом, где распечатываются клоны (они появятся там, где был исходный абзац).

Это, по сути, будет повторять поведение *ngFor, так что, вероятно, это не очень полезно. Кроме того, из вашего комментария к yurzui следует, что это не то, что вы хотите.

person AngularChef    schedule 29.01.2017
comment
Я пробую вариант 1, я бы сказал, что у вас ошибка в @ViewChild('template'), должно быть 'clone' (по крайней мере, это работает для меня). Есть ли способ динамически определить, куда вводить клонированный шаблон? типа document.getElementById.createEmbeddedView? - person GWorking; 06.02.2017
comment
@ Джерард. Ну, вам нужна точка привязки, чтобы вставить клонированный шаблон. Насколько мне известно, в декораторе @ViewChild(selector) selector может быть либо директивой/компонентом, либо переменной шаблона, как в моем примере. В документации неясно, можно ли использовать другие типы селекторов. Возможно, попробуйте селектор класса, например. @ViewChild('.active') или @ViewChild('[active]'). - person AngularChef; 06.02.2017
comment
Хорошо, и важно то, что теперь это работает, а до вас это было совершенно непонятно. Тысяча благодарностей! :) - person GWorking; 07.02.2017
comment
Рад, что смог помочь. :) - person AngularChef; 07.02.2017
comment
(Я задал вопрос на основе вашего решения о том, как передать переменную в клонированный шаблон, все еще пытаясь) stackoverflow.com/questions/42057886 / - person GWorking; 07.02.2017