0

I try to build a keyword list from all existing keywords. I manage to retrieve them all and output them in the debug console.

I am confused about how and when to call resolve(taxonomyKeywords). I like to call it when all loops and their inner loops are finished. I tried using foreach, yet run in the same issue. Is my approach way off and there's a much easier way?

private searchKeyword(searchTerm: string, results: ITag[]) : ITag[] | Promise<ITag[]>
{
  return new Promise<IPersonaProps[]>( (resolve, reject) => {
    let taxonomyKeywords : ITag[] = [];

    this.props.taxonomyProvider.getTermStores().then( (stores: ITermStore[]) => {
      for(var store of stores )
      {
        this.props.taxonomyProvider.getTermGroups( store.id ).then( (groups: ITermGroup[]) => {

          for(var group of groups)
          {
            this.props.taxonomyProvider.getTermSets(group).then( (sets: ITermSet[]) => {
              for(var termSet of sets)
              {
                this.props.taxonomyProvider.getTerms(termSet).then( (terms: ITerm[]) => {
                  for(var term of terms)
                  {
                    if( term.name.indexOf(searchTerm) >= 0 )
                    {
                      taxonomyKeywords.push( { key: term.name, name: term.name} );
}}});}});}});}});});}
Dennis Kuhn
  • 239
  • 3
  • 10
  • 1
    You never should call `resolve`, as you should avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Jul 11 '17 at 06:02
  • 1
    You should be using `map` and `Promise.all`, not `forEach` – Bergi Jul 11 '17 at 06:02

1 Answers1

1

I think below pattern shall be better:

private function searchKeyword(searchTerm: string, results: ITag[]): ITag[] | Promise<ITag[]> {

    return this.props.taxonomyProvider
        .getTermStores()
        .then((stores: ITermStore[]) => {
            return Promise.all(stores.map(s => this.props.taxonomyProvider.getTermGroups(s.id)));
        })
        .then((groups: Array<ITermGroup[]>) => {

            const flattenGroups: ITermGroup[] = groups.reduce((p, c) => p.concat(c), []);

            return Promise.all(flattenGroups.map(g => this.props.taxonomyProvider.getTermSets(g)));
        })
        .then((sets: Array<ITermSet[]>) => {
            const flattenSets: ITermSet[] = sets.reduce((p, c) => p.concat(c), []);

            return Promise.all(flattenSets.map(s => this.props.taxonomyProvider.getTerms(s)));
        })
        .then((terms: Array<ITerm[]) => {
            const flattenTerms: ITerm[] = terms.reduce((p, c) => p.concat(c), []);
            return flattenTerms
                .filter(t => t.name.indexOf(searchTerm) >= 0)
                .map(t => ({ key: t.name, name: t.name }));
        });
}

You should learn how promise work

Howard
  • 4,474
  • 6
  • 29
  • 42
  • Re: "learn how `promise` work" - I am trying to :-) It's more the mapping thing. I give your pattern a go ... Thanks a lot already :-) – Dennis Kuhn Jul 11 '17 at 06:13
  • 1
    This doesn't work. Those `taxonomyProvider.getXY` methods all return promises, and you cannot just return an array of promises from `then` – Bergi Jul 11 '17 at 06:27
  • I think that is the error I am getting now: `Error - typescript - : error TS2345: Argument of type '(groups: ITermGroup[][]) => Promise[]' is not assignable to parameter of type '(value: Promise[]) => Promise[] | PromiseLike[]>'.` – Dennis Kuhn Jul 11 '17 at 06:29
  • Awesome thanks a lot that worked like a charm and I am learning :-) – Dennis Kuhn Jul 11 '17 at 07:24