2

我将尝试使用异步管道来显示/隐藏一些等待消息。

app.component.html

<ng-template #isWait>
    <h1>Please wait</h1>
</ng-template>

<div *ngIf="wait | async; else isWait">
    <hello name="{{ name }}"></hello>

    <p>
        Start editing to see some magic happen :)
    </p>

</div>

<button (click)="toggle()">Toggle</button>

<!-- Doesn't change -->
<div style="margin:1rem;">
    Doesn't change here
    <span style="color:red;">Value is {{wait | async}}</span>
  (AppComponent)
</div>

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name: string = 'Angular 5';
  wait: Observable<boolean>;

  constructor(public waitService: WaitService) {
    this.wait = this.waitService.wait;
  }

  toggle() {
    this.waitService.toggle();
  }
}

等待服务.ts

export class WaitService {
  wait: Observable<boolean>;
  private _wait: boolean = false;
  private _onChange: EventEmitter<boolean> = new EventEmitter();

  constructor() {
    this.wait = Observable.create((obs: any) => {
      obs.next(this._wait);
      this._onChange.subscribe((w: boolean) => {
        if (this._wait !== w) {
          this._wait = w;
          obs.next(this._wait);
        }
      });
    });
  }

  toggle() {
    this._onChange.emit(!this._wait);
  }
}

我有带有等待属性的 WaitService 和用于切换等待的方法切换。当我尝试切换wait时,它在一种情况下有效,但对彼此不起作用(如我所料)。

所以,这让我很困惑。我会试着弄清楚为什么会发生。

示例:https ://stackblitz.com/edit/angular-fwghfj

如果您单击切换按钮,等待消息不会发生任何事情,但Wait2Component中的订阅将被发出,并且每次单击切换时都会写入控制台输出。

但是在订阅注释行后,显示和隐藏等待消息将正常工作,但在其他地方等待仍然没有变化。

当然,我可以将wait更改为布尔值,并且不关心使用async的这种情况,但这对我来说是出乎意料的行为。

4

3 回答 3

3

你可以这样写 WaitService :

import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs/BehaviorSubject";

@Injectable()
export class WaitService
{
    private readonly isWaiting = new BehaviorSubject(false);
    public readonly wait$ = this.isWaiting.asObservable();
    public toggle()
    {
        this.isWaiting.next(!this.isWaiting.value);
    }
}
于 2017-11-16T12:17:04.207 回答
1

问题是,对于每个订阅者,Observable.create都会调用回调,这就是您修改this._wait. 换句话说,当您调用'句柄时,例如调用toggle()。五次甚至更多。但是只有第一个调用会通知它的观察者,因为.this._onChange.subscribe()nextthis._wait !== w

避免这种情况的一种简单方法是与share()操作员共享相同的源 Observable。

this.wait = Observable.create((obs: any) => {
  // ...
}).share();

但更好的解决方案不是subscribe()在内部调用Observable.create,而是使用运算符链do()来执行任何副作用:

this.wait = this._onChange
  .filter((w: boolean) => w !== this._wait)
  .do((w: boolean) => this._wait = w)
  .share();

这应该产生相同的结果。

更新演示见:https ://stackblitz.com/edit/angular-nbgmz7?file=app%2Fservices%2Fwait.service.ts

于 2017-11-16T12:17:35.930 回答
0

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name: string = 'Angular 5';
  wait: Observable<boolean>;

  constructor(public waitService: WaitService) {
    this.wait = this.waitService.waitingStatus();
  }

  toggle() {
    this.waitService.toggle();
  }
}

您的服务

@Injectable()
export class WaitService {
  private currentWaitingStatus: boolean = false;
  private waitingStatus$: Subject<boolean> = new BehaviorSubject<boolean>(this.currentWaitingStatus)

  waitingStatus(): Observable<boolean> {
     return this.waitingStatus$
  }

  toggle() {
     this.currentWaitingStatus= !this.currentWaitingStatus
     this.waitingStatus$.next(this.currentWaitingStatus)
  }
}

我更喜欢有一个方法来返回我的财产,而不是把它公开。

因为,你的组件一定不知道你的服务内部是怎样的。如果您的服务被 n 个客户使用,明天您想更改您的财产的名称,您必须在任何地方更改它

否则,如果您将其抽象为一种方法,您将在服务中的一个地方更改juste

于 2017-11-16T13:20:44.463 回答