Angular CDK并将值传递给DomPortalHost中的组件

时间:2018-04-08 18:04:45

标签: angular portal angular-cdk

我有以下服务

@Injectable()
export class PService {
   private loadPComponent: ComponentPortal<PComponent>;
   private bodyPortalHost: DomPortalHost;

   constructor(private appRef: ApplicationRef,
               private  componentFactoryResolver: 
                       ComponentFactoryResolver,
               private injector: Injector) {
      this.loadPComponent = new ComponentPortal(PComponent);
   }
   instance(elementRef: Element) {
      this.bodyPortalHost = new DomPortalHost(elementRef, 
           this.componentFactoryResolver, this.appRef, this.injector);
   }
   show() {
      const componentRef: ComponentRef<PComponent> = 
                 this.bodyPortalHost.attach(this.loadPComponent);
   }
   hide() {
      this.bodyPortalHost.detach();
   }
}

所以,我有一个组件calle“PComponent”,并从该服务我创建dinamically组件 这个班有两种方法 instance - 传递调用服务的组件的Element show - 附加已经“创建”的PComponent

一切正常,Portal是一个很棒的解决方案! 但我的PComponent有一个带有一些变量的HTML模板,例如

  

{{imageURL}}

应该是图片网址,并将该图片显示为PComponent中的div内容。 问题 我如何将imageURL字符串传递给服务或组件?

提前致谢

1 个答案:

答案 0 :(得分:2)

这是答案

这是Pcomponent代码,该组件应该从另一个组件创建。 的 p.component.ts

@Component({
    selector: 'app-p',
    templateUrl: './p.component.html',
    styleUrls: ['./p.component.css']
})
export class PComponent implements OnInit {
    name: string = '';
    constructor(@Inject(CONTAINER_DATA) public componentData: any) { }

    ngOnInit() {
        console.log(this.componentData.data.test);
    }
}

所以我们必须注入CONTAINER_DATA InjectionToken,从该变量可以获取从其他组件传递的数据。 CONTAINER_DATA变量在服务文件中创建。 的 p.service.ts

import {ApplicationRef, ComponentFactoryResolver, ComponentRef, Injectable, InjectionToken, Injector} from '@angular/core';
import {CONTAINER_DATA, PComponent} from './p.component';
import {
    ComponentPortal,
    DomPortalHost, PortalInjector
} from '@angular/cdk/portal';
export const CONTAINER_DATA = new InjectionToken<{}>('CONTAINER_DATA');
@Injectable()
export class PService {
    private loadPComponent: ComponentPortal<PComponent>;
    private bodyPortalHost: DomPortalHost;
    constructor(private appRef: ApplicationRef,
        private  componentFactoryResolver: ComponentFactoryResolver,
        private injector: Injector) { }
    instance(elementRef: Element, data) {
        this.loadPComponent = new ComponentPortal(PComponent, null, 
            this.createInjector({data}));
        this.bodyPortalHost = new DomPortalHost(elementRef, 
            this.componentFactoryResolver, this.appRef, this.injector);
    }
    show() {
        const componentRef: ComponentRef<PComponent> = 
        this.bodyPortalHost.attach(this.loadPComponent);
    }
    createInjector(dataToPass): PortalInjector {
        const injectorTokens = new WeakMap();
        injectorTokens.set(CONTAINER_DATA, dataToPass);
        return new PortalInjector(this.injector, injectorTokens);
    }
    hide() {
        this.bodyPortalHost.detach();
    }
}

因此,在服务中我们使用@ angular / cdk / portal来获取PComponent实例。 instance() show()方法是从外部Component调用的方法。 createInjector()是创建 Injector 的方法,它帮助我们将数据传递给组件(PComponent)。 所以现在是时候在另一个组件中使用我们的服务了。 的 example.component.ts

@Component({
    selector: 'app-example',
    templateUrl: './example.component.html',
    styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
    @ViewChild('bpage', {read: ElementRef}) tref: ElementRef;
    constructor(private route: ActivatedRoute, private pService: 
         PService, private contentService: ContentService) { }

    ngOnInit() {
        Promise.resolve().then(() => {
           this.pService.instance(this.tref.nativeElement, {'test': 
            'prueba'});
    }
}

该组件在html模板中有一个类似的标记:

<div #bpage></div>

在此标记中应收取来自PComponent并从PService注入的内容。 在OnInit方法中,我们必须将服务调用封装到Promise中,这样可以避免以下错误:

ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后发生了变化。上一个值:&#39; null:undefined&#39;。当前值:&#39; null:测试文字&#39;。看起来这个视图是在其父级及其子级被脏检查后创建的。它是否已在变更检测钩子中创建?

页面刷新后,您将看到自动生成并在bpage标签中发布的PComponent的内容

希望对你有所帮助