Shahrukh Shahid
Shahrukh Shahid

Reputation: 418

Check Store before API call NgRx Angular

I am creating NgRx application but I am quite confused about its implementation as it is my first app with NgRx. I have a store with "Companies" state. I gotta search the companies and return if found. If the required company is not found it should call the API and fetch the results likewise but the process is circular and runs infinite time.

Here is my code:

    this.companySearchCtrl.valueChanges
      .pipe(
        debounceTime(300),
        distinctUntilChanged()
      )
      .subscribe(val => {
        if (val !== ' ' || val !== '') {
          this.store.select(getCompanys).subscribe(data => {
            console.log(data);
//filter companies on the basis of search text
            const filteredData = data.filter(x =>
              x['name']
                .toLowerCase()
                .startsWith(this.companySearchCtrl.value.toLowerCase())
            );
            console.log(filteredData);
            if (filteredData.length === 0) { //if data is not found in store
              console.log('got a call');
              this.store.dispatch(
                new CompanyActions.find({
                  where: { name: { regexp: `${val}/i` } } // call to API to search with regExp
                })
              );
            } else {
// if required data found in store
              console.log('got no call');
              this.filteredCompanies$ = of(filteredData);
            }
          });
        }
      });

This process runs fine if data is found in store. If data is not found in store or I dont get any results from API call it runs infinitely. How can I make this correct?

Upvotes: 5

Views: 3693

Answers (2)

tlt
tlt

Reputation: 15271

Make a few conventions:

  1. state.Companies = null is initial state if no request to server has been sent yet
  2. state.Companies = [] is state after first request was sent but no companies returned from server
  3. use createSelector that filters your companies based on criteria you need
  4. use withLatestFrom in your effects which will enable you to check store state within effects

Now, turn the logic the other way around:

  1. when you look for companies, first fire an action that will trigger effects
  2. in that effect, check if state.Companies is null or not
  3. if its null > fire api request
  4. if its not null > fire an action that will trigger selector for filtering
  5. if data was not found even if state.Companies was not null that means either you need to refresh your Companies collection or the value doesn't exist on server

Upvotes: 5

Rana Khurram
Rana Khurram

Reputation: 29

Create another action named dataNotFound. If you found data then set its state isFound to true and if data does not find, set its state isFound to false and always before sending call with regex check isFound that either data was found in previous call or not. If data was not found then don't send call again.

I've made a little bit change in your code to manage this. You just have to create an action dataNotFound now.

     this.companySearchCtrl.valueChanges
          .pipe(
            debounceTime(300),
            distinctUntilChanged()
          )
          .subscribe(val => {
            if (val !== ' ' || val !== '') {
              this.store.select(getCompanys).subscribe(data => {
                console.log(data);
    //filter companies on the basis of search text
                const filteredData = data.filter(x =>
                  x['name']
                    .toLowerCase()
                    .startsWith(this.companySearchCtrl.value.toLowerCase())
                );
                console.log(filteredData);
                if (filteredData.length === 0) { //if data is not found in store
                  console.log('got a call');
                  this.store.select(isDataFound).subscribe(isFound => {
                      if(isFound) {
                          this.store.dispatch(
                          new CompanyActions.find({
                       where: { name: { regexp: `${val}/i` } } // call to API to 
                                                                search with regExp
                    })
                  );
                      } else {
                          this.store.dispatch(new CompanyActions.dataNotFound({isFound: false}));
                      } 
                  });

                } else {
    // if required data found in store
                  console.log('got no call');
                  this.store.dispatch(new CompanyActions.dataNotFound({isFound: true}));  
                  this.filteredCompanies$ = of(filteredData);
                }
              });
            }
          });

Upvotes: 3

Related Questions