使用异步管道

时间:2017-09-07 13:04:15

标签: angular rxjs angular-template

如果没有observable,我可以在HTML模板中编写以下行:

<div *ngIf="(myVarA || myVarB) && myVarC !== x"></div>

如果所有myVar变量现在实际上都是可观察的,我该如何翻译这一行?

<div *ngIf="((myVarA | async) || (myVarB | async)) && (myVarC | async) !== x">

不起作用。

在另一个问题(Putting two async subscriptions in one Angular *ngIf statement)中,可以实现将两个或多个可观察量组合成一个ngIf的可能性,如

<div *ngIf="{ a: myVarA | async, b: myVarB | async } as result"></div>

但是,我没有看到在表达式上使用任何布尔运算符(或任何运算符)的可能性,然后用于计算ngIf。

我该如何解决这个问题?请注意,我的所有Observable都使用下面的BehaviorSubject。我认为我想要的是在模板中使用combineLatest运算符。

额外奖励:如果整个表达式的计算结果为true,以便以后在模板中使用(如myVarA | async as varA),有没有办法提取myVarA的单个值?

3 个答案:

答案 0 :(得分:8)

如何使用combineLatest

例如:

import { combineLatest } from 'rxjs/observable/combineLatest';
import { Observable } from 'rxjs/Observable';    

@Component({...})
export class FooComponent {
  obs1$: Observable<bolean>;
  obs2$: Observable<bolean>;
  obs3$: Observable<bolean>;

  constructor(){
    // set observables
  }

  get combined$(){
    return combineLatest(
      this.obs1$,
      this.obs2$
      this.obs3$,
      (one,two,three)=>(one || two) && three);
  }
}

// template
<div *ngIf="combined$ | async">

检查以下小提琴以获取指导:

https://jsfiddle.net/uehasmb6/11/

有关combineLatest运算符here

的详细信息

更新:但如果您仍想将所有逻辑保留在模板中,您可以尝试以下方法:

<div *ngIf="((myVarA | async) || (myVarB | async)) && ((myVarC | async) !== x)">

但我建议你不要这样做。保持HTML模板尽可能干净是good practice

答案 1 :(得分:0)

Jota.Toledo的回答非常好,但是我想跟进关于如何在ngIf之后访问表达式的一部分的“奖金”问题。

基本上我所做的就是将类中的两个或多个observable组合为Jota.Toledo所描述的。但是,一个observable不是布尔值,但包含在ngIf之后需要可用的项目。

然后很容易做到以下几点:

<div *ngIf="newObs | async as item"></div>

因为我们可以依赖于ngIf中非空对象的真实性。然后ngIf看起来像

public class CarDataExtractor {

   private final Car car;

   private CarDataExtractor(Car car) {
       this.car = car;
   }

  public static CarDataExtractor on(Car car) {
       return new CarDataExtractor(car);
   }

   public EngineDataExtractor engine() {
       return car != null && car.getEngine() != null
               ? EngineDataExtractor.on(car.getEngine())
               : EngineDataExtractor.on(null);
   }

   public Car self() {
       return car;
   }
}

public class EngineDataExtractor {

   private final Engine engine;

   private EngineDataExtractor(Engine engine) {
       this.engine = engine;
   }

   public static EngineDataExtractor on(Engine engine) {
       return new EngineDataExtractor(engine);
   }

   public PowerDataExtractor engine() {
       return engine != null && engine.getPower() != null
               ? PowerDataExtractor.on(engine.getPower())
               : PowerDataExtractor.on(null);
   }

   public Engine self() {
       return engine;
   }
}

...

Power power = CarDataExtractor.on(dao.getCar()).engine().power().self()

如果在ngIf之后需要多个项目,这当然不起作用。在这种情况下,您必须在嵌套的div部分上使用两个ngIfs。

答案 2 :(得分:0)

为常见的AND / OR / ALL逻辑创建助手可观察的“生成器”

首先,放置paymentSelected == false && mode == 'addPayment'很简单,但是当您需要添加新条件时,必须在多个位置更新UI。

最好公开一个称为showPaymentPanel$的可观察对象,然后在.ts和模板文件中清楚地说明其用途:*ngIf="showPaymentPanel$ | async"。这也使测试更加容易。

但是我最终得到了很多这样的代码:

showTokenizedPaymentMethods$ = combineLatest(this.hasTokenizedPaymentMethods$, 
                                             this.showAvailablePaymentMethods$).
                              pipe(map(([ hasTokenizedMethods, showAvailableMethods ]) => 
                              showAvailableMethods && hasTokenizedMethods));

那真是一团糟!甚至比多个异步管道还差!

所以我创建了辅助函数来生成新的可观察对象 :(全局某处)

export const allTrue = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.every(v => v == true) ), distinctUntilChanged());
export const allFalse = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.every(v => v == false) ), distinctUntilChanged());
export const anyTrue = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.find(v => v == true) != undefined ), distinctUntilChanged());
export const anyFalse = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.find(v => v == false) != undefined), distinctUntilChanged());

注意:这些不是在管道中使用的运算符。

在ts文件中,您可以按以下方式创建可观察对象(命名为特定于用户界面):

public showPaymentPanel$ = allTrue(this.hasTokenizedPaymentMethods$, this.showAvailableMethods$);

即使存在现有的可观察对象,我通常也会创建UI可观察对象:

public showAccountDetails$ = this.isLoggedIn$;     // this condition is always subject to change

您还可以编写它们:

public showSomethingElse$ = allTrue(this.showPaymentPanel$, this.whateverItIs$);

有时候,我会将它们显示在这样分组的用户界面中:

public ui = { this.showPaymentPanel$, this.showSomethingElse$ );

然后的用法:

`*ngIf="ui.showPaymentPanel$ | async"` 

(只有ui应该是公开的,因此在模板中它可以使您非常清楚地知道要允许的内容)

尽可能限制在一个管道内!