当条件发生变化时重新运行管道以进行观察(角度7)

时间:2019-02-28 21:38:45

标签: angular rxjs

我有一个要根据用户输入的字段进行过滤的表,并且该表的源是由BehaviorSubject制成的可观察对象。设置如下:

class Component {
    //filled with a http call to a webservice
    private subject$ = new BehaviorSubject([])
    public state = 'Open';
    public workOrders$ = this.subjects$.asObservable().pipe(map(orders => {
        return orders.filter(f => f.State == this.state)
    }));
}

,重复的tr的HTML是

<tr *ngFor="let order of workOrders$ | async">

以及状态输入字段的HTML

<input type="text" [(ngModel)]="state" />

在初始加载时,这可以按状态正确过滤所有工作订单,但是每当this.state发生变化时,我都希望该管道重新过滤数组以更新表。完成此类任务的最佳实践是什么?我不想突变主题,因为当过滤器再次更改时,我需要保留原始数据集。

3 个答案:

答案 0 :(得分:0)

您可以使用rxjs combineLatest函数,并且可以观察到需要重新计算的情况:

private subject$ = new BehaviorSubject([])
public state = 'Open';
public stateSubject = new BehaviorSubject(this.state);

public workOrders$ = combineLatest(
    this.subjects$,
    this.stateSubject,
    (orders, state) => {
        return orders.filter(f => f.State == state)
    }
);

然后在您的输入上:

<input type="text" (ngModelChange)="stateSubject.next($event)" [(ngModel)]="state" />

答案 1 :(得分:0)

您提到state来自一个输入字段,这意味着(假设FormsModule是导入的,应该考虑ngModel),我们可以将该值作为Observable获得。

您可以使用switchMap订阅一个Observable,将其发射映射到另一个Observable,并让结果Observable从第二Observable发出值,直到第一个Observable再次发出(您 switch 到新的Observable)。

根据表单的设置方式,甚至是使用(keyup)绑定,您可以通过多种不同的方式从表单控件中获取“值的可观察值”。没有 ngForm在附加到控件的模板中声明,您只需通过模板绑定查询ngModel

<input type="text" [(ngModel)]="state" #value="ngModel"/>

然后在您的组件中

类组件{

@ViewChild('value') value: NgModel;

//filled with a http call to a webservice
private subject = new BehaviorSubject([])

public state = 'Open'; // This remains as a component property, but we don't need it for the Observable stream as we'll get the value changes Observable from the form control.

public workOrders = this.subject.asObservable().pipe(
    switchMap(this.value.valueChanges),
    withLatestFrom(this.subject),
    map([inputValue, orders] => {
        return orders.filter(f => f.State === inputValue.value)
    }));
}

您还可以从http调用和输入值更改中分别管理预订,但这很无聊。

但是...

如您所见,以上内容有些复杂;我们需要withLatestFrom来保留http调用的值,我假设该值一经收到即为静态。由于您使用的是标记中的async管道来订阅和调用Observable,因此最好只过滤另一个管道的结果,这可能是一个更好的设计选择!

@Pipe({name: 'filterState'})
  export class FilterStatePipe implements PipeTransform {
      transform(value: YourTypeHere[], state: string) {
          return value.filter(s => s.State === state);

      }
}

然后在模块中声明它,并在标记中使用它,如下所示:

<input type="text" [(ngModel)]="state" />

<tr *ngFor="let order of workOrders$ | async | filterState:state">

async为您解包了Observable,然后您的自定义管道将根据state的值过滤该值。 state更改后,应重新运行管道。

答案 2 :(得分:0)

您需要订阅输入值的更改 可以通过将表单(假设输入字段在表单内)转换为反应形式,或在输入值发生变化时调用函数来完成此操作。 有关反应式的更多信息,请参见here 我将介绍第二种最简单的方法: HTML

<input type="text" (ngModelChange)="dataChanged()" [(ngModel)]="state" /> 

TS

class Component {
//filled with a http call to a webservice
private subject$ = new BehaviorSubject([])
public state = 'Open';
public allorders
//Variable to hold all the subjects before applying any filter
this.subjects$.asObservable().subscribe( val => {
    this.allorders = val
  })
}

dataChanged(){
    this.allorders.filter(f => f.State == this.state)
  }));
}