【问题标题】:Angular2 load configuration from backend on startupAngular2在启动时从后端加载配置
【发布时间】:2016-07-11 06:05:03
【问题描述】:

在我的 Angular2 应用程序中,我正在尝试使用 HTTP 在引导程序上从后端加载配置,以便我可以使用提取的数据来创建角度服务。

每当我尝试读取保存在我的配置中的 HTTP 响应时,我总是得到 TypeError: Cannot read property 'url' of undefined 错误。

似乎只有在整个引导方法完成时 HTTP 请求才完成,而我的代码试图在检索到 Observable 响应之前提取它。

如何修复它以从服务器中提取配置并在启动时使用它来创建角度服务? (我想用提取的数据在提供者内部创建服务)

如果有更好的方法在启动时从服务器中提取配置,请发表评论。

我的 ma​​in.ts 看起来像这样:

bootstrap(AppComponent, 
    [APP_ROUTER_PROVIDERS, HTTP_PROVIDERS, ConfigurationService, Config])
    .catch(err => console.error(err)
);

configuration.service.ts

@Injectable()
export class ConfigurationService {

    constructor(private http: Http) {
    }

    load() {
        return this.http.get('config/getConfig').map(response => response.json());
    }

}

config.ts

@Injectable()
export class Config {

    public config;

    constructor(public configurationService: ConfigurationService) {
        configurationService.load().subscribe(
            config => this.config = config,
            error => console.error('Error: ' + error)
        );
    }

    get(key: any) {
        return this.config[key];
    }
}

app.component.ts

@Component({
    selector: 'app',
    templateUrl: 'app/app.component.html',
    styleUrls: ['app/app.component.css'],
    directives: [ROUTER_DIRECTIVES],
    providers: [MyService]
})
export class AppComponent {

    constructor(public myService: MyService) {
    }

}

my.service.ts

@Injectable()
export class MyService{

    private url;

    constructor(public config: Config) {
        this.url = config.get('url');
    }
}

【问题讨论】:

标签: angular angular2-services


【解决方案1】:

您可以利用APP_INITIALIZER 服务在应用程序启动之前重新加载配置:

bootstrap(AppComponent, [
  {
     provide: APP_INITIALIZER,
     useFactory: (config:Config) => {
       return config.load();
     },
     dependency: [ Config ]
   }
]);

为此,您需要稍微调整一下您的 ConfigService 类:

@Injectable()
export class ConfigService {
  constructor(private http:Http) {}

  load() { // <------
    return new Promise((resolve) => {
      this.http.get(...).map(res=>res.json())
        .subscribe(config => {
          this.config = config;
          resolve();
        });
  }
}

然后您将能够直接访问应用程序中配置对象的属性。

【讨论】:

  • 我有一个非常相似的要求,我遵循了你上面的技术。但是,我发现load()函数是在app.component.ts的ngOnInit()之前调用的,但是配置数据是在之后加载的。如果我希望在ngOnInit 之前加载配置怎么办?
  • +1 请忽略我之前的评论。今天,当我清理 node_modules 文件夹并重新安装所有库时,它开始以正确的顺序工作。你是@Thierry 的男人
  • 我用 Angular 2.0 (Final) 创建了一个 plunkr。 plnkr.co/edit/U5LUZ0rRDcuCNJ5MBGwC
  • 顺便说一句,为什么 load() 会返回一个值,谁得到这个值,为什么?对我来说,没有它也能完美运行。
  • 在Angular4中怎么做?
【解决方案2】:

使用 AoT 编译时会引发错误,因为工厂是匿名函数。然后你需要做的是为工厂导出一个函数

export function ConfigLoader(configService: ConfigService) {
    return () => configService.load();
}

应用的配置如下所示:

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        HttpModule,
        BrowserModule
    ],
    providers: [
        ConfigService,
        {
            provide: APP_INITIALIZER,
            useFactory: ConfigLoader,
            deps: [ConfigService]
        }],
    bootstrap: [ AppComponent ]
})
export class AppModule {
}

参考https://github.com/angular/angular/issues/10789

【讨论】:

    【解决方案3】:

    这样写加载函数比较好

    public load() {
        let promise =this.http.get(url).map(res => res.json()).toPromise();
        promise.then(config =>  this.validation = config);
        return promise;
    };
    

    【讨论】:

    • 如何更好?
    • 这将如何处理相对/绝对 url 路径?
    • 答案是从 2017 年开始,我不再使用 angularjs。而且我想从那时起就有新版本的 angularjs
    猜你喜欢
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多