Правильное использование flatMap - будет эффективнее mergeMap или concatMap - PullRequest
0 голосов
/ 13 марта 2019

Как я уже говорил в прошлом, я новичок в программировании и пытаюсь научить себя Angular - возможно, это приведет к новой карьере!Я создаю приложение для себя, чтобы справиться с веб-разработкой.В настоящее время я пытаюсь использовать автозаполнение материала в форме, чтобы, когда пользователь добавляет / вставляет значение в текстовый ввод, событие keyup также прослушивается в наблюдаемой, которая выполняет вызов API, который возвращает некоторые данные, и я использую возвращенную датузаполнить автозаполнение (у меня есть 3 на моей странице).Это моя HTML-форма ...

<form novalidate [formGroup]="assignmentForm">
      <div>
        <input type="text" matInput placeholder="User" formControlName="worker" name="worker" [matAutocomplete]="workerTemplate" #worker>
        <mat-autocomplete #workerTemplate="matAutocomplete">
          <mat-option *ngFor="let worker of workerTags" [value]="worker">{{ worker.displayName}}</mat-option>
        </mat-autocomplete>
      </div>

      <div>
        <input type="text" matInput placeholder="Company" formControlName="company" name="company" [matAutocomplete]="companyTemplate" #company>
        <mat-autocomplete #companyTemplate="matAutocomplete">
          <mat-option *ngFor="let company of companyTags" [value]="company">{{company.displayName}}</mat-option>
        </mat-autocomplete>
      </div>

      <div>
        <input type="text" matInput placeholder="Department" formControlName="department" name="department" [matAutocomplete]="departmentTemplate" #department>
        <mat-autocomplete #departmentTemplate="matAutocomplete">
          <mat-option *ngFor="let department of departmentTags" [value]="department">{{department.displayName}}</mat-option>
        </mat-autocomplete>
      </div>
    </form>

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

public companyTags: any[];
public departmentTags: any[];
public workerTags: any[];

@ViewChild('company')
private companyEl: ElementRef;
@ViewChild('department')
private departmentEl: ElementRef;
@ViewChild('worker')
private workerEl: ElementRef;
private assignmentSubscription: Subscription;

constructor(private apiService: ApiService) {}

public ngOnInit() {
  const companySource = fromEvent(this.companyEl.nativeElement, 'keyup');
  const departmentSource = fromEvent(this.departmentEl.nativeElement, 'keyup');
  const workerSource = fromEvent(this.workerEl.nativeElement, 'keyup');

  const tagsSource = merge(companySource, departmentSource, workerSource)
    .pipe(
      debounceTime(500),
      distinctUntilChanged(),
      flatMap((ev: KeyboardEvent) => {
        // if the user presses backspace the value is "" and all results are returned (to set limit)
        if ((<HTMLInputElement>ev.target).value !== '') {
          return this.apiService.getTags((<HTMLInputElement>ev.target).name, (<HTMLInputElement>ev.target).value, 3)
        }

        return of([]);
      }),
    );

  this.assignmentSubscription = tagsSource.subscribe((res) => {
    this.clearAllTags();
    if (res.length > 0) {
      // the type is contained in the array so we can determine which array we need to populate
      // we can use interpolation rather than a horrible if then else
      this[`${res[0].type}Tags`] = res;
    }
  });
}

public clearAllTags(): void {
  this.companyTags = null;
  this.departmentTags = null;
  this.workerTags = null;
}

Это все работает, но мне интересно, если это самый эффективный способ сделать это?Я немного читал о flatMap, mergeMaop и concatMap, и я не уверен, какой метод лучше всего использовать в моем случае?Также я должен поместить логику, содержащуюся в flatMap где-то еще, так как кажется, что это не то место?Я не уверен, как бы я это сделал, используя chaing или добавив другой метод в канал (.do?).Любые советы и мысли будут оценены.Если я не вижу смысла или плохо формулирую свой вопрос, пожалуйста, укажите это, и я перепишу / отредактирую.Большое спасибо заранее.

1 Ответ

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

На самом деле вы должны использовать switchMap вместо concatMap или flatMap, flatMap сохранит внутреннюю наблюдаемую работу и значение выброса, даже если есть новое значение, поступающее из исходного ввода, в вашем случае с клавиатуры ввода,Таким образом, то, что пользователь в конечном итоге увидит на экране, будет мигать его последний входной результат + последний результат.

например, когда вы пытаетесь найти «яблоко», вы получаете «приложение» через исходные данные, тогда api будет искать «приложение», но перед возвращением api вы набрали «le» и теперь должнывернуть результат для «яблоко».Если в этом случае используется flatMap, он сначала отобразит результат для «приложения», а затем быстро изменится на «яблоко».Принимая во внимание switchMap, поисковый запрос API 'app' будет пропущен (на самом деле не отменять, а не выдавать значение), и вместо этого будет возвращаться поиск 'apple'.

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