【问题标题】:Angular 2 RC 4 Dynamically adding & removing components with DynamicComponentLoader.loadNextToLocation(...) is failingAngular 2 RC 4 使用 DynamicComponentLoader.loadNextToLocation(...) 动态添加和删除组件失败
【发布时间】:2016-07-08 12:44:13
【问题描述】:

我目前正在从事一个从 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)

Google 在 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 提交了一个错误,但我希望其他人可能已经遇到了这个问题,并且有一个有效的方法来解决这个问题或解决这个问题。

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

【问题讨论】:

  • 听起来像` let elementRef: ViewContainerRef = this._appRef['_rootComponents'][0].location; ` 没有返回 ViewContainerRef。你检查了吗?
  • 嗨,比尔,你解决了这个问题吗?

标签: angular


【解决方案1】:

您需要改用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);
    });
  }
}

【讨论】:

  • 您好 Thierry,如果您查看上面的示例,您会看到我尝试了 ComponentResolver(在上面搜索“(SinnerService.ts changed to use ComponentResolver):”。不幸的是,如您所见在我的示例下方,返回的错误与我使用 DynamicComponentLoader 收到的错误几乎相同。我实际上在这个问题上向 Google 提交了一个错误,因为这似乎不适用于 RC 4。
猜你喜欢
  • 2017-11-18
  • 2017-12-09
  • 1970-01-01
  • 2017-05-18
  • 2018-09-15
  • 2016-01-17
  • 1970-01-01
  • 2017-03-21
  • 1970-01-01
相关资源
最近更新 更多