angular - How to hydrate data from dynamic imports? - Stack Overflow

admin2025-04-25  1

In my Angular app I need to fetch different menus depending on the language selected (can't use i18n), and I'm currently using this code to do so:

protected readonly menuItems = signal<LibHeaderMenuItem[]>([]);

ngOnInit() {
  import(`./menus/menus.${this.applicationManager.lang}.ts`).then(m => {
    this.menuItems.set(m.default);
  });
}

// NOTE: Greatly simplified for readability
@for (item of menuItems(); track item.href) {
  <a [routerLink]="item.href">{{item.label}}</a>
}

Which works fine, with the problem that when rendered with SSR this will run both on the server and client, resulting in the menu flickering on initial load since Angular can't properly hydrate this data. If I only run the import code on the server, I get the data initially, but then it becomes completely empty once the JS is loaded on the client.

The only way I can think of to solve this is to use JSON files and load them with HttpClient instead, but then I lose type safety in each menu file, and given the complexity of the data this would be quite risky.

Is there any way to make Angular properly hydrate data that comes from dynamic imports, just like they do with data from http requests?

EDIT: I tried using the old TransferState which seems to do the trick, but this feels a bit dirty, and something that would eventually get deprecated(?) since provideClientHydration is supposed to take care of this for you.

In my Angular app I need to fetch different menus depending on the language selected (can't use i18n), and I'm currently using this code to do so:

protected readonly menuItems = signal<LibHeaderMenuItem[]>([]);

ngOnInit() {
  import(`./menus/menus.${this.applicationManager.lang}.ts`).then(m => {
    this.menuItems.set(m.default);
  });
}

// NOTE: Greatly simplified for readability
@for (item of menuItems(); track item.href) {
  <a [routerLink]="item.href">{{item.label}}</a>
}

Which works fine, with the problem that when rendered with SSR this will run both on the server and client, resulting in the menu flickering on initial load since Angular can't properly hydrate this data. If I only run the import code on the server, I get the data initially, but then it becomes completely empty once the JS is loaded on the client.

The only way I can think of to solve this is to use JSON files and load them with HttpClient instead, but then I lose type safety in each menu file, and given the complexity of the data this would be quite risky.

Is there any way to make Angular properly hydrate data that comes from dynamic imports, just like they do with data from http requests?

EDIT: I tried using the old TransferState which seems to do the trick, but this feels a bit dirty, and something that would eventually get deprecated(?) since provideClientHydration is supposed to take care of this for you.

Share Improve this question edited Jan 15 at 7:13 Chrillewoodz asked Jan 15 at 7:01 ChrillewoodzChrillewoodz 28.4k23 gold badges100 silver badges187 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

provideClientHydration should work correctly if you request data via HttpClient.

I hope your menus.en.ts can be menus.en.json instead (i.e. it doesn't contain any nonserializable code).

then just put it to assets folder (or any other folder that will be copied to the build otput) and request it via httpClient

http = inject(HttpClient);
langs$ = this.http.get(`/assets/menus.${this.lang}.json`)
转载请注明原文地址:http://anycun.com/QandA/1745595894a90949.html