【问题标题】:angular 4 async pipe is not working角度 4 异步管道不工作
【发布时间】:2017-09-27 03:42:21
【问题描述】:

我正在尝试使用异步管道,但没有显示数据。我正在记录来自服务器的数据,它在控制台中显示良好。但由于某种原因,我无法让异步工作。

shift.service.ts

import { Injectable } from '@angular/core';
import { Shift } from '../shift/shift';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ShiftService {

  constructor(private shift:Shift, private httpClient:HttpClient
              ) { this.checkShiftStatus();}

  checkShiftStatus():Promise<Shift>{
    this.httpClient.get<Shift>('http://localhost:8080/shift/isopen')
      .subscribe((data) => {
        this.shift = data;
        console.log(this.shift);
      },
      error => {
        console.error('Something went wrong while trying to check the shift!');
      });
    return Promise.resolve(this.shift);
  }
}

shift.component.ts

import { Component, OnInit } from '@angular/core';
import { Shift } from './shift';
import { ShiftService } from '../services/shift.service';

@Component({
  selector: 'app-shift',
  templateUrl: './shift.component.html',
  styleUrls: ['./shift.component.css']
})
export class ShiftComponent implements OnInit {
  isShiftOpen:Promise<boolean>;

  shiftLive:Promise<Shift>;

  constructor(private shiftService: ShiftService, public shift:Shift) { }

  ngOnInit() {
    this.isShiftOpen = this.getShift().then(shift => this.shift.active = shift.active);
    this.shiftLive = this.shiftService.checkShiftStatus();
  }

  getShift(){
    return this.shiftService.checkShiftStatus().then(shift => this.shift = shift);
  }
}

shift.component.html

<md-grid-list *ngIf="isShiftOpen | async" cols="2" rowHeight="100px">
  <md-grid-tile>
      <button md-raised-button [disabled]='isShiftOpen' color="primary">Open Shift</button>
      <button md-raised-button [disabled]='!isShiftOpen' color="warn">Close Shift</button>
  </md-grid-tile>
</md-grid-list>

<md-card class="card">
  <md-card-title>
    Shift Stats:
  </md-card-title>
  <md-card-content>

    </md-card-content>
</md-card>
<!-- <div *ngIf="(shiftLive | async)?.notnull; else loading"> -->
<div *ngIf="shiftLive | async">
    <p> Shift status: {{ shiftLive.active }} </p>

    <p> Tickets Sold: {{ shiftLive.totalNumberOfTicketsSold }} </p>
</div>
<ng-template #loading>Loading Data...</ng-template>

即使服务提供的值为 true,按钮也不会显示。我确实让 div 显示,但 shiftLive.active 或 shiftLive.totalNumberOfTicketsSold 没有价值。

【问题讨论】:

    标签: angular


    【解决方案1】:

    您在结果异步传入之前解决了 Promise,并且 Promise 仅解决一次。您需要返回未解决的承诺并等待结果进来,然后解决您的承诺,如下所示:

    checkShiftStatus():Promise<Shift>{
      let promise = new Promise<Shift>();
      this.httpClient.get<Shift>('http://localhost:8080/shift/isopen')
        .subscribe((data) => {
          this.shift = data;
          promise.resolve(this.shift);
          console.log(this.shift);
        },
        error => {
          console.error('Something went wrong while trying to check the shift!');
        });
      return promise;
    }
    

    然后你在你的组件中使用承诺是错误的。您正在定义和设置范围之外的变量。异步管道为您处理所有这些。

    或者更好的是,根本不要使用 promise,因为 observables 要好得多

    服务:

    // just return the observable stream and don't subscribe, let async handle your subscriptions
    checkShiftStatus():Observable<Shift>{
      return this.httpClient.get<Shift>('http://localhost:8080/shift/isopen')
        .do((data) => {
          // you really shouldn't do this. statefulness like this is a sign of bad design
          this.shift = data;
          console.log(this.shift);
        }).catch(err => {
         console.log('make sure to handle this error');
         Observable.throw(err);
       });
    }
    

    组件:

    // only set this once so that we don't make the same http call over and over, we have all the data we need here (the $ syntax is standard for denoting an observable)
    this.shiftLive$ = this.shiftService.checkShiftStatus();
    

    模板:

    //only use async once to avoid multiple subscriptions, and declare it "as" whatever you want, and then you have access to it throughout the template, you can still use your loading template as you want.
    <ng-container *ngIf="shiftLive$ | async as shiftLive; else loading"> 
    <md-grid-list *ngIf="shiftLive.active" cols="2" rowHeight="100px">
      <md-grid-tile>
          <button md-raised-button [disabled]='shiftLive.active' color="primary">Open Shift</button>
          <button md-raised-button [disabled]='!shiftLive.active' color="warn">Close Shift</button>
      </md-grid-tile>
    </md-grid-list>
    
    <md-card class="card">
      <md-card-title>
        Shift Stats:
      </md-card-title>
      <md-card-content>
    
      </md-card-content>
    </md-card>
    
    <div>
        <p> Shift status: {{ shiftLive.active }} </p>
    
        <p> Tickets Sold: {{ shiftLive.totalNumberOfTicketsSold }} </p>
    </div>
    <ng-template #loading>Loading Data...</ng-template>
    </ng-container>
    

    【讨论】:

    • 我做了您建议的更改并尝试运行该程序。但最终出现错误说明 ERROR TypeError: Cannot read property 'active' of undefined at Object.eval [as updateRenderer] (ShiftComponent.html:18) at Object.debugUpdateRenderer [as updateRenderer] 。在我使用的服务中 this.httpClient.get('localhost:8080/shift/isopen');现在只有这么多代码。甚至没有试图捕捉错误。有什么建议么?谢谢。
    • 在包含 *ngIf="shiftLive$ | async as shiftLive; 否则在 div 部分加载它开始工作正常。但是你对它进行多次 http 调用服务器是正确的。
    • 您只需订阅一次,就像我向您展示的那样。无需将该可观察流拆分为两个调用。所有需要的信息都在同一个调用中
    • 材料导致问题。在 md-grid 中移动 div 后,我只需要进行一次 http 调用。感谢您的帮助!
    【解决方案2】:

    我猜你在 shift.service.ts 的 checkShiftStatus 方法中返回了一个未定义的值

    return Promise.resolve(this.shift);
    

    你应该这样重构你的方法:

    checkShiftStatus(): Observable<Shift>{
      return this.httpClient.get<Shift>('http://localhost:8080/shift/isopen')
    }
    

    然后对 shift.component.ts 和 shift.component.html 中的数据做一些事情:

    export class ShiftComponent implements OnInit {
    
      shift: any;
    
      constructor(private shiftService: ShiftService, public shift:Shift) { }
    
      ngOnInit() {
        this.getShift();
      }
    
      getShift(): void {
        this.shiftService.checkShiftStatus()
          .subscribe(shift => this.shift = shift);
      }
    
      isActive(): boolean {
        return this.shift && this.shift.active;
      }
    
      ticketsSold(): number {
        return this.shift ? this.shift.totalNumberOfTicketsSold : 0;
      }
    }
    

    <md-grid-list *ngIf="isActive()" cols="2" rowHeight="100px">
      <md-grid-tile>
        <button md-raised-button [disabled]='isActive()' color="primary">Open Shift</button>
        <button md-raised-button [disabled]='!isActive()' color="warn">Close Shift</button>
      </md-grid-tile>
    </md-grid-list>
    
    <md-card class="card">
      <md-card-title>
        Shift Stats:
      </md-card-title>
      <md-card-content>
      </md-card-content>
    </md-card>
    <!-- <div *ngIf="shift?.notnull; else loading"> -->
    <div *ngIf="shift">
      <p> Shift status: {{ isActive() }} </p>
      <p> Tickets Sold: {{ ticketsSold() }} </p>
    </div>
    <ng-template #loading>Loading Data...</ng-template>
    

    【讨论】:

    • 异步管道是订阅 observables 的更清洁、更安全和首选的方法
    猜你喜欢
    • 2021-02-02
    • 2021-10-19
    • 2019-04-10
    • 2016-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    • 2021-07-08
    相关资源
    最近更新 更多