Search code examples
aureliaaurelia-store

Aurelia store - UI indicator that state is changing


I'm trying to refactor a Aurelia app to use the Aurelia Store plugin rather than a singleton class which is injected to all my viewmodel classes. In my current app there are a bunch of service classes which make ajax calls to fetch data from web api. Using promise chaining when making the call it was easy to pause the UI while stuff was loading, e.g.

this.isLoading = true;
this.api.getStuff()
  .then(s => this.myproperty = s.stuff)
  .catch(a => console.error("hgssgg"))
  .finally(() => this.isLoading = false);

Now that I have moved my API calls into my store actions, how can I represent this loading in my UI?

Apologies for basic question. Any help is much appreciated.


Solution

  • That is a perfectly fine approach. Generally you should prefer local state over global (plugin) state as long as the feature is only used by a single component. So if you have lets say an element which is the only component responsible for rendering the loader image, it's certainly a good way to keep it only local to that component via a property isLoading.

    Now as you mentioned there might come the time where you need to access that state from various places in your app, thats when you want to promote it to global state. Or, and that is the benefit of encapsulating the loader in a custom element, let the consumer conditionally show the loader element. On top of that store the loading state and the loading mechanism in a service which you expose via DI.

    // loading-service.ts
    export class LoadingService {
      showLoader: boolean = false;
    
      public async yourLoadingMechanism() {
        this.showLoader = true;
        await fetchYourDataAsync();
        this.showLoader = false;
      }
    }
    
    // consumer-view.ts
    export class ConsumerView {
      constructor(loadingService: LoadingService) {}
    }
    
    // consumer-view.html
    <template>
      <button click.delegate="loadingService.yourLoadingMechanism()>Fetch data</button>
      <status-loader show.bind="loadingService.showLoader"></status-loader>
    </template>
    

    I personally think there is no 100% this or that. Using the store plugin does not necessarily mean you have to go all-in on global state management but can and should use classic services in conjunction where you see fit. Above approach not only encapsulates the loading indicator but also helps you to refactor data access into a single place. If the service itself needs to listen to state changes you can even create your subscription in there and do what is needed.