kittencup / angular2-ama-cn

angular2 随便问
692 stars 101 forks source link

如何在service中获得根组件的viewContainerRef #183

Open keyiis opened 8 years ago

keyiis commented 8 years ago

起因这样的,我想用service实现一个模态框(基于bootstrap modal),在任何一个组件中都可以通过调用这个service去弹出或隐藏模态框,那么就需要在service中将modal.component动态加载到根组件下一级,当模态框被关闭时这个组件自动销毁,在下次需要时再动态加载进来,我使用的是resolveComponent,但每次这个模态框都被加载到body标签下,也就是说和根组件平级,不知道问题出在哪,下面是相关的一些代码,懂行的指点一下,先谢过了! 1、在根组件中获得ViewContainerRef便于sevice中引用到

export class AppComponent { 
   //可在子组件中获得ViewContainerRef
   private viewContainerRef:ViewContainerRef;
   public constructor(viewContainerRef:ViewContainerRef) {
    this.viewContainerRef = viewContainerRef;
  }
}

2、在需要调用模态框的组件中调用modal.service

@Component({
  selector: 'routea',
  template: require('./a.component.html'),
  styles: [`......`],
  providers: [ModalService]
})
export class AComponent{
  constructor(private modalService: ModalService,private appService: AppService) {
  }
  show(){
    this.modalService.show();
  }
}

3、modal.service中动态加载模态框组件

import { Injectable,ApplicationRef, ViewContainerRef, ComponentResolver,Injector } from '@angular/core';
import {ModalComponent} from './modal.component'
@Injectable()
export class ModalService {
  private viewContainerRef:ViewContainerRef;
    constructor(applicationRef: ApplicationRef, injector: Injector,private compiler: ComponentResolver) { 
        var classOfRootComponent = applicationRef.componentTypes[0];
        console.log(applicationRef.componentTypes);
        // 获得根组件也就是main.ts中bootstrap启动的组件
        var appInstance = injector.get(classOfRootComponent);
        // 获得根组件中手工设置的viewContainerRef属性
        this.viewContainerRef= appInstance.viewContainerRef;
    }
    show() {
        console.log(this.viewContainerRef);
        this.compiler.resolveComponent(ModalComponent)
        .then(
            (factory) =>
            this.viewContainerRef.createComponent(factory)
        ).then((componentRef) => {
                return componentRef;
            }
        );
    }
}
WingGao commented 7 years ago

@keyiis 有解决方案吗?

keyiis commented 7 years ago

@WingGao 木有,目前还没有找到一款能在angular2使用满意的模态框组件。

hstarorg commented 7 years ago

模态框应该是组件,不应该做成服务吧。如果非要这样做,完全可以在服务中,写js操作dom的代码。

keyiis commented 7 years ago

@hstarorg 模态框当然是组件,但用服务的方式调用会更灵活。

hstarorg commented 7 years ago

@keyiis 模态框核心是内容,如果服务并不好使用。 如果是提示框,确认框,我觉得用service倒是不错的。

keyiis commented 7 years ago

@hstarorg 我就是用模态框去实现提示框和确认框的哦

limerickgds commented 7 years ago

@keyiis 这个写一个 directive 而不是 service 来处理,可以参照 material2 portal

looading commented 7 years ago

@keyiis 差不多的方法。

  1. modal.service
    
    import { Injectable, ApplicationRef, Type, ComponentRef, ComponentFactory, Injector, ViewContainerRef,
    Component, ComponentFactoryResolver} from '@angular/core';

@Injectable() export class ModalService {

private _componentRef: ComponentRef;

public result: Promise;

private _resolve: (result?: T) => void; private _reject: (reason?: T) => void;

constructor(private _applicationRef: ApplicationRef, private _injector: Injector, private _componentFactoryResolver: ComponentFactoryResolver) { this.result = new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; });

}

open(component: Type): ComponentRef { const componentFactory = this._componentFactoryResolver.resolveComponentFactory(component); const appElementRef: ViewContainerRef = this._applicationRef.components[0].instance.viewRef; const componentRef = this._componentRef = appElementRef.createComponent(componentFactory); return componentRef; }

close(result: T) { this._componentRef.destroy(); this._resolve(result); }

dismiss(reason: T) { this._componentRef.destroy(); this._reject(reason); }

}


2. 自定义模态框组件 DetailModalComponent

3. some.component 里调用
```typescript
  constructor(private deploy: DeployService,
              private L: LogService,
              private modalService: ModalService,
              private componentFactoryResolver: ComponentFactoryResolver) {}

  onShowMore(project, index) {
    const modalRef = this.modalService.open<DetailModalComponent>(DetailModalComponent);
    modalRef.instance.noHeader = true;
    this.modalService.result
      .then(data => {
        console.log('DetailModalComponent close', data);
      })
      .catch(error => {
        console.error('DetailModalComponent dismiss', error);
      });

  }