Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
672 views
in Technique[技术] by (71.8m points)

angular - Angular2: Insert a dynamic component as child of a container in the DOM

Is there a way to insert dynamically a component as a child (not a sibling) of a DOM tag in Angular 2?

There are plenty of examples around there to insert a dynamic component as a sibling of a given ViewContainerRef's tag, like (as of RC3):

@Component({
  selector: '...',
  template: '<div #placeholder></div>'
})
export class SomeComponent {
  @ViewChild('placeholder', {read: ViewContainerRef}) placeholder;

  constructor(private componentResolver: ComponentResolver) {}

  ngAfterViewInit() {
    this.componentResolver.resolveComponent(MyDynamicComponent).then((factory) => {
        this.componentRef = this.placeholder.createComponent(factory);
    });
  }
}

But this generates a DOM similar to:

<div></div>
<my-dynamic-component></my-dynamic-component>

Expected result:

<div>
    <my-dynamic-component></my-dynamic-component>
</div>

Using the SomeComponent's ViewContainerRef has the same result, it is still inserting the generated component as a sibling, not a child. I would be okay with a solution where the template is empty and dynamic components are inserted in the template (within the component selector tag).

The DOM structure is very important when using libraries like ng2-dragula to drag from a list of dynamic components and benefit from the model updates. The extra div is in the list of draggable elements, but outside the model, breaking the drag & drop logic.

Some say it is not possible (c.f. this comment), but it sounds like a very surprising limitation.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

TL;DR: replace <div #placeholder></div> with <div><ng-template #placeholder></ng-template></div> to insert inside the div.

Here is a working stackblitz example (Angular 6), and the relevant code:

@Component({
  selector: 'my-app',
  template: `<div><ng-template #container></ng-template></div>`
})
export class AppComponent implements OnInit {

    @ViewChild('container', {read: ViewContainerRef}) viewContainer: ViewContainerRef;

    constructor(private compiler: Compiler) {}

    ngOnInit() {
      this.createComponentFactory(MyDynamicComponent).then(
        (factory: ComponentFactory<MyDynamicComponent>) => this.viewContainer.createComponent(factory),
        (err: any) => console.error(err));
    }

    private createComponentFactory(/*...*/) {/*...*/}

}

It seems <ng-container #placeholder></ng-container> is also working (replace ng-template by ng-container). I like this approach because <ng-container> is clearly addressed to this usecase (a container that don't add a tag) and can be used in other situations like NgIf without wrapping in a real tag.


PS: @GünterZ?chbauer directed me to the right discussion in a comment, and I finally answered my own question.


Edit [2018-05-30]: Updated to stackblitz link to have a working, up-to-date example.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...