0

My Angular app have some modules, which are loaded lazily. In a component of module A, I'd like to check whether the module is loaded or not before rendering all html tags in the component with *ngIf. How can I do that? Thank you.

UPDATE 1.

export class CustomerManModule extends AppModuleBase {
  constructor(injector: Injector) {
    super(injector, AppConsts.module.customerMan);

    var localeName = locale();
    this.appService.getLanguage(localeName, AppConsts.module.customerMan).subscribe((messages: any) => {
      let language = new Object();
      language[localeName] = messages;
      loadMessages(language);
    })
  }
}

After I call loadMessages function, all localization strings will be loaded and I'd like to load these ones only one time when module loaded. After that, all components of that module need to check if those strings are loaded or not to continue rendering.

duyan
  • 63
  • 1
  • 8
  • If you're asking about a global loader, take a look this SO:https://stackoverflow.com/questions/54135784/how-to-implement-a-global-loader-in-angular – Eliseo May 31 '21 at 06:21
  • Thank you. But this is not my case. – duyan May 31 '21 at 07:13
  • Are we talking about a Component inside of moduleA or is it from a different module? – ChrisY May 31 '21 at 07:57
  • Yes, it's inside module A. In constructor of module A, I load some data from database for whole module. All components of that module need to check if data is ready before rendering themselves. – duyan May 31 '21 at 08:01
  • Ah okay. Then I think my answer kind of wrong bc you don't wait for the lazy module to load but for the data, that you'r requesting. I don't have time for an update now. Maybe this helps in the meantime: When you load data from a database you most likely use the HttpClient from Angular. There you get an Observable back. You can store this Observable in a custom service and access it from your component via the Async Pipe. https://angular.io/api/common/NgIf (search for async) – ChrisY May 31 '21 at 11:45
  • Hi @ChrisY. Please see my UPDATE 1. Can your approach do that? I emphasize that I only want to load all localization strings for each module only one time. If I use Promise or Observable in components, I have to load them many times, right? – duyan Jun 01 '21 at 03:27
  • @duyan I have updated the answer, sorry for the delay – ChrisY Jun 06 '21 at 15:31

1 Answers1

1

When the a Module is loaded its constructor is called.

So you can create a custom ModuleStateService, inject it in the constructor of the module and keep track of its state.

Example:

@NgModule({
  imports: [CommonModule, SharedServicesModule],
  declarations: [LoginComponent]
})
export class AuthModule {
  constructor(moduleStateService: ModuleStateService) {
    console.log('AuthModule loaded');
    
    moduleStateService.loadedModule('AuthModule');
  }
}

Update Sorry for the late update.

You can use a Route Resolver in combination with a service that uses some simple caching mechanism, like shareReplay(1) so that the request is only made once.

//Resolver

@Injectable({
  providedIn: 'root'
})
export class LocalizationResolver implements Resolve<Observable<any>> {
  constructor(private languageService: LanguageService) {}

  resolve(): Observable<any> {
    return this.languageService.loadMessages();
  }
}
// Service, with simplified caching

@Injectable({
  providedIn: 'root'
})
export class LanguageService {
  private cache = {};
  private url = 'https://api.github.com/users';

  constructor(private http: HttpClient) {}

  loadMessages(): Observable<any> {
    if (this.cache['messages']) {
      return this.cache['messages'];
    }
    this.cache['messages'] = this.http.get(this.url).pipe(shareReplay(1)); // todo error handling
    return this.cache['messages'];
  }
}
// Route configuration:

const ROUTES = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', component: ContainerComponent },
   ...
  {
    path: 'resolver',
    component: WithResolverComponent,
    resolve: { users: LocalizationResolver }
  }
];

Stackblitz

ChrisY
  • 1,681
  • 10
  • 12
  • Thanks for your answer. This one can check whether the module is loaded or not. But how can I continue rendering the component? How can the component wait for the module loaded to continue rendering? – duyan May 31 '21 at 07:17
  • you can create a resolver which listens to an observable with a `pipe(filter())` on the boolean being observed. This way the route wouldn't load until the module is loaded. If you don't want to block the route, but just the content, you can do the same just with a `*ngIf` internally in the component's template – Mikkel Christensen May 31 '21 at 08:44
  • Do I have to create the resolver for each component or I can use a common resolver? I don't like to create multiple resolvers. Please show me an example if I can use a common resolver for all components. Thanks. – duyan May 31 '21 at 09:01