【问题标题】:Angular2: inject server side config into serviceAngular2:将服务器端配置注入服务
【发布时间】:2016-10-21 05:12:47
【问题描述】:

我在 ASP.NET Core 中使用带有 TypeScript 的 Angular 2.0.0。我的目标是基于服务器端变量在我的应用程序中创建 AppConfig 服务。在其他几个答案的帮助下,我能够创建以下代码:

Index.cshtml

<app>
    <i class="fa fa-spin fa-5x fa-spinner"></i>
</app>

<script>
    System.import('/app/main').then((m) => {
        var config = {
            apiUrl: @options.ApiServerUrl
        };

        m.RunApplication(config);
    }, console.error.bind(console));
</script>

app.config.ts

import { Injectable } from "@angular/core";

@Injectable()
export class AppConfig {
    apiUrl: string;
}

ma​​in.ts

import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppModule } from "./app.module";
import { AppConfig } from "./app.config";

export function RunApplication(config: Object) {

    var appConfig = new AppConfig();
    appConfig.apiUrl = config["apiUrl"];

    console.log('Created config: ', appConfig);

    platformBrowserDynamic()
        .bootstrapModule(AppModule, [{ providers: [{ provide: AppConfig, useValue: appConfig }] }])
        .catch(err => console.error(err));
}

app.module.ts

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { HttpModule } from "@angular/http";
import { AppRouting, AppRoutingProviders } from "./app.routes";
import { AppConfig } from "./app.config";
import { AppComponent } from "./app.component";
import { DashboardComponent } from "./dashboard/dashboard.component";
import { DashboardService } from "./dashboard/dashboard.service";

@NgModule({
    declarations: [
        AppComponent,
        DashboardComponent
    ],
    imports: [
        BrowserModule,
        HttpModule,
        AppRouting
    ],
    providers: [
        AppRoutingProviders,
        AppConfig,
        DashboardService
    ],
    bootstrap: [AppComponent],
})
export class AppModule { }

dashboard.service.ts

import { Http } from "@angular/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import "rxjs/add/operator/map";
import { AppConfig } from "../app.config";

@Injectable()
export class DashboardService {

    constructor(private appConfig: AppConfig, private http: Http) {
        console.log('Injected config: ', appConfig);
        console.log('Injected apiUrl: ', appConfig.apiUrl);
    }
}

Chrome 控制台的输出

正如您所见,由于某种原因创建和注入的AppConfig 不一样,apiUrl 的值不会出现在DashboardService 中。我怀疑这里的某个地方有错误:

bootstrapModule(AppModule, [{ providers: [{ provide: AppConfig, useValue: appConfig }] }])

但我对 Angular2 很陌生,不知道如何解决它。你能指出问题出在哪里吗?

【问题讨论】:

  • 听起来像 stackoverflow.com/questions/37611549/… 就是你要找的东西。
  • @vebbo 您是否根据 Günter 的反馈设法完成这项工作?
  • @SamJackSon 是的,通过将 appconfig 分配给全局“窗口”变量。绝对不是一个优雅的解决方案,但对我有用。

标签: angular typescript angular2-services angular2-di


【解决方案1】:

@NgModule() 中的 AppConfig 提供程序会影响传递给 bootstrapModule() 的提供程序

有了How to pass parameters rendered from backend to angular2 bootstrap method,你应该得到你想要的。

【讨论】:

  • 我对这条线有点困惑:useFactory: (config: ConfigService) =&gt; () =&gt; config.load()这里发生了什么?
  • 此外,无法找到 APP_INITIALIZER。不是已经弃用了吗?
  • 应该由@angular/coreangular.io/docs/ts/latest/api/core/index/…导出
  • 我可以在 app.module.ts 中 providers: [ AppRoutingProviders, AppConfig, { provide: APP_INITIALIZER, useFactory: (config: AppConfig) =&gt; () =&gt; { config.apiUrl = "http://localhost:26264"; return config; }, deps: [AppConfig], multi: true }, DashboardService ], 执行此操作,但我仍然不明白这如何帮助我从 index.html 传递参数
  • 这意味着bootstrapModule(AppModule, ...) 不接受... 的提供者。它实际上是 CompilerOptions 预期作为第二个参数。您需要将此提供程序移至@NgModule()。您可以将其分配给 window (window.appConfig = appConfig;) 上的属性,然后在 @NgModule(...) 从那里再次读取 ({ provide: AppConfig, useValue: window.appConfig })
【解决方案2】:

我最终将对象添加到全局变量中。

// ===== 文件 globals.ts

import { AppConfig } from './app.config';
'use strict';
export var appConfig: AppConfig;

// ===== 文件 app.config.ts

import { Injectable } from "@angular/core";
@Injectable()
export class AppConfig {
    entityId: string;
    formId: string;
}

// ===== 文件 index.html 或 cshtml

<script>
    System.import('app').then((m) => {
        var config = {
            entityId: '12',
            formId: '22'
        };
        m.RunApplication(config);
        },
        console.error.bind(console)
    );
</script>

// ===== 文件 main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';
import { AppConfig } from './app.config';
import myGlobals = require('./globals');

//platformBrowserDynamic().bootstrapModule(AppModule);

export function RunApplication(config: Object) {

    var appConfig = new AppConfig();
    appConfig.entityId = config["entityId"];
    appConfig.formId = config["formId"];

    console.log('Created config: ', appConfig, appConfig.entityId, appConfig.formId);

    myGlobals.appConfig = appConfig;

    platformBrowserDynamic()
        .bootstrapModule(AppModule)
        .catch(err => console.error(err));
}

// ===== 文件 app.module.ts

import { AppConfig } from './app.config';
import myGlobals = require('./globals');
...

@NgModule({
    imports: [
        ...
    ],
    declarations: [
        ...
    ],
    providers: [
        {
            provide: AppConfig,
            useValue: myGlobals.appConfig
        }
    ],
    bootstrap: [AppComponent]
})

// ===== 文件 intro.component.ts

import { AppConfig } from "./app.config";
import myGlobals = require('./globals');
@Component({
    selector: 'my-intro,[my-intro]',
    templateUrl: ''
})
export class IntroComponent {
    constructor() {
        console.log('constructor', 'appConfig', myGlobals.appConfig);
    }
}

【讨论】:

【解决方案3】:

使用加载配置设置的 Promise 使用 CanActivate 类保护您的路由也应该可以工作。

将 appSettings.service 与返回承诺的函数一起使用

getAppSettings(): Promise<any> {
        var observable = this.http.get(this.ApiUrl, { headers: this.headers })
            .map((response: Response) => {
                var res = response.json();
                return res;
            });

        observable.subscribe(config => {
        this.config= config;
        console.log(this.config)
        });
        return observable.toPromise();  
    }

CanActivate 守卫如下:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AppSettingsService } from './appsettings.service';

@Injectable()
export class CanActivateViaAuthGuard implements CanActivate {

//router: Router
    constructor(private appSettingsService: AppSettingsService)
    {
    }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
               return this.appSettingsService.getAppSettings().then(() => { 
    return true });
   }
}

这将确保您的设置在构建相应组件时可用。 (使用 APP_INITIALIZER 并没有限制被调用的构造函数,所以我不得不使用这个技术,另外请确保你不要导出模块中的所有组件:[])

为了保护路由并确保在调用构造函数之前加载设置,请在路由定义的路径中使用常用的 canActivate 选项

 path: 'abc',
 component: AbcComponent,
 canActivate: [CanActivateViaAuthGuard]

appsettings 的初始化应该在 AbcComponent 的构造函数被调用之前发生,这在 Angular 2.0.1 中已经过测试和工作

【讨论】:

  • 也可以使用检查来加载基于用户身份验证 true|false 或任何其他相关条件的设置
猜你喜欢
  • 2016-05-09
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
  • 2016-07-07
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多