Angular中useFactory无法获取异步加载的_locale值问题
解决Angular异步获取Locale导致LOCALE_ID注入失败问题
问题场景
尝试通过useFactory为LOCALE_ID注入LocaleService中的_locale值,但由于LocaleService中通过API请求异步赋值_locale,导致useFactory执行时_locale仍为undefined,触发以下错误:
message: InvalidPipeArgument: 'locale.toLowerCase is not a function' for pipe 'CurrencyPipe' , Error: InvalidPipeArgument: 'locale.toLowerCase is not a function' for pipe 'CurrencyPipe'
直接给_locale赋值固定值时功能正常,问题根源在于API请求的异步特性。需要等待API响应返回并完成_locale赋值后,再执行依赖LOCALE_ID的逻辑。
现有代码
LocaleService
import { Injectable } from '@angular/core'; import { SystemSettingsService } from 'src/app/system-settings/system-settings.service'; import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; import localeDeExtra from '@angular/common/locales/extra/de'; @Injectable({ providedIn: 'root', }) export class LocaleService { public _locale: string; public _localeSettings: any; constructor(private systemSettings: SystemSettingsService) { this.getLocaleSettings(); } getLocaleSettings() { this.systemSettings.getLocale().subscribe((data) => { this._localeSettings = data; this.setLocale(); }); } setLocale() { if (this._localeSettings.format === 1) { this._locale = 'de-De'; registerLocaleData(localeDe, 'de-DE', localeDeExtra); } else if (this._localeSettings.format === 2) { this._locale = 'en-US'; } } }
模块代码
import { NgModule, LOCALE_ID } from '@angular/core'; import { CommonModule, CurrencyPipe } from '@angular/common'; import { LocaleService } from './locale.service'; @NgModule({ declarations: [], imports: [ CommonModule, ], providers: [CurrencyPipe, { provide: LOCALE_ID, deps: [LocaleService], useFactory: (localeService: LocaleService) => localeService._locale }] }) export class MyModule { }
解决方案
核心思路是利用APP_INITIALIZER在Angular应用初始化阶段,等待LocaleService完成API请求和locale赋值,确保LOCALE_ID注入时已有有效值。
步骤1:修改LocaleService,添加初始化方法并返回Promise
调整服务逻辑,让初始化逻辑返回Promise,确保应用启动时等待请求完成:
import { Injectable } from '@angular/core'; import { SystemSettingsService } from 'src/app/system-settings/system-settings.service'; import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; import localeDeExtra from '@angular/common/locales/extra/de'; @Injectable({ providedIn: 'root', }) export class LocaleService { public _locale: string; public _localeSettings: any; constructor(private systemSettings: SystemSettingsService) { } // 新增初始化方法,返回Promise initializeLocale(): Promise<void> { return new Promise((resolve) => { this.systemSettings.getLocale().subscribe((data) => { this._localeSettings = data; this.setLocale(); resolve(); }, () => { // 请求失败时设置默认locale this._locale = 'en-US'; resolve(); }); }); } setLocale() { if (this._localeSettings.format === 1) { this._locale = 'de-De'; registerLocaleData(localeDe, 'de-DE', localeDeExtra); } else if (this._localeSettings.format === 2) { this._locale = 'en-US'; } else { // 兜底默认值 this._locale = 'en-US'; } } }
步骤2:配置APP_INITIALIZER和LOCALE_ID
在模块中配置APP_INITIALIZER,让应用初始化时等待LocaleService的异步操作完成,同时保持LOCALE_ID的注入逻辑:
import { NgModule, LOCALE_ID, APP_INITIALIZER } from '@angular/core'; import { CommonModule, CurrencyPipe } from '@angular/common'; import { LocaleService } from './locale.service'; // 定义初始化函数 export function localeInitializer(localeService: LocaleService) { return () => localeService.initializeLocale(); } @NgModule({ declarations: [], imports: [ CommonModule, ], providers: [ CurrencyPipe, { provide: APP_INITIALIZER, useFactory: localeInitializer, deps: [LocaleService], multi: true }, { provide: LOCALE_ID, deps: [LocaleService], useFactory: (localeService: LocaleService) => localeService._locale } ] }) export class MyModule { }
原理说明
APP_INITIALIZER会在Angular应用启动前执行指定函数,且会等待Promise完成后才继续初始化流程,确保_locale已完成赋值。- 增加了API请求失败的兜底逻辑,避免因接口异常导致应用无法启动。
内容的提问来源于stack exchange,提问作者Learner
相关产品推荐
相关产品推荐

