Angular Can';找不到正确的弯钩

Angular Can';找不到正确的弯钩,angular,angular5,Angular,Angular5,我使用的是Angular 5.2.1。我有一个主页,它有两个组成部分: <proposal-expansion [proposallist]="proposalList" ... ></proposal-expansion> <proposal-dashboard ... ></proposal-dashboard> 在主页组件中,以下是在发出该事件时调用的函数: showRecent(event) { this.proposalList

我使用的是Angular 5.2.1。我有一个主页,它有两个组成部分:

<proposal-expansion [proposallist]="proposalList" ... ></proposal-expansion>
<proposal-dashboard ... ></proposal-dashboard>
在主页组件中,以下是在发出该事件时调用的函数:

showRecent(event) {
    this.proposalList = event;
    this.showDashboard = false;
    this.spinnerService.spinner(false);
}
因此,此时,扩展组件从proposalList获取数据并尝试渲染。在扩展组件中呈现了许多子组件,实际显示扩展组件需要4-5秒。请记住,在这段时间内没有与服务器的交互——4-5秒都是有角度的

鉴于显示扩展组件需要很长时间,我希望显示一个微调器,以便用户知道正在发生什么。我有一个微调器服务,它通过传入
true
来显示微调器,或
false
来隐藏微调器。单击仪表板上的按钮后(在
expandRecent()
中),我立即将
true
传递给服务。这就是我遇到问题的地方

即使打开微调器是第一件事(除了
console.log()之外)
,它实际上并不是首先发生的。起初,我以为微调器会立即打开和关闭。但是,我发现如果我从未关闭微调器,它仍然会等到加载扩展组件后才打开微调器。此外,我还发现如果我在单击b之前手动打开微调器然后旋转器将不会关闭,直到扩展按需要加载。因此,似乎我需要确定何时何地打开旋转器

根据角度文档,ngOnChanges

当角度(重新)设置数据绑定输入属性时响应

基于此,我在扩展组件中添加了这一点,认为只要更新了
proposalList
,这将被称为:

ngOnChanges() {
    this.spinnerService.spinner(true);
}
我还在
expandRecent()中删除了将微调器设置为true的行
method。但是,当我完成所有这些操作时,在加载扩展组件之前,仍然没有微调器,更糟糕的是,它在ngOnChanges打开它之前关闭了微调器。因此,它在4-5秒钟内没有显示微调器,然后它启动并无限期运行

我应该使用哪些适当的生命周期挂钩,以及应该在哪些组件中使用它们,以使微调器按预期运行

谢谢

使用最新尝试更新:

我现在已经开始使用路由器和服务来实现这一点,但仍然存在同样的问题

expandRecent(): void {
    console.log("expand recent");
    this.spinnerService.spinner(true);
    this.changeDetectorRef.detectChanges();
    // essentially this just passes the data from one list to another in the service
    this.proposalService.proposalShortList$.take(1).subscribe(
        list => this.proposalService.setProposalList(list)
    );
    // this navigates to the ProposalExpansion component
    this.router.navigate(['../display'], { relativeTo: this.route });
}
然后我尝试将其添加到ProposalExpansion组件中:

ngAfterViewChecked() {
    this.spinnerService.spinner(false);
}
现在,当expandRecent()运行时,这就是我在控制台中看到的(数字是每个组件的ngOnInit运行时的时间戳):

基于控制台,人们可能会认为它正在工作。然而,微调器从未真正可见。但是,如果我将
router.navigate
放在
setTimeout
函数中,那么微调器的工作完全符合预期。(当时间设置为100 ms或更大时,setTimeout工作。它在10 ms或更小的时间内不工作。)虽然这是一个我可以使用的工作环境,但我真的很想了解正在发生的事情,而且似乎我不应该使用这种工作环境

我很想在Plunker中使用它,但在添加所有代码之前,我甚至很难让它与棱角材料一起工作,所以这将是一项重要的时间投资,我宁愿避免

以下是微调器代码:

spinner.component.html

<div *ngIf="(spinner$ | async)">
    <i class="fas fa-spinner fa-pulse fa-2x fa-fw"></i>
</div>

spinner.component.ts

import { Component, OnInit } from '@angular/core';
import {Observable} from 'rxjs/Observable';

import { SpinnerService } from './spinner.service';

@Component({
  selector: 'spinner',
  templateUrl: './spinner.component.html',
  styleUrls: ['./spinner.component.scss']
})
export class SpinnerComponent implements OnInit {
    spinner$: Observable<boolean>;

    constructor(private spinnerService: SpinnerService) { }

    ngOnInit() {
        this.spinner$ = this.spinnerService.spinner$;
    }

    // to show the spinner
    showSpinner() {
        this.spinnerService.spinner(true);
    }

    // to hide the spinner
    hideSpinner() {
        this.spinnerService.spinner(false);
    }
}
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class SpinnerService {
    private spinnerSubject = new BehaviorSubject<boolean>(false);
    spinner$: Observable<boolean> = this.spinnerSubject.asObservable();

    constructor() {}

    spinner(spin:boolean) {
        console.log("Should change spinner to "+spin);
        this.spinnerSubject.next(spin);
    }
}
从'@angular/core'导入{Component,OnInit};
从“rxjs/Observable”导入{Observable};
从“./spinner.service”导入{SpinnerService};
@组成部分({
选择器:“微调器”,
templateUrl:'./spinner.component.html',
样式URL:['./spinner.component.scss']
})
导出类SpinnerComponent实现OnInit{
微调器$:可观察;
构造函数(专用spinnerService:spinnerService){}
恩戈尼尼特(){
this.spinner$=this.spinnerService.spinner$;
}
//展示旋转器
showSpinner(){
这个.spinnerService.spinner(true);
}
//隐藏旋转器
hideSpinner(){
此.spinnerService.spinner(false);
}
}
spinner.service.ts

import { Component, OnInit } from '@angular/core';
import {Observable} from 'rxjs/Observable';

import { SpinnerService } from './spinner.service';

@Component({
  selector: 'spinner',
  templateUrl: './spinner.component.html',
  styleUrls: ['./spinner.component.scss']
})
export class SpinnerComponent implements OnInit {
    spinner$: Observable<boolean>;

    constructor(private spinnerService: SpinnerService) { }

    ngOnInit() {
        this.spinner$ = this.spinnerService.spinner$;
    }

    // to show the spinner
    showSpinner() {
        this.spinnerService.spinner(true);
    }

    // to hide the spinner
    hideSpinner() {
        this.spinnerService.spinner(false);
    }
}
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class SpinnerService {
    private spinnerSubject = new BehaviorSubject<boolean>(false);
    spinner$: Observable<boolean> = this.spinnerSubject.asObservable();

    constructor() {}

    spinner(spin:boolean) {
        console.log("Should change spinner to "+spin);
        this.spinnerSubject.next(spin);
    }
}
从'@angular/core'导入{Injectable};
从“rxjs/Observable”导入{Observable};
从'rxjs/BehaviorSubject'导入{BehaviorSubject};
@可注射()
出口级喷丝板服务{
私有spinnerSubject=新行为主体(false);
spinner$:Observable=this.spinnerSubject.asObservable();
构造函数(){}
微调器(旋转:布尔值){
log(“应将微调器更改为“+spin”);
这个。喷丝头主体。下一个(旋转);
}
}

使用布管时,可以按如下方式打开/关闭微调器:

应用程序组件

import { Component } from '@angular/core';
import { Router, Event, NavigationStart, NavigationEnd, NavigationError, NavigationCancel } from '@angular/router';

@Component({
    selector: 'mh-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    loading: boolean = true;

    constructor(private router: Router) {
        router.events.subscribe((routerEvent: Event) => {
            this.checkRouterEvent(routerEvent);
        });
    }

    checkRouterEvent(routerEvent: Event): void {
        if (routerEvent instanceof NavigationStart) {
            this.loading = true;
        }

        if (routerEvent instanceof NavigationEnd ||
            routerEvent instanceof NavigationCancel ||
            routerEvent instanceof NavigationError) {
            this.loading = false;
        }
    }
}
应用程序模板

<span class="glyphicon glyphicon-refresh glyphicon-spin spinner" *ngIf="loading"></span>
<router-outlet></router-outlet>


您可以为微调器定义任何所需的图像/图形。只需根据加载标志将其打开/关闭即可。

虽然这不能解释微调器无法按预期工作的原因,但它确实起到了使其按预期工作的作用。基本上,我必须将导航置于setTimeout函数中:

expandRecent(): void {
    console.log("expand recent");
    this.spinnerService.spinner(true);
    this.proposalService.proposalShortList$.take(1).subscribe(
        list => this.proposalService.setProposalList(list)
    );
    let myrouter = this.router;
    let myroute = this.route;
    setTimeout(function() {
        myrouter.navigate(['../display'], { relativeTo: myroute });
    },100);
}

虽然这也不能回答这个问题,但它确实为用户交互的主要问题提供了一个潜在的解决方案。根据材料文档:

延迟渲染

默认情况下,扩展面板内容将被初始化,即使 面板已关闭。请改为将初始化延迟到面板关闭 如果是开放的,则内容应作为ng模板提供:


这是扩展标题
一些延迟的内容
因此,与其尝试一次性渲染所有扩展面板
<mat-expansion-panel>
  <mat-expansion-panel-header>
    This is the expansion title
  </mat-expansion-panel-header>

  <ng-template matExpansionPanelContent>
    Some deferred content
  </ng-template>
</mat-expansion-panel>