How to use a promise value for an array filter method?

I need to return the boolean result of a file readAsText promise to an array filter method. The promise returns the correct value, based on the inputs. But I do not know how to get a value for the “return” function. First is the called function, followed by the array filter code segment. The ??? on the “return” indicates the value I need to fill in, for the filter method to work. If I replace the ??? manually with true or false, the filter method works fine. So how do I get the “found” variable out of the promise and into the “???” value?

  phraseFound(path: string, phrase: string) {
    let panelMediaFile = 'panelMedia_' + this.global.langAbbv + '.json';    // e.g. "panelMedia_en.json"
//    
    return  this.file.readAsText(this.global.fileSystem.int + path, panelMediaFile).then((jsonStr) => {
              let found = (jsonStr.toLowerCase().indexOf(phrase) == -1) ? false : true;
              return found;   //found = TRUE
            }).catch((err) => { this.global.showError('t10', err); });
  }

        filteredItems = filteredItems.filter( item => {
          let tapaSrcPath = this.global.path.titles + item.titleURI + '/tapaSrc/';
          let found = this.phraseFound(tapaSrcPath, searchTermsPhrase)
            .then(found => {
              return found;
            });
          return ???;
        });

Thank you in advance!

P.S. Here is the complete method:

  searchSortTapaskills(searchTerms: string, isFilter: boolean): any {
    searchTerms = (searchTerms == undefined) ? '' : searchTerms;
    this.searchFiltered = (searchTerms != '');
//   
    let array: any = this.global.tapaskills;
    if(!array) return [ ];   // if empty list, then return an empty list
    let filteredItems = [ ];
//
    if(this.searchFiltered) {    // filter first for performance of sort
      searchTerms = searchTerms.toLowerCase();
      filteredItems = array;
      if (isFilter) {
        let searchTermsPhrase = searchTerms;   // for efficiency, only search for entire phrase
        filteredItems = filteredItems.filter( item => {
          let tapaSrcPath = this.global.path.titles + item.titleURI + '/tapaSrc/';
          let found = this.phraseFound(tapaSrcPath, searchTermsPhrase)
            .then(found => {
              return found;   //found = TRUE
            });
          return found;   //found = promise object
        });
      } else {
        let searchTermsArr: string[ ] = searchTerms.split(' ');   // space delimited
        for (let idx=0; idx < searchTermsArr.length; idx++) {   // loop thru all words
          filteredItems = filteredItems.filter( item => {
            return item.title.toLowerCase().includes(searchTermsArr[idx]);    // only filter the title
          });
        };
      };   //...(2019-04-18)//
    } else {
      filteredItems = array;
    };
//
    let sortColumn = this.sortColumn;
    let sortOrder = this.sortOrder;
//
    return filteredItems.sort(function(a, b){   // finally sort what remains
      let property = sortColumn;
      if(a[property] < b[property]){
          return -1 * sortOrder;
      }
      else if( a[property] > b[property]){
          return 1 * sortOrder;
      }
      else{
          return 0;
      }
    });
  }    //...(2019-04-13)//

Hi, @KioMio
Please elaborate your question what exactly the problem you face in the code and what do you want as a result so, that I can help you.

Can you edit your post and show proper complete methods, as it looks like you might have to use async,await keywords for your job?

Thank you for responding. I have tried to add what you requested. Hope it helps.

Thank you for responding. I also thought that the await keyword might help, but did not know how to implement it. I added the complete method.

ok, I could help but your code looks messy. Can you indent your code?

Sorry, I have not used this editor before. I found out how to use preformatted text.

ok, this looks good. I will let you know in some time.

ok, you cannot use async methods in array filter as it is synchronous. Instead you could loop through each item one by one and use await keyword. Make changes as mentioned below:

  • First, return a promise from your phraseFound method like below:
phraseFound(path: string, phrase: string) {
    let panelMediaFile = 'panelMedia_' + this.global.langAbbv + '.json';    // e.g. "panelMedia_en.json"
//    
    return  new Promise((resolve) => {
    			this.file.readAsText(this.global.fileSystem.int + path, panelMediaFile).then((jsonStr) => {
	              	resolve(jsonStr.toLowerCase().indexOf(phrase) === -1);
	            }).catch((err) => { 
	            	this.global.showError('t10', err); 
	            });
    		});
}
  • Second, loop through your filteredItems items one by one and use the await keyword to wait for the promise to return the value.
var filtered_results = [];
for(var i=0;i<filteredItems.length;++i){
	let tapaSrcPath = this.global.path.titles + filteredItems[i].titleURI + '/tapaSrc/';
	let found = await this.phraseFound(tapaSrcPath, searchTermsPhrase).then((found) => {
		      		return found;
		    	});
	if(found){
		filtered_results.push(filteredItems[i]);
	}
}

filteredItems = filtered_results;
  • Third, since you are using await in the second step, you will need to change searchSortTapaskills to async searchSortTapaskills.

This should do the trick for you.

Wow! That is some great programming and insight. I will try this out. Thank you.

1 Like

Thank you! Your idea worked perfectly. I simplified the function as follows:

  async phraseFound(path: string, phrase: string) {
    let panelMediaFile = 'panelMedia_' + this.global.langAbbv + '.json';    // e.g. "panelMedia_en.json"
    let jsonStr = await this.file.readAsText(this.global.fileSystem.int + path, panelMediaFile);
    let found = (jsonStr.toLowerCase().indexOf(phrase) == -1) ? false : true;
    return found;
  }

1 Like

Glad to help :slight_smile: Yes, this certainly makes your code much more concise. Well done!