Использование SwitchMap () для обработки отмены предыдущих запросов - PullRequest
0 голосов
/ 14 декабря 2018

У меня есть функция в приложении Angular2, где пользователь может выбирать различные фильтры для фильтрации данных, возвращаемых в виде сетки.Это получение и фильтрация данных работает.Однако мне нужно найти способ - предпочтительно использовать RxJS и что-то вроде switchMap() для отмены запросов при внесении изменений в выбор фильтров - чтобы только самый последний запрос передавался по проводам.

Мне было трудно заставить это работать.Поэтому сначала мне нужно определить, является ли моя текущая конфигурация действительно наблюдаемой RxJS, а затем, где подключить оператор, такой как switchMap().

. Вот как выглядит мой код:

private sendRequest = _.debounce((languageFilter, locationFilter, zipFilter, firstNameFilter, lastNameFilter, branchFilter) =>
{
    this.filtersService.getByFilters(
        this.page - 1, this.pagesize, this.currentStage, this.language = languageFilter, this.location = locationFilter,
        this.zipcode = zipFilter, this.firstName = firstNameFilter, this.lastName = lastNameFilter,
        this.branch = branchFilter,
        (resRecordsData) => {
            this.records = resRecordsData;
         });
 }, 200);

public onFilterReceived(values)
{
    let languageFilter = [];
    let locationFilter = [];
    let zipFilter = [];
    let firstNameFilter = [];
    let lastNameFilter = [];
    let branchFilter = [];

     this.route.params.subscribe(
         (params: any) => {
             this.page = params['page'];
             this.pn_zip_e = params['pn_zip.e'];
             this.pn_firstName_e = params['pn_firstName.e'];
             this.pn_lastName_e = params['pn_lastName.e'];
             this.pn_location_e = params['pn_location.e'];
             this.pn_branch_e = params['pn_branch.e'];
             this.pn_language_e = params['pn_language.e'];
         }
     );

     this.pn_language_e === "1" ? languageFilter = values['language'] : languageFilter = [];
     this.pn_location_e === "1" ? locationFilter = values['location'] : locationFilter = [];
     this.pn_zip_e === "1" ? zipFilter = values['zip'] : zipFilter = [];
     this.pn_firstName_e === "1" ? firstNameFilter = values['firstName'] : firstNameFilter = [];
     this.pn_lastName_e === "1" ? lastNameFilter = values['lastName'] : lastNameFilter = [];
     this.pn_branch_e === "1" ? branchFilter = values['branch'] : branchFilter = [];

     this.sendRequest(languageFilter, locationFilter, zipFilter, firstNameFilter, lastNameFilter, branchFilter);
};

Функция getByFilters(), вызываемая из моего filtersService, выглядит следующим образом:

public getByFilters(page, pagesize, stage?, language?, location?, zipcode?, firstName?, lastName?, branch?, fn?: any)
{
    return this.apiService.get({
      req: this.strReq, reqArgs: { page, pagesize, stage, language, location, zipcode, firstName, lastName, branch }, callback: fn });
}

И это, в свою очередь, вызывает запрос GET в нашей центральной службе контроллера запросов (apiService), который выглядит следующим образом:

public get(args: {
    req: string,
    reqArgs?: any,
    reqBody?: any,
    callback?: IRequestCallback
}): Observable<Response>
{
    args['reqType'] = 'get';
    return this.runHttpRequest(args);
}

Как только я получу свой ответ, я присваиваю его «this.records», а затем использую его в своем представлении, чтобы перебрать «this.records.data» - массив, чтобы напечатать мои записина экран.

Итак, из моего кода выше, в этой строке я получаю ответ и присваиваю его «this.records»:

  this.records = resRecordsData;

Итак, мой первый вопрос:как мне определить, есть ли у меня RxJS, наблюдаемый здесь - и как мне использовать оператор, такой как switchMap(), для обработки отмены предыдущих запросов фильтра?

Я пробовал это, но это не работает.Я предполагаю, что синтаксис неверен:

private sendRequest = _.debounce((languageFilter, locationFilter, zipFilter, firstNameFilter, lastNameFilter, branchFilter) =>
{
    this.streamFiltersService.getByFilters(
        this.page - 1, this.pagesize, this.currentStage, this.language = languageFilter, this.location = locationFilter,
        this.zipcode = zipFilter, this.firstName = firstNameFilter, this.lastName = lastNameFilter,
        this.branch = branchFilter,
         (resRecordsData) => {
            resRecordsData.switchMap((res) => {
                this.records = res;
            });
            console.log('records: ', this.records);
         });
 }, 200);

Прежде всего, чтобы убедиться, что я лаю нужное дерево, я хотел бы иметь возможность определить, является ли ответ, который я имею здесь, на самом деленаблюдаемый RxJS.И, если нет, найдите способ преобразовать его в один, чтобы я мог затем использовать switchMap() на нем.

1 Ответ

0 голосов
/ 14 декабря 2018

Я создал реальный случай для switchMap и два ввода с реактивной формой.Это можно адаптировать с помощью fromEvent(inputElement,'change') вместо this.inputElement.valueChanges.

// We want combine of all lastest values.
combineLatest(
  // We merge default name with observable of name input.
  merge(
    of('default'),
    // From input we want to be inform after 200ms debounce and if they have change.
    this.name.valueChanges.pipe(debounceTime(200), distinctUntilChanged())
    ),
  // We merge default choice with observable of choice input.
  merge(
    of('value 1'),
    this.choice.valueChanges.pipe(debounceTime(200), distinctUntilChanged())

  )
).pipe(map(e => {
  // We construct the request payload
  return {
    name: e[0],
    choice: e[1]
  }
  // Ignore combined default value, ask api and subscribe to answer.
})).pipe(skip(1), switchMap(e => this.myApi(e))).subscribe(console.log);

Чтобы быть уверенным в понимании каждого шага, я настоятельно рекомендую вам разбить его на составную переменную и console.log для каждого подписанного потока.Пример:

Наблюдаемый ввод

this.name.valueChanges.pipe(debounceTime(200), distinctUntilChanged()).subscribe(console.log)

выдаст вам текущее значение ввода после отката 200 мс, и если значение изменилось, сравните с предыдущим испущеннымone.

Ввод наблюдаемый со значением по умолчанию

merge(
    of('default'),
    this.name.valueChanges.pipe(debounceTime(200), distinctUntilChanged())
),

Мы объединяем немедленное значение по умолчанию с будущим значением, полученным во входном потоке.

CombineLatest

из предыдущего составного слияния, мы хотим объединить последнее излученное значение из каждого входа в один поток.

map

.pipe(map(e => {
  // We construct the request payload
  return {
    name: e[0],
    choice: e[1]
  }
  // Ignore combined default value, ask api and subscribe to answer.
})

потому что CombineLatest создаст массив последнего испущенного потока, предоставленного в качестве параметра. Мы хотим отобразить этот массив в объект реальной полезной нагрузки для вашего API.

switchMap

switchMap(e => this.myApi(e)))

У вас есть полезная нагрузка (производите по карте, описанной ранее), вы трансформируете ее в новую наблюдаемую.Теперь вы можете просто подписаться, и волшебным образом вы получите ответ своей базы API на свою коллекцию входных значений и автоматически отмените предыдущий запрос, который больше не актуален.

живой образец


Чтобы быть базой на вашем маршруте Params, вы можете сделать что-то вроде этого.

  ngOnInit() {
    // From url params change, we map output with default value.
    const routeParams$ = this.route.params.pipe(map(params => {
      return {
        user: '',
        choice: '',
        ...params
      };
    }));
    // Uncomment me to see it in action.
    // routeParams$.subscribe(console.log);
    // Transform this payload to http request and subscribe to it.
    routeParams$.pipe(switchMap(e => this.myApi(e))).subscribe(console.log);
  }

Live sample

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...