首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在可观测值的初始加载过程中未加载的值

在可观测值的初始加载过程中未加载的值
EN

Stack Overflow用户
提问于 2019-04-10 11:46:01
回答 2查看 1.3K关注 0票数 1

在一个角度应用程序中,我想动态地从数据库加载菜单(.NEt核心项目)。为此,我创建了一个API服务来获取json格式的数据。为了从前端请求这种json格式,我在workout.service.ts-file中使用了一个服务(我尝试了它,不管有没有一个可观察到的,但得到了相同的结果)。

为了加载菜单,我使用了menu.service.ts-file,其中函数getVerticalMenuItems()用于加载在初始化过程中无法工作的垂直菜单;

在这里,我使用resultmenu.push方法将数据转换为以下格式:

代码语言:javascript
复制
export const verticalMenuItems = [
  new Menu(1, 'Dashboard', '/', null, 'dashboard', null, false, 0),
  new Menu(100, 'Action', '/actions', null, 'extension', null, false, 0)]

垂直菜单上传,我们使用vertical-menu.component.ts (我猜想问题出现在这里,它总是显示Array=null值)

menu.modal.ts

代码语言:javascript
复制
export class Menu {
    constructor(public id: number,
                public title: string,
                public routerLink: string,
                public href: string,
                public icon: string,
                public target: string,
                public hasSubMenu: boolean,
                public parentId: number) { }
} 

workout.service.ts

代码语言:javascript
复制
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import 'rxjs/Rx';
import { User } from './models/user.model';
import { Observable } from 'rxjs/Rx';
import { Menu } from './theme/components/menu/menu.model';

@Injectable()
export class WorkoutService {


private headers: HttpHeaders;

  private menuUrl: string = 'https://localhost:44355/api/Menus';

constructor(private http: HttpClient) {
this.headers= new HttpHeaders({'Content-Type':'application/json; charset=utf-8});}

  // Get Menus
  public getMenus() {return this.http.get(this.menuUrl, { headers: this.headers }).map((response: Response) => {     
      return response;
    });

  }


}

menu.service.ts

代码语言:javascript
复制
@Injectable()
export class MenuService {
  my_menu: Array<Menu>;

  constructor(private location:Location,
              private router: Router,
              private workoutService: WorkoutService) { } 



// for vertical Menu items loading
 public getVerticalMenuItems(): Array<Menu> {  
    const resultMenu: Array<Menu>=[];       
    this.workoutService.getMenus()
       .subscribe(
       (data:any) => {       
        data.forEach(i => {
          resultMenu.push(new Menu(i.id, i.title, i.routerLink, i.href, i.icon, i.target, i.hasSubMenu, i.parentId))
        })
        console.log(resultMenu);
      }
    );

    console.log(resultMenu);
    console.log(verticalMenuItems);
    return resultMenu;
    //return verticalMenuItems; -- NOTE: old working code taken from Gradus theme templates ;(working code)

  }

// working code
  public getHorizontalMenuItems(): Array<Menu> {
      return horizontalMenuItems;
  }


public expandActiveSubMenu(menu: Observable<Menu[]>){
      let url = this.location.path();
      let routerLink = url; // url.substring(1, url.length);
      let activeMenuItem = menu.map(items=>items.filter(item => item.routerLink === routerLink));
      if(activeMenuItem[0]){
        let menuItem = activeMenuItem[0];
        while (menuItem.parentId != 0){  
          let parentMenuItem = menu.map(items=>items.filter(item => item.id == menuItem.parentId)[0]);
          menuItem = parentMenuItem;
          this.toggleMenuItem(menuItem.id);
        }
      }
  }

  public toggleMenuItem(menuId){
    let menuItem = document.getElementById('menu-item-'+menuId);
    let subMenu = document.getElementById('sub-menu-'+menuId);  
    if(subMenu){
      if(subMenu.classList.contains('show')){
        subMenu.classList.remove('show');
        menuItem.classList.remove('expanded');
      }
      else{
        subMenu.classList.add('show');
        menuItem.classList.add('expanded');
      }      
    }
  }

  public closeOtherSubMenus(menu: Array<Menu>, menuId) {
    debugger;
    let currentMenuItem = menu.filter(item => item.id == menuId)[0]; 
    if(currentMenuItem.parentId == 0 && !currentMenuItem.target){
      menu.forEach(item => {
        if(item.id != menuId){
          let subMenu = document.getElementById('sub-menu-'+item.id);
          let menuItem = document.getElementById('menu-item-'+item.id);
          if(subMenu){
            if(subMenu.classList.contains('show')){
              subMenu.classList.remove('show');
              menuItem.classList.remove('expanded');
            }              
          } 
        }
      });
    }

vertical-menu.component.ts

代码语言:javascript
复制
export class VerticalMenuComponent implements OnInit {
  @Input() resultMenu: Array<Menu> = [];

  /***************************************
  * MOVED THE NEW INPUTS TO HERE
  ****************************************/
  @Input()
  set menuItems(items: Menu[]) {
    this._menuItemsLoaded$.next(items);
  }
  _menuItemsLoaded$: ReplaySubject<Menu[]> = new ReplaySubject<Menu[]>(1);

  // We must save the received items and also emit it
  @Input() 
  set menuParentId(items: number) {
    this._menuParentIdLoaded$.next(items);
  }
  _menuParentIdLoaded$: ReplaySubject<number> = 
  new ReplaySubject<number>(1);

  /***************************************
  * END OF NEW INPUTS
  ****************************************/

  @Output() onClickMenuItem: EventEmitter<any> = new EventEmitter<any>();
  parentMenu: Array<any>;
  public settings: Settings;

  constructor(public appSettings: AppSettings, public menuService: MenuService, public router: Router) {
    this.settings = this.appSettings.settings;
  }

  ngOnInit() {
  /***************************************
   * FIXED THE FILTERS INSIDE THE PIPES
   ****************************************/
    combineLatest(
      this._menuItemsLoaded$.pipe(
            filter(Boolean), 
            filter((i) => !!i.length), 
            debounceTime(300)),
      this._menuParentIdLoaded$.pipe(
            // for _menuParentId (exclusively) we cannot use 
            // filter(Boolean) here, or the 0 values will be blocked
            filter((i) => i !== null && i !== undefined),
            debounceTime(300)),
    ).subscribe(([menuItems, parentId]) => 
      this.parentMenu = menuItems.filter(item => item.parentId == parentId)
    );
  }

  // as we're using some subjects, we must finalize
  // them in case this component is eventually destroyed
  ngOnDestroy() {
    if (this._menuItemsLoaded$ && !this._menuItemsLoaded$.closed) {
      this._menuItemsLoaded$.complete();
    }

    if (this._menuParentIdLoaded$ && !this._menuParentIdLoaded$.closed) {
      this._menuParentIdLoaded$.complete();
    }
  }

    //ngOnChanges() {
    //  if (this.menuItems == null) {
    //    this.parentMenu = null;
    //  }
    //  this.parentMenu = this.menuItems.filter(item => item.parentId == this.menuParentId);
    //  console.log(this.parentMenu);
    //}


    ngAfterViewInit() {
      this.router.events.subscribe(event => {
        if (event instanceof NavigationEnd) {
          if (this.settings.fixedHeader) {
            let mainContent = document.getElementById('main-content');
            if (mainContent) {
              mainContent.scrollTop = 0;
            }
          }
          else {
            document.getElementsByClassName('mat-drawer-content')[0].scrollTop = 0;
          }
        }
      });
    }

    onClick(menuId) {
      /*************************************
       * Import take operator from 'rxjs/operators'
       * As part of the changes, the values that we need are
       * all on `_menuItemsLoaded$` ReplaySubject. 
       *************************************/
      combineLatest(this._menuItemsLoaded$).pipe(take(1))
        .subscribe(([items]) => {
          this.menuService.toggleMenuItem(menuId);
          this.menuService.closeOtherSubMenus(items, menuId);
          this.onClickMenuItem.emit(menuId);
        }
    }


}

vertical-menu.component.html

代码语言:javascript
复制
<div *ngFor="let menu of parentMenu" class="menu-item">
    <a *ngIf="menu.routerLink && menu.hasSubMenu" mat-button 
        fxLayout="row" [fxLayoutAlign]="(settings.menuType=='default') ? 'start center' : 'center center'"
        [routerLink]="[menu.routerLink]" routerLinkActive="active-link" [routerLinkActiveOptions]="{exact:true}"
        [matTooltip]="menu.title" matTooltipPosition="after" [matTooltipDisabled]="(settings.menuType=='mini') ? 'false' : 'true'"
        (click)="onClick(menu.id)" [id]="'menu-item-'+menu.id">
        <mat-icon class="menu-icon">{{menu.icon}}</mat-icon>
        <span class="menu-title">{{menu.title}}</span>  <!--  !menu.hasSubMenu--> 
    </a>
    <a *ngIf="menu.href && !menu.subMenu && !menu.hasSubMenu" mat-button 
        fxLayout="row" [fxLayoutAlign]="(settings.menuType=='default') ? 'start center' : 'center center'"
        [attr.href]="menu.href || ''" [attr.target]="menu.target || ''"
        [matTooltip]="menu.title" matTooltipPosition="after" [matTooltipDisabled]="(settings.menuType=='mini') ? 'false' : 'true'"
        (click)="onClick(menu.id)" [id]="'menu-item-'+menu.id">
        <mat-icon class="menu-icon">{{menu.icon}}</mat-icon>
        <span class="menu-title">{{menu.title}}</span>        
    </a>
    <a *ngIf="menu.hasSubMenu" mat-button 
        fxLayout="row" [fxLayoutAlign]="(settings.menuType=='default') ? 'start center' : 'center center'"
        [matTooltip]="menu.title" matTooltipPosition="after" [matTooltipDisabled]="(settings.menuType=='mini') ? 'false' : 'true'"
        (click)="onClick(menu.id)" [id]="'menu-item-'+menu.id">
        <mat-icon class="menu-icon">{{menu.icon}}</mat-icon>
        <span class="menu-title">{{menu.title}}</span>
        <mat-icon class="menu-expand-icon transition-2">arrow_drop_down</mat-icon>
    </a>

    <div *ngIf="menu.hasSubMenu" class="sub-menu" [id]="'sub-menu-'+menu.id"> 
        <app-vertical-menu [menuItems]="_menuItemsLoaded$ | async" [menuParentId]="menu.id" (onClickMenuItem)="updatePS($event)"></app-vertical-menu>

     <!-- <app-vertical-menu (onClickMenuItem)="updatePS($event)"
                     [menuItems]="{menuItems: _menuItemsLoaded$ | async, parentId: 0}">
      </app-vertical-menu> -->
    </div>
</div>

sidenav.component.html

代码语言:javascript
复制
<div fxLayout="column" fxLayoutAlign="center center" class="user-block transition-2" [class.show]="settings.sidenavUserBlock"> 
    <div [fxLayout]="(settings.menuType != 'default') ? 'column' : 'row'" 
         [fxLayoutAlign]="(settings.menuType != 'default') ? 'center center' : 'space-around center'" class="user-info-wrapper">
        <img [src]="userImage" alt="user-image">
        <div class="user-info">
            <p class="name">Emilio Verdines</p>
            <p *ngIf="settings.menuType == 'default'" class="position">Web developer <br> <small class="muted-text">Member since May. 2016</small></p>
        </div>
    </div>
    <div *ngIf="settings.menuType != 'mini'" fxLayout="row" fxLayoutAlign="space-around center" class="w-100 muted-text">
        <button mat-icon-button><mat-icon>person_outline</mat-icon></button>
        <a mat-icon-button routerLink="/mailbox">
            <mat-icon>mail_outline</mat-icon>
        </a>
        <a mat-icon-button routerLink="/login">
            <mat-icon>power_settings_new</mat-icon>
        </a>
    </div>
</div>

<perfect-scrollbar #sidenavPS class="sidenav-menu-outer" [class.user-block-show]="settings.sidenavUserBlock">   
    <span *ngIf="!menuItems">loading....</span>
    <app-vertical-menu [menuItems]="menuItems" [menuParentId]="0" (onClickMenuItem)="updatePS($event)"></app-vertical-menu> 
</perfect-scrollbar>

sidenav.component.ts

代码语言:javascript
复制
@Component({
  selector: 'app-sidenav',
  templateUrl: './sidenav.component.html',
  styleUrls: ['./sidenav.component.scss'],
  encapsulation: ViewEncapsulation.None,
  providers: [MenuService]
})
export class SidenavComponent implements OnInit {
  @ViewChild('sidenavPS') sidenavPS: PerfectScrollbarComponent;
  public userImage = '../assets/img/users/user.jpg';
  public menuItems: Array<any>;
  public settings: Settings;
  constructor(public appSettings: AppSettings, public menuService: MenuService) {
    this.settings = this.appSettings.settings;
  }

  ngOnInit() {
    debugger;
    this.menuItems = this.menuService.getVerticalMenuItems();
  }

  ngOnChange() {
    debugger;
    this.menuItems = this.menuService.getVerticalMenuItems();
  }

  public closeSubMenus() {
    const menu = document.querySelector('.sidenav-menu-outer');
    if (menu) {
      for (let i = 0; i < menu.children[0].children.length; i++) {
        const child = menu.children[0].children[i];
        if (child) {
          if (child.children[0].classList.contains('expanded')) {
            child.children[0].classList.remove('expanded');
            child.children[1].classList.remove('show');
          }
        }
      }
    }
  }

  public updatePS(e) {
    this.sidenavPS.directiveRef.update();
  }

dynamic-menu.component.ts

代码语言:javascript
复制
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators} from '@angular/forms';
import { MatSnackBar } from '@angular/material';
import 'rxjs/add/operator/debounceTime';
import { Menu } from '../../theme/components/menu/menu.model';
import { MenuService } from '../../theme/components/menu/menu.service';
import { DynamicMenuService } from './dynamic-menu.service';
import { AppSettings } from '../../app.settings';
import { Settings } from '../../app.settings.model';
import { VerticalMenuComponent } from '../../theme/components/menu/vertical-menu/vertical-menu.component';
import { listTransition } from '../../theme/utils/app-animation';
import { combineLatest, Observable } from 'rxjs';

@Component({
  selector: 'app-dynamic-menu',
  templateUrl: './dynamic-menu.component.html',
  providers: [ DynamicMenuService, MenuService ],
  animations: [ listTransition ],
  host: {
    '[@listTransition]': ''
  }
})
export class DynamicMenuComponent implements OnInit {
  settings: Settings;
  menuItems:Array<Menu>;
  _menuItems$: Observable<Menu[]>;
  public icons = ['home','person', 'card_travel', 'delete', 'event', 'favorite', 'help' ]
  public form:FormGroup;
  constructor(public appSettings:AppSettings, 
              public formBuilder: FormBuilder, 
              public snackBar: MatSnackBar,
              private menuService:MenuService,
              private dynamicMenuService:DynamicMenuService) {
    this.settings = this.appSettings.settings; 
    this._menuItems$ = this.menuService.getVerticalMenuItems()
        .pipe(tap((menuItems: Menu) => this.menuItems = menuItems));
  }

  ngOnInit() {
    this.form = this.formBuilder.group({
      'title': ['', Validators.compose([Validators.required, Validators.minLength(3)])],
      'icon': null,
      'routerLink': ['', Validators.required],    
      'href': ['', Validators.required],            
      'target': null,
      'hasSubMenu': false,
      'parentId': 0
    });
  }

  ngAfterViewInit() {
    this.form.valueChanges.debounceTime(500).subscribe(menu => {  
      if(menu.routerLink && menu.routerLink != ''){
        this.form.controls['href'].setValue(null);
        this.form.controls['href'].disable();
        this.form.controls['href'].clearValidators();
        this.form.controls['target'].setValue(null);
        this.form.controls['target'].disable();
      }
      else{
        this.form.controls['href'].enable();
        this.form.controls['href'].setValidators([Validators.required]);
        this.form.controls['target'].enable();
      }
      this.form.controls['href'].updateValueAndValidity();

      if(menu.href && menu.href != ''){
        this.form.controls['routerLink'].setValue(null);
        this.form.controls['routerLink'].disable();
        this.form.controls['routerLink'].clearValidators();
        this.form.controls['hasSubMenu'].setValue(false);
        this.form.controls['hasSubMenu'].disable();
      }
      else{
        this.form.controls['routerLink'].enable();
        this.form.controls['routerLink'].setValidators([Validators.required]);
        this.form.controls['hasSubMenu'].enable();
      }
      this.form.controls['routerLink'].updateValueAndValidity();
    })
  }

  onSubmit(menu:Menu):void {
    if (this.form.valid) {
      this.dynamicMenuService.addNewMenuItem(VerticalMenuComponent, this.menuItems, menu);
      this.snackBar.open('New menu item added successfully!', null, {
        duration: 2000,
      });
      this.form.reset({
        hasSubMenu:false,
        parentId:0
      });    
    } 
  } 

}

dynamic-menu.service.ts

代码语言:javascript
复制
import { Injectable, Injector, ComponentFactoryResolver, ApplicationRef, EmbeddedViewRef } from '@angular/core';
import { VerticalMenuComponent } from '../../theme/components/menu/vertical-menu/vertical-menu.component';
import { Menu } from '../../theme/components/menu/menu.model';

@Injectable()
export class DynamicMenuService {

    constructor(private componentFactoryResolver: ComponentFactoryResolver,
                private applicationRef: ApplicationRef,
                private injector: Injector) { }     

    addNewMenuItem(component: any, menuItems:Array<Menu>, menuItem) {

        const lastId = menuItems[menuItems.length-1].id;
        const newMenuItem = new Menu(lastId+1, menuItem['title'], menuItem['routerLink'], menuItem['href'], menuItem['icon'], menuItem['target'], menuItem['hasSubMenu'], parseInt(menuItem['parentId']));

        menuItems.push(newMenuItem);
        let item = menuItems.filter(item=>item.id == newMenuItem.parentId)[0];
        if(item) item.hasSubMenu = true;  

        const componentRef = this.componentFactoryResolver
            .resolveComponentFactory(component)
            .create(this.injector);        

        this.applicationRef.attachView(componentRef.hostView);

        let instance = <VerticalMenuComponent>componentRef.instance;
        instance.menuItems = menuItems;
        instance.menuParentId = 0;

        const elem = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;

        const sidenav = document.getElementById('sidenav-menu-outer');        
        sidenav.replaceChild(elem, sidenav.children[0]);     

    } 
}

检查图像以获得更多信息,其中显示由于订阅延迟在这里输入图像描述而导致的数组null复制错误,如下所示,链接在这里输入图像描述新错误与tap绑定在这里输入图像描述

结果输出在这里输入图像描述

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-12 09:15:45

嗯,我会在代码中修改一些东西。

<vertical-menu>的使用

而不是:

代码语言:javascript
复制
<app-vertical-menu [menuItems]="menuItems" [menuParentId]="0" (onClickMenuItem)="updatePS($event)"></app-vertical-menu> 

我会这样做:

代码语言:javascript
复制
<app-vertical-menu [menuItems]="_menuItems$ | async" [menuParentId]="0" (onClickMenuItem)="updatePS($event)"></app-vertical-menu> 

从现在开始,menuItems_menuItems$的转变仅仅是表面现象,表明它是可以观察到的。真正的改变是async管道。

在调用menuService的类型记录代码中

代码语言:javascript
复制
_menuItems$: Observable<Menu>;

ngOnInit() {
  this._menuItems$ = this.menuService.getVerticalMenuItems();
}

MenuService

代码语言:javascript
复制
import {filter, map} from 'rxjs/operators';

...

getVerticalMenuItems(): Observable<Menu[]> {  

  return this.workoutService.getMenus().pipe(
    // this will avoid null/undefined values
    filter(Boolean),
    // this will avoid empty arrays comming from getMenus()
    // just comment it if empty arrays are allowed here
    filter(data => !!data.length),
    // here we're building the Menu array
    map((data:any) => data.map(i => new Menu(i.id, i.title, 
                                             i.routerLink, i.href,
                                             i.icon, i.target, 
                                             i.hasSubMenu, i.parentId))
  ); // here we're closing the pipe

}

通过这样做,我们将把订阅和取消订阅菜单服务的责任委托给async管道。

我不知道getMenu()在这里做什么。它会从服务器获取菜单数据吗?如果是这样的话,当应用程序启动时,在服务中缓存菜单数据不是比每次都去服务器更好吗?只是猜测一下,因为我不太清楚你是如何在你的应用程序中建立起来的。

更新

由于我漏掉了另一个错误,所以我在其他组件中添加了一些更多的更改。

VerticalMenuComponent

在该组件中,您有:

代码语言:javascript
复制
@Input('menuItems') menuItems;
@Input('menuParentId') menuParentId;

...

ngOnInit() {
  this.parentMenu = this.menuItems.filter(item => item.parentId == this.menuParentId); -- not working??
}

要成功初始化parentMenu,必须确保加载了menuItemsmenuParentId。在OnInit中这样做是不安全的。我提议的方式是非常可靠的,IMO (我在我的一些组件中使用它),并使用强大的RxJs。

更新的filter(Boolean) 2(不能用于menuParentId):

代码语言:javascript
复制
// We must save the received items and also emit it
@Input() 
set menuItems(items: Menu[]) {
  this._menuItemsLoaded$.next(items);
}
private _menuItemsLoaded$: ReplaySubject<Menu[]> = new ReplaySubject<Menu[]>(1);

// We must save the received items and also emit it
@Input() 
set menuParentId(items: number) {
  this._menuParentIdLoaded$.next(items);
}
private _menuParentIdLoaded$: ReplaySubject<number> = 
  new ReplaySubject<number>(1);

...

ngOnInit() {
  combineLatest(
    this._menuItemsLoaded$.pipe(
          filter(Boolean), 
          filter((_) => !!_.length), 
          debounceTime(300)),
    this._menuParentIdLoaded$.pipe(
          // for _menuParentId (exclusively) we cannot use 
          // filter(Boolean) here, or the 0 values will be blocked
          filter((_) => _ !== null && _ !== undefined),
          debounceTime(300)),
  ).subscribe(([menuItems, parentId]) => 
    this.parentMenu = menuItems.filter(item => item.parentId == parentId)
  );
}

// as we're using some subjects, we must finalize
// them in case this component is eventually destroyed
ngOnDestroy() {
  if(this._menuItemsLoaded$ && !this._menuItemsLoaded$.closed) {
    this._menuItemsLoaded$.complete();
  }

  if(this._menuParentIdLoaded$ && !this._menuParentIdLoaded$.closed) {
    this._menuParentIdLoaded$.complete();
  }
}

另一种方法

如果您认为上面的方法是压倒性的(我同意,但我认为习惯RxJ也很有帮助),并且您完全控制了VerticalMenuComponent及其@Input()的API,那么您可以考虑创建一个菜单组件数据接口,只传递一个参数:

代码语言:javascript
复制
export interface VerticalMenuComponentData {
  menuItems: Menu[];
  parentId: number;
}

...

// We must save the received items and also emit it
@Input() 
get verticalMenuComponentData: VerticalMenuComponentData { return this._verticalMenuComponentData; }
set verticalMenuComponentData(data: VerticalMenuComponentData) {
  this._verticalMenuComponentData = data;

  // You don't need to call anything inside ngOnInit
  this.parentMenu = data && data.menuItems && data.parentId 
    ? data.menuItems.filter(item => item.parentId == data.parentId) 
    : [];
}
private _verticalMenuComponentData: VerticalMenuComponentData;

然后,您应该稍微修改一下模板:

代码语言:javascript
复制
<app-vertical-menu (onClickMenuItem)="updatePS($event)"
                   [menuItems]="{menuItems: _menuItems$ | async, parentId: 0}">
</app-vertical-menu> 
票数 2
EN

Stack Overflow用户

发布于 2019-04-11 06:30:05

当调用订阅()时,您的代码不会停止等待服务器响应。相反,它继续执行getVerticalMenuItems()的其余部分。当http请求完成后,将执行作为subscribe()参数的函数。但这可能是一两秒钟后。所以您的console.log(--END OF SUBSCRIBE---)实际上不是真的,它不是subscribe()的结束,subscribe()在执行过程中还没有完成。

现在可以做的是:使resultMenu成为一个组件变量,并将数据保存在其中。然后,在html中,您可以正常使用该变量,例如:

代码语言:javascript
复制
<ul *ngFor="let menu of resultMenu">
  <li>
    //other code
    {{menu.title}}
  </li>
</ul>

角将检测到您的this.resultMenu已更改,并将自动更新视图(除非更改检测设置为onPush,则必须这样做)。您将看到您的菜单将在服务器响应后立即出现。

如果在显示数据之前必须对接收到的数据进行处理,则必须实现ngOnChanges并在那里这样做。每当组件的输入发生更改时,都会调用它。

这里是一个Stackblitz演示,查看控制台日志

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55611767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档