在Angular 6上使用其他容器组件向body添加组件(Add component to body with other container component on Angular 6)

我已经创建了接受组件的服务,将该组件添加到我的组件并将它们添加到<body> 。 问题是当我在我的组件中有ng-content来放置传入的组件时,它只是将它添加到ng-content之下,就像appendChild一样。

./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    domElem.appendChild(contentElem);
    // Append DOM element to the body
    document.body.appendChild(domElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <ng-content>
      </ng-content>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
 

如果我们提供图片组件,那个服务电话的结果将在正文中:

<modal>
   <div></div>
   <app-picture _nghost-c2="">
     <p _ngcontent-c2=""> picture works!</p>
   </app-picture>
</modal>
 

期待身体:

<modal>
   <div>
     <app-picture _nghost-c2="">
        <p _ngcontent-c2=""> picture works!</p>
     </app-picture>
   </div>
</modal>

I have made service which accept component, adding that component to my component and adding them to <body>. Problem is while I have ng-content in my component to place the incoming component, it simply adding it below the ng-content as simply appendChild do.

./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    domElem.appendChild(contentElem);
    // Append DOM element to the body
    document.body.appendChild(domElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <ng-content>
      </ng-content>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
 

result of that service call will be in body if we provide picture component:

<modal>
   <div></div>
   <app-picture _nghost-c2="">
     <p _ngcontent-c2=""> picture works!</p>
   </app-picture>
</modal>
 

expectation in body:

<modal>
   <div>
     <app-picture _nghost-c2="">
        <p _ngcontent-c2=""> picture works!</p>
     </app-picture>
   </div>
</modal>

                

最满意答案

作为解决方案,您可以通过将传入的DOM放入模态DOM内的特定标记来执行javascript解决方案。 ./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Append DOM element to the body
    document.body.appendChild(domElem);
    // Add incoming component to modal component
    domElem.querySelector('#Modal').appendChild(contentElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <div id="Modal"></div>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}

As solution you can do javascript solution, by putting incoming DOM into specific tag inside modal DOM. ./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Append DOM element to the body
    document.body.appendChild(domElem);
    // Add incoming component to modal component
    domElem.querySelector('#Modal').appendChild(contentElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <div id="Modal"></div>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}在Angular 6上使用其他容器组件向body添加组件(Add component to body with other container component on Angular 6)

                

我已经创建了接受组件的服务,将该组件添加到我的组件并将它们添加到<body> 。 问题是当我在我的组件中有ng-content来放置传入的组件时,它只是将它添加到ng-content之下,就像appendChild一样。

./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    domElem.appendChild(contentElem);
    // Append DOM element to the body
    document.body.appendChild(domElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <ng-content>
      </ng-content>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
 

如果我们提供图片组件,那个服务电话的结果将在正文中:

<modal>
   <div></div>
   <app-picture _nghost-c2="">
     <p _ngcontent-c2=""> picture works!</p>
   </app-picture>
</modal>
 

期待身体:

<modal>
   <div>
     <app-picture _nghost-c2="">
        <p _ngcontent-c2=""> picture works!</p>
     </app-picture>
   </div>
</modal>

I have made service which accept component, adding that component to my component and adding them to <body>. Problem is while I have ng-content in my component to place the incoming component, it simply adding it below the ng-content as simply appendChild do.

./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    domElem.appendChild(contentElem);
    // Append DOM element to the body
    document.body.appendChild(domElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <ng-content>
      </ng-content>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
 

result of that service call will be in body if we provide picture component:

<modal>
   <div></div>
   <app-picture _nghost-c2="">
     <p _ngcontent-c2=""> picture works!</p>
   </app-picture>
</modal>
 

expectation in body:

<modal>
   <div>
     <app-picture _nghost-c2="">
        <p _ngcontent-c2=""> picture works!</p>
     </app-picture>
   </div>
</modal>

                

最满意答案

作为解决方案,您可以通过将传入的DOM放入模态DOM内的特定标记来执行javascript解决方案。 ./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Append DOM element to the body
    document.body.appendChild(domElem);
    // Add incoming component to modal component
    domElem.querySelector('#Modal').appendChild(contentElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <div id="Modal"></div>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}

As solution you can do javascript solution, by putting incoming DOM into specific tag inside modal DOM. ./service.ts

import {
    Injectable,
    Injector,
    ComponentFactoryResolver,
    EmbeddedViewRef,
    ApplicationRef,
    ComponentRef
} from '@angular/core';
import { ModalComponent } from './modal.component';
@Injectable({
  providedIn: 'root'
})
export class ModalService {
  constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }
  appendComponentToBody(component: any) {
    // Create a component reference from the incoming component 
    let componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);
    // Attach incoming component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRef.hostView);
    // Get DOM element from incoming component
    let contentElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Create a component reference from the service component 
    let componentRefer = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);
    // Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(componentRefer.hostView);
    // Get DOM element from service component
    let domElem = (componentRefer.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;
    // Append DOM element to the body
    document.body.appendChild(domElem);
    // Add incoming component to modal component
    domElem.querySelector('#Modal').appendChild(contentElem);
  }
}
 

./modal.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'modal',
  template: `
    <div>
      <div id="Modal"></div>
    </div>    
  `,
  styles: []
})
export class ModalComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}