Angular 5:无法将已销毁的视图插入ViewContainer

时间:2018-02-22 21:19:44

标签: angular typescript

我收到的错误是我以前在Angular应用中从未见过的。错误发生在Angular源代码的this line上。

当我退出并重新登录我的应用时会发生这种情况。我这样做的路径有一个可观察的观察点,并且当它向其流发出一个值时,观察到的任何东西都会更新值并且更改检测将运行,从而删除一些元素并添加一些其他元素。

我非常确定下面的组件会导致错误。任何人都可以看到任何明显的我做错了吗?我留下了我认为可能与bug相关的部分,并注释掉了其他所有内容。也许我在这里不恰当地使用ngTemplateOutletContentChild ......

组件:

@Component({
    selector: 'paginated-infinite-scroll',
    templateUrl: './paginated-infinite-scroll.component.html'
})
export class PaginatedInfiniteScrollComponent {
    // ...

    @ContentChild('results') resultsRef: TemplateRef<any>;
    @ContentChild('noResults') noResultsRef: TemplateRef<any>;
    @ContentChild('loading') loadingRef: TemplateRef<any>;
    @ContentChild('loadingMore') loadingMoreRef: TemplateRef<any>;

    // ...
}

模板:

<div infiniteScroll [infiniteScrollDistance]="2" [infiniteScrollThrottle]="300" [scrollWindow]="true" (scrolled)="scrolled()">
    <ng-container *ngIf="result.items.length > 0 && !loading">
        <ng-template [ngTemplateOutlet]="resultsRef"></ng-template>
    </ng-container>

    <ng-container *ngIf="result.items.length === 0 && !loading">
        <ng-template [ngTemplateOutlet]="noResultsRef"></ng-template>
    </ng-container>

    <ng-container *ngIf="loading">
        <ng-template [ngTemplateOutlet]="loadingRef"></ng-template>
    </ng-container>

    <ng-container *ngIf="loadingMore">
        <ng-template [ngTemplateOutlet]="loadingMoreRef"></ng-template>
    </ng-container>
</div>

用法:

<paginated-infinite-scroll [onScroll]="onScroll" [query]="query" [result]="result">
    <ng-template #results>
        // Loop through results here...
    </ng-template>

    <ng-template #noResults>
        // Show no results message here...
    </ng-template>

    <ng-template #loading>
        // Show loading spinner here...
    </ng-template>

    <ng-template #loadingMore>
        // Show some other loading spinner here...
    </ng-template>
</paginated-infinite-scroll>

1 个答案:

答案 0 :(得分:0)

修正了此问题。该错误实际上并非来自我原始问题中的代码。我在指令中有一个可观察的,我从来没有取消订阅。该指令订阅了一个auth事件,每次我登录/注销它都会尝试插入或分离它所连接的组件,在这种情况下,因为我导航后该组件将被销毁,所以bug出现了

这是我的指示逻辑:

@Directive({
    selector: '[loggedIn]'
})
export class LoggedInDirective implements OnInit, OnDestroy {
    private which: boolean = false;
    private _loggedIn: boolean = false;

    view = this.templateRef.createEmbeddedView(null);
    authEventsSub: Subscription;

    constructor(
        private viewContainerRef: ViewContainerRef,
        private templateRef: TemplateRef<any>
    ) {}

    ngOnInit() {
        this.authEventsSub = this.authEventsService.events$.subscribe((event: AuthEvent) => {
            this._loggedIn = (event === AuthEvent.LOGGED_IN) || (event === AuthEvent.READY);
            this.render();
        });
    }

    private render() {
        if (this.which) {
            if (this._loggedIn) {
                this.viewContainerRef.insert(this.view);
            } else {
                this.viewContainerRef.detach();
            }
        } else {
            if (this._loggedIn) {
                this.viewContainerRef.detach();
            } else {
                this.viewContainerRef.insert(this.view);
            }
        }
    }

    // ...
}

通过取消订阅ngOnDestroy钩子中的observable来修复它:

authEventsSub: Subscription;

constructor(
    private viewContainerRef: ViewContainerRef,
    private templateRef: TemplateRef<any>,
    private authEventsService: AuthEventsService,
) {}

ngOnInit() {
    this.authEventsSub = this.authEventsService.events$.subscribe((event: AuthEvent) => {
        this._loggedIn = (event === AuthEvent.LOGGED_IN) || (event === AuthEvent.READY);
        this.render();
    });
}

ngOnDestroy() {
    if (this.authEventsSub) {
        this.authEventsSub.unsubscribe();
    }
}