Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

typescript - Angular 2 Dynamically insert a component into a specific DOM node without using ViewContainerRef

I have a question regarding dynamic component creation in Angular 2 rc5.

So let's assume that we have two plain angular components:

  @Component({
      template: `
        <div id="container">
          <h1>My Component</h1>
        </div>
       `,
      selector: 'my-app'
  })
  export class AppComponent { }

  @Component({
      template: '<p>{{text}}</p>',
      selector: 'simple-cmp'
  })
  export class SimpleComponent { public text='Hello World!' }

Then some external non-angular chunck of code modificates a DOM:

let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);

Here is some presumable tree after manipulations:

 <div id="container">
      <h1>My Component</h1>
      <div id="placeholder"></div>
 </div>

So what I'm trying to do is just dynamically add SimpleComoponent instance into #placeholder div. How can I achieve this result?

I've been trying using ComponentFactory.createComponent(injector, [], newNode), it added the component though, but neither life cycle hooks nor binding not worked at all.

I believe there is some way to implement this using ViewContainerRef, but how can I link it with dynamically created node?

Here is the result I expect

 <div id="container">
      <h1>My Component</h1>
      <div id="placeholder">
        <simple-cmp>Hello world!</simple-cmp>
      </div>
 </div>

Thanks!

See Question&Answers more detail:os

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

1 Answer

0 votes
by (71.8m points)

When creating a component you can pass the DOM node that will act as a host element of the created component:

create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any, ngModule?: NgModuleRef): ComponentRef

But since this component is not child of any other component, you have to manually attach it to ApplicationRef so you get change detection.

So here is what you need to do:

1) Create a component specifying the root node under which it should be added.
2) Attach the view to the ApplicationRef so that you get change detection. You will still have no Input and ngOnChanges operations, but the DOM update will be working fine.

  @Component({
      template: `
        <div id="container">
          <h1>My Component</h1>
        </div>
       `,
      selector: 'my-app'
  })
  export class AppComponent { 
      constructor(private resolver: ComponentFactoryResolver,
                  private injector: Injector,
                  private app: ApplicationRef) { 

      }

      addDynamicComponent() {
         let factory = this.resolver.resolveComponentFactory(SimpleComponent);

         let newNode = document.createElement('div');
         newNode.id = 'placeholder';
         document.getElementById('container').appendChild(newNode);

         const ref = factory.create(this.injector, [], newNode);
         this.app.attachView(ref.hostView);
      }
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...