Stateful Pipes

There are two categories of pipes:

  • Stateless pipes are pure functions that flow input data through without remembering anything or causing detectable side-effects. Most pipes are stateless. The CurrencyPipe we used and the length pipe we created are examples of a stateless pipe.

  • Stateful pipes are those which can manage the state of the data they transform. A pipe that creates an HTTP request, stores the response and displays the output, is a stateful pipe. Stateful Pipes should be used cautiously.

Angular provides AsyncPipe, which is stateful.

AsyncPipe

AsyncPipe can receive a Promise or Observable as input and subscribe to the input automatically, eventually returning the emitted value(s). It is stateful because the pipe maintains a subscription to the input and its returned values depend on that subscription.

  1. @Component({
  2. selector: 'app-root',
  3. template: `
  4. <p>Total price of product is {{fetchPrice | async | currency:"CAD":true:"1.2-2"}}</p>
  5. <p>Seconds: {{seconds | async}} </p>
  6. `
  7. })
  8. export class AppComponent {
  9. fetchPrice = new Promise((resolve, reject) => {
  10. setTimeout(() => resolve(10), 500);
  11. });
  12. seconds = Observable.of(0).concat(Observable.interval(1000))
  13. }

View Example

Implementing Stateful Pipes

Pipes are stateless by default. We must declare a pipe to be stateful by setting the pure property of the @Pipe decorator to false. This setting tells Angular’s change detection system to check the output of this pipe each cycle, whether its input has changed or not.

  1. // naive implementation assumes small number increments
  2. @Pipe({
  3. name: 'animateNumber',
  4. pure: false
  5. })
  6. export class AnimateNumberPipe implements PipeTransform {
  7. private currentNumber: number = null; // intermediary number
  8. private targetNumber: number = null;
  9. transform(targetNumber: number): string {
  10. if (targetNumber !== this.targetNumber) {
  11. this.currentNumber = this.targetNumber || targetNumber;
  12. this.targetNumber = targetNumber;
  13. const difference = this.targetNumber - this.currentNumber
  14. Observable.interval(100)
  15. .take(difference)
  16. .subscribe(() => {
  17. this.currentNumber++;
  18. })
  19. }
  20. return this.currentNumber;
  21. }
  22. }

View Example

原文: https://angular-2-training-book.rangle.io/handout/pipes/stateful_and_async_pipes.html