Труба RERUN для наблюдения при изменении состояния (Angular 7) - PullRequest
0 голосов
/ 01 марта 2019

У меня есть таблица, которую я фильтрую на основе введенного пользователем поля, а источником этой таблицы является наблюдаемая, созданная из объекта 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)
    }));
}

и HTML для повторяемого tr:

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

и HTML для поля ввода для состояния

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

При начальной загрузке это корректно фильтрует все рабочие задания по состоянию, но всякий раз, когда изменяется this.state, я хочу, чтобы этот канал повторно фильтровал массив для обновления таблицы.Какова наилучшая практика для выполнения такого рода задач?Я не хочу изменять объект, потому что мне нужно сохранить исходный набор данных для повторного изменения фильтра.

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Вы упомянули, что state было из поля ввода, что означает (предполагая, что FormsModule импортируется, что следует учитывать ngModel), мы можем получить это значение в качестве наблюдаемого.

Вы можете использовать switchMap, чтобы подписаться на одну Наблюдаемую, сопоставить ее выбросы со второй Наблюдаемой и получать результирующие значения излучения Наблюдаемой от второй Наблюдаемой, пока первая Наблюдаемая не испустит снова (вы переключаетесь на новую Наблюдаемую).

Вы можете получить Observable изменений значений из своего элемента управления формы несколькими различными способами в зависимости от того, как настроена форма, или даже просто с помощью привязки (keyup).Не указав ngForm в шаблоне, прикрепленном к элементу управления, вы можете просто запросить ngModel через привязку шаблона:

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

, а затем в своем компоненте:

class Component {

@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 изменяется, труба должна быть перезапущена.

0 голосов
/ 01 марта 2019

Вам необходимо подписаться на изменения входного значения. Это можно сделать, либо преобразовав форму (при условии, что поле ввода находится внутри формы) в реактивную форму, либо вызвав функцию всякий раз, когда изменяется входное значение. Дополнительная информацияна реактивных формах можно найти здесь Я перейду ко второму и самому простому способу: 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)
  }));
}
0 голосов
/ 01 марта 2019

Вы можете использовать функцию rxjs CombinLatest и иметь заметный трек, который необходимо пересчитать:

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" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...