Есть ли способ «подписаться» на переменную массива изменений в Angular? - PullRequest
0 голосов
/ 26 февраля 2020

Я ищу способ дождаться, чтобы пользователь прекратил взаимодействие, а затем сделать HTTP-запрос, для этого я ищу оператор debounceTime() из Rx Js, но цель, которую я жду for это массив, который я определил.

Это сценарий:

export class KeywordSelectionComponent implements OnInit {

  constructor(private proposalService: ProposalService) { }

  @ViewChild(MatTable, {static: true}) kwTable: MatTable<any>;
  @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
  @Input() proposalId: string;

  keywordInput = new FormControl(null, Validators.required);

  dataSource: MatTableDataSource<Keyword>;
  displayedColumns = ['action', 'keyword', 'searches', 'competition', 'cpc'];
  suggestedKeywords: Keyword[] = [];
  selectedKeywords: string[] = [];

  fetchSuggestions(seeds?: string[]) {
    const ideas = {
      seeds: [],
      limit: 25
    };
    this.proposalService.getKeywordIdeas(this.proposalId, ideas).pipe(retry(3)).subscribe(res => {
      this.suggestedKeywords = res;
    });
  }

}

Я не включаю здесь весь компонент, но идея заключается в следующем:

У меня есть список suggestedKeywords, который я отображаю на странице, каждый из которых должен вызывать метод addKeyword(), чтобы добавить это ключевое слово в dataSource, и после этого я вызываю метод fetchSuggestions(), чтобы получить новые ключевые слова. заполнить список suggestedKeywords.

Проблема возникает, когда я пытаюсь выбрать несколько ключевых слов в быстрой последовательности, так как это вызовет запрос для каждого из этих кликов для обновления списка suggestedKeywords, поэтому я хотел использовать debounceTime() для предотвращения запуска запроса до тех пор, пока пользователь не прекратит нажимать элементы на некоторое время; однако для этого требуется, чтобы Observable изменял элемент, насколько мне известно, но в моем случае это просто простой массив.

Есть ли какой-то способ отслеживать значение массива, чтобы после изменения он ждет некоторое время, прежде чем сделать HTTP-запрос, например Observable?

EDIT : Использовал оператор from(), как предложено в комментариях, чтобы на самом деле слушать изменения мне нужно определить другие методы? Я думаю о чем-то похожем на valueChanges() в FormControls.

Просматривая больше документации, я склоняюсь к Subject, BehaviorSubject и т. Д .; но я не уверен, что это будет правильный подход, кто-нибудь может привести пример, как это сделать?

Ответы [ 2 ]

1 голос
/ 26 февраля 2020

Оберните ваш массив в операторе Observable.of () Rx JS, и он будет вести себя как наблюдаемый

0 голосов
/ 28 февраля 2020

В конечном итоге я использовал Subject для отслеживания изменений, вызывая его next() функцию каждый раз модифицированный массив suggestedKeywords и подписываясь на него как на наблюдаемый.

My компонент в итоге выглядел так:

export class KeywordSelectionComponent implements OnInit {

  constructor(private proposalService: ProposalService) { }

  keywordInput = new FormControl(null, Validators.required);
  suggestedKeywords: Keyword[] = [];
  selectedKeywords: string[] = [];
  isLoadingResults = false;

  tag$ = new Subject<string[]>();

  ngOnInit() {
    this.tag$.asObservable().pipe(
      startWith([]),
      debounceTime(500),
      switchMap(seeds => this.getSuggestionsObservable(seeds))
    ).subscribe(keywords => {
      this.suggestedKeywords = keywords;
    });
  }

  addSuggestedKeyword(keyword: Keyword) {
    const suggestedKeyword = keyword;
    const existing = this.dataSource.data;

    if (!existing.includes(suggestedKeyword)) {
      existing.push(suggestedKeyword);
      this.dataSource.data = existing;
    }

    this.tag$.next(this.getCurrentTableKeywords());
  }

  fetchKeywordSearch(keyword: string) {
    this.isLoadingResults = true;
    this.keywordInput.disable();
    const search = {
      type: 'adwords',
      keyword
    };
    const currentData = this.dataSource.data;

    this.proposalService.getKeywordSearch(this.proposalId, search).pipe(retry(3)).subscribe(res => {
      currentData.push(res);
      this.dataSource.data = currentData;
    }, error => {},
    () => {
      this.isLoadingResults = false;
      this.keywordInput.enable();
      this.tag$.next(this.getCurrentTableKeywords());
    });
  }

  getCurrentTableKeywords(): string[] {}

  getSuggestionsObservable(seeds: string[] = []): Observable<Keyword[]> {
    const ideas = {
      type: 'adwords',
      seeds,
      limit: 25
    };

    return this.proposalService.getKeywordIdeas(this.proposalId, ideas).pipe(retry(3));
  }

}
...