有没有一种方法可以“订阅” Angular中的数组变量更改?

时间:2020-02-25 21:44:43

标签: javascript angular typescript rxjs debouncing

我正在寻找一种等待用户停止交互然后发出HTTP请求的方法,为此,我正在寻找来自RxJs的debounceTime()运算符,但我正在等待的目标是我定义的数组。

这是场景:

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)?

编辑:如注释中所建议的,使用了from()运算符,为了实际收听更改,我是否需要定义其他方法?我在想类似于valueChanges()中的FormControls

浏览更多文档,我倾向于SubjectBehaviorSubject等;但是我不确定这是否是正确的方法,谁能提供一个有关如何执行此操作的示例吗?

2 个答案:

答案 0 :(得分:1)

将数组包装到Observable.of()RxJS运算符中,其行为将类似于Observable

答案 1 :(得分:0)

我最终要做的是使用Subject跟踪更改,将其next()函数称为evrytime,将其修改为suggestedKeywords数组,并按照可观察的方式进行订阅。 / p>

我的组件最终看起来像这样:

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));
  }

}