Angular 2 RC 4动态添加&使用DynamicComponentLoader.loadNextToLocation(...)删除组件失败

时间:2016-07-08 12:44:13

标签: angular

我目前正在开展一个项目,我将其从Angular 2 beta 13升级到RC 4。 在升级之前,使用此服务动态添加和删除正在加载数据的任何页面的简单组件(简单的微调器)的功能都可以正常工作:

(SinnerService.ts)

import {Injectable, DynamicComponentLoader, ApplicationRef, ElementRef,          
        ComponentRef} from '@angular/core';

import {Spinner} from './spinner';

@Injectable()
export class SpinnerService {
spinnerComp: ComponentRef;

    constructor(private _componentLoader: DynamicComponentLoader, private _appRef: ApplicationRef) {
    }

    public start() {
        let elementRef: ElementRef = this._appRef['_rootComponents'][0].location;

        return this.startInside(elementRef, null);
    }

    public startInside(elementRef: ElementRef, anchorName: string) {

        let spinnerRef = (!anchorName) ?
            this._componentLoader.loadNextToLocation(Spinner, elementRef, anchorName) :
            this._componentLoader.loadNextToLocation(Spinner, elementRef);

        spinnerRef.then((compRef: ComponentRef) => {
            this.spinnerComp = compRef;
        });
    }

    public stop() {
        if (this.spinnerComp) {
            this.spinnerComp.dispose();
        }
    }
}

在升级过程中,对类进行了更改以匹配对Angular 2所做的更改。 生成的文件会导致发生异常,该异常显示在更新的代码下面:

(对于RC 4,SinnerService.ts已更改):

import {Injectable, DynamicComponentLoader, ApplicationRef, ViewContainerRef, ComponentRef} from '@angular/core';

import {Spinner} from './spinner';

@Injectable()
export class SpinnerService {
    spinnerComp: ComponentRef<any>;

    constructor(private _componentLoader: DynamicComponentLoader, private _appRef: ApplicationRef) {
    }

    public start() {
        let elementRef: ViewContainerRef = this._appRef['_rootComponents'][0].location;

        return this.startInside(elementRef, null);
    }

    public startInside(elementRef: ViewContainerRef, anchorName: string) {

        let spinnerRef = (!anchorName) ?
            this._componentLoader.loadNextToLocation(Spinner, elementRef) :
            this._componentLoader.loadNextToLocation(Spinner, elementRef);

        spinnerRef.then((compRef: ComponentRef<any>) => {
            this.spinnerComp = compRef;
        });
    }

    public stop() {
        if (this.spinnerComp) {
            this.spinnerComp.destroy();
        }
    }
}

错误:

EXCEPTION: Error: Uncaught (in promise): TypeError:
location.createComponent is not a function
browser_adapter.ts:82

EXCEPTION: Error: Uncaught (in promise): TypeError: 
location.createComponent is not a functionBrowser DomAdapter.logError @ browser_adapter.ts:82
browser_adapter.ts:82

STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.ts:82
browser_adapter.ts:82

Error: Uncaught (in promise): TypeError: 
location.createComponent is not a function
at resolvePromise (zone.js:538)
at resolvePromise (zone.js:523)
at zone.js:571
at ZoneDelegate.invokeTask (zone.js:356)
at Object.onInvokeTask (ng_zone_impl.ts:61)
at ZoneDelegate.invokeTask (zone.js:355)
at Zone.runTask (zone.js:256)
at drainMicroTaskQueue (zone.js:474)
at XMLHttpRequest.ZoneTask.invoke (zone.js:426) BrowserDomAdapter.logError @ browser_adapter.ts:82 zone.js:461

Unhandled Promise rejection: location.createComponent is not a 
function ; Zone: angular ; Task: Promise.then ; Value: TypeError: 
location.createComponent is not a function(…) consoleError @ zone.js:461
zone.js:463

Error: Uncaught (in promise): TypeError: location.createComponent is not a function(…)

所以,我阅读了很多关于这个主题的内容,并尝试了几种方法来使用DynamicComponentLoader.loadNextToLocation(...)。在调查期间,我还注意到这个组件似乎被Google弃用了。 (https://angular.io/docs/js/latest/api/core/index/DynamicComponentLoader-class.html

我继续对Angular 2进行更改的列表,提到您必须使用ViewContainerRef而不是ElementRef,但是没有关于如何执行此操作的示例。

经过更多挖掘后,我看到了一些建议,使用ComponentResolver而不是DynamicComponentLoader.loadNextToLocation(...),如下所示:

(SinnerService.ts更改为使用ComponentResolver):

import {Injectable, DynamicComponentLoader, ApplicationRef, ViewContainerRef, Component, ComponentRef, ComponentResolver, ComponentFactory, ViewChild} from '@angular/core';

import {Spinner} from './spinner';

@Injectable()
export class SpinnerService {
    spinnerComp: ComponentRef<any>;

    constructor(private _componentLoader: DynamicComponentLoader, private _appRef: ApplicationRef,
                private _resolver: ComponentResolver) {
    }

    public start() {
        let elementRef: ViewContainerRef = this._appRef['_rootComponents'][0].location;

        return this.startInside(elementRef, null);
    }

    public startInside(elementRef: ViewContainerRef, anchorName: string) {

        //let spinnerRef = (!anchorName) ?
        //    this._componentLoader.loadNextToLocation(Spinner, elementRef) :
        //    this._componentLoader.loadNextToLocation(Spinner, elementRef);
DynamicComponentLoader
        //spinnerRef.then((compRef: ComponentRef<any>) => {
        //    this.spinnerComp = compRef;
        //});

        let spinnerRef = this._resolver.resolveComponent(Spinner);

        spinnerRef.then((factory: ComponentFactory<any>) => {
            this.spinnerComp = elementRef.createComponent(factory)
        });
    }

    public stop() {
        if (this.spinnerComp) {
            this.spinnerComp.destroy();
        }
    }
}

但是,这也导致抛出的错误几乎与之前的错误相同:

EXCEPTION: Error: Uncaught (in promise): TypeError: 
elementRef.createComponent is not a function    
browser_adapter.ts:82

EXCEPTION: Error: Uncaught (in promise): TypeError: 
elementRef.createComponent is not a function    BrowserDomAdapter.logError @ browser_adapter.ts:82  browser_adapter.ts:82
STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.ts:82
    browser_adapter.ts:82

Error: Uncaught (in promise): TypeError: 
elementRef.createComponent is not a function
at resolvePromise (zone.js:538)
at zone.js:574
at ZoneDelegate.invokeTask (zone.js:356)
at Object.onInvokeTask (ng_zone_impl.ts:61)
at ZoneDelegate.invokeTask (zone.js:355)
at Zone.runTask (zone.js:256)
at drainMicroTaskQueue (zone.js:474)
at XMLHttpRequest.ZoneTask.invoke (zone.js:426)
BrowserDomAdapter.logError @ browser_adapter.ts:82
    zone.js:461 

Unhandled Promise rejection: elementRef.createComponent is not a 
function ; Zone: angular ; Task: Promise.then ; Value: TypeError: 
elementRef.createComponent is not a function(…)     consoleError @ zone.js:461
    zone.js:463 

Error: Uncaught (in promise): TypeError: elementRef.createComponent is 
not a function(…)   consoleError @ zone.js:463
    SignalRService.js:40 Event hub started.

所以,似乎这个重要的功能被打破了。

是否有其他人成功使用过此功能?

我在他们的GitHub存储库上向Google提交了一个错误,但我希望其他人可能已经遇到过这个问题并且有一个有效的方法来执行此操作或解决方法。

任何帮助将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

您需要使用ComponentResolverViewContainerRef类。这是一个简单的示例:

@Component({
  selector: 'my-app',
  template: '<template #target></template>'
})
export class AppComponent {
  @ViewChild('target', {read: ViewContainerRef}) target;

  componentRef: ComponentRef;

  constructor(private componentResolver:ComponentResolver) {}

  ngAfterViewInit() {
    this.componentResolver.resolveComponent(SomeComponent).then((factory) => {
      this.componentRef = this.target.createComponent(factory);
    });
  }
}