1

我有以下服务

@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();
   }
}

因此,我有一个名为“PComponent”的组件,并且从该服务中我以动态方式创建该组件,该类有两个方法实例-传递调用服务显示的组件的元素-附加已“创建”的PComponent

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

{{ 图片网址 }}

那应该是一个图像 url 并将该图像显示到 PComponent 中的 div 内容中。 问题 我如何将 imageURL 字符串传递到服务或组件中?

提前致谢

4

1 回答 1

4

这是答案

这是 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()方法是从外部组件调用的方法。createInjector()是创建Injector的方法,它帮助我们将数据传递给组件( PComponent )。所以是时候在另一个组件中使用我们的服务了。 例子.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:表达式在检查后已更改。以前的值:'null:未定义'。当前值:'null:测试文本'。似乎视图是在对其父级及其子级进行脏检查之后创建的。它是在变更检测挂钩中创建的吗?

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

希望对你有帮助

于 2018-04-08T23:01:32.833 回答