【问题标题】:Pass Page/Global Variables into Angular2 app for use with services将页面/全局变量传递到 Angular2 应用程序以与服务一起使用
【发布时间】:2016-02-05 02:02:41
【问题描述】:

我在这里寻找一些最佳实践。我的 angular2 应用程序将存在于现有的内容管理系统中。因此,我需要捕获此 CMS 生成的一些“变量”(如身份验证令牌等),并将它们与我的 angular2 应用程序中的 http 请求一起使用。

当 CMS 显示 index.html 页面时,CMS 会对其进行预解析,并在页面发送到浏览器之前替换一些标记(即 [ModuleContext:ModuleId])。

这是我的 index.html 页面的示例(略):

<!-- 2. Capture CMS values to pass to app -->
<script type="text/javascript">
    var moduleId = parseInt("[ModuleContext:ModuleId]");
    var portalId = parseInt("[ModuleContext:PortalId]");
    var sf = $.ServicesFramework(moduleId);
</script>

<!-- 3. Configure SystemJS and Bootstrap App-->
<script type="text/javascript">
    System.config({
        packages: {
            //sets the root path of the Angular2 App
            'DesktopModules/KrisisShifts/app': {
                format: 'register',
                defaultExtension: 'js'
            }
        },
        map: { 'app': './app' }
    });
    System.import('app/boot')
            .then(null, console.error.bind(console));
</script>
<shift-app>Loading...</shift-app>

特别是 $.ServicesFramework 用于生成有效的 http web.api 请求。我想在可以注入到每个使用它的组件中的服务中捕获它。

例如(我正在使用打字稿):

import {Injectable} from 'angular2/core';
import {OnInit} from 'angular2/core';

@Injectable()
export class dnnService implements OnInit{

    sf: any;

    constructor() {}

    ngOnInit() {
        if ($.ServicesFramework) {
            this.sf = $.ServicesFramework(moduleId);
        };
    }

}

一个问题是打字稿编译器会抛出找不到“$”等错误。我可以通过在打字稿类声明之前使用声明来强制它工作,如下所示:

//Global Variable Declarations
declare var $: any;
declare var moduleId: any;

问题:

有什么更好的方法(如果存在)来捕获这些“全局”变量,以便在可以很好扩展的应用程序中使用。


编辑 - 更新到 RC6

我在 RC6 中使用了以下内容:

@NgModule({
declarations: [
    AppComponent,
    FormatDatePipe,
    ShiftPartialPipe 
],
imports: [
    BrowserModule,
    RouterModule.forRoot(AppRoutes),
    FormsModule,
    ReactiveFormsModule,
    HttpModule 
],
bootstrap: [AppComponent],
providers: [
    { provide: LocationStrategy, useClass: HashLocationStrategy },
    { provide: dnnModId, useValue: moduleId },
    { provide: dnnPortalId, useValue: portalId },
    { provide: dnnEditMode, useValue: editMode },
    { provide: dnnSF, useValue: $.ServicesFramework(moduleId) }
]
})

【问题讨论】:

  • 您对declare var ...parseInt("[ModuleContext:ModuleId]") 有疑问吗?
  • 它是关于最佳实践的。我展示的是工作,但我想知道其他人是否有更好的方法来完成同样的事情,主要是将全局或页面级别的 javascript 变量放入 angular2 服务(这样可以对其进行测试)
  • @JKing 你找到更好的方法了吗?我正在尝试使用新的 cli(使用 Webpack)定义一个标准,但我仍在努力……它也适用于相同的用例:DNN、http 标头等,理想情况下是自动模块 ID 检测跨度>
  • @iJungleBoy 我做到了。我不得不放弃 @inject 的做法。我今天不在电脑旁。我明天会发布它是如何工作的。
  • @JKing 你如何在客户端var moduleId = parseInt("[ModuleContext:ModuleId]"); 中呈现服务变量,就像这样。我从昨天开始就想知道怎么做。我将变量存储在视图中,想在客户端使用此变量。

标签: typescript angular angular2-services


【解决方案1】:

更新 >= RC.6

在 RC.6 中引入 @NgModule() 提供者被添加到那里而不是 boostrap(...). Alsoprovide()` 被弃用和删除以支持对象文字语法:

在共享库中定义

import {OpaqueToken} from '@angular/core';

export let SF = new OpaqueToken('sf');
@NgModule({
  providers: [{provide: SF, useValue: $.ServicesFramework(moduleId)},
  directives: [...]
  ...
})
class SomeModule {}

提供者也可以添加到组件和指令中

@Component({
   providers: [
    {provide: SF, useValue: $.ServicesFramework(moduleId)},
   ]);
})
class SomeComponent {}

将其注入到组件、指令、管道或服务中

constructor(@Inject(SF) private sf:string) {}

原创

在共享库中定义

import {OpaqueToken} from '@angular/core';

export let SF = new OpaqueToken('sf');

bootstrap()添加

// import SF from shared library

罢工>

bootstrap(AppComponent, [
    // other providers
    provide(SF, {useValue: $.ServicesFramework(moduleId)}),
    ]);

你想在哪里使用它

// import SF from shared library

 constructor(@Inject(SF) private _sf: string){ }

这利用了 Angulars DI 并避免了使代码难以测试的硬编码依赖项。

另见

提示: 也可以使用纯字符串代替OpaqueToken。使用OpaqueToken 可以防止名称冲突,例如,如果它用于许多用户使用的开源包中。如果您控制了整个环境,那么您可以确保自己不会发生冲突,并且应该安全地使用字符串而不是 OpaqueToken

更新

引入了具有泛型支持的InjectionToken 以替换现已弃用的OpaqueToken

【讨论】:

  • @Günter Zöchbauer 纯字符串是什么意思?你能解释一下吗?
  • @GünterZöchbauer 知道了,我将我的令牌存储在 View(asp.net core) 中作为var message = "@ViewBag.Token" 我如何在客户端使用这个消息值?
  • 抱歉,我不明白您的问题或“此消息”与依赖注入有何关系。我建议使用足够的代码创建一个新问题,以演示您尝试完成的工作、尝试的内容以及失败的地方。
【解决方案2】:

为了稍微扩展 Gunther 的回答,我在 RC5 中也这样做了,除了不是将它添加到 bootstrap() 中的提供程序(来自以前的版本),而是将令牌作为提供程序放置在新的 @ngModule 装饰器中正在做引导。例如:

@NgModule({
    bootstrap: [MyComponent],
    declarations: [MyComponent],
    imports: [BrowserModule],
    providers: [
        { provide: OpaqueToken, useValue: someObject }
    ]
})
export class AppModule { }

browserDynamicPlatform().bootstrapModule(AppModule);

【讨论】:

  • 感谢 Jerome - 对新的 rc5 进行了很好的澄清 - 我认为最终版本将保持这种方式
  • 实际上这个 provide() 在 rc6 中已被弃用和删除。正确的做法真的是:` providers: [ { provide: yOpaqueToken, useValue: someObject } ] `
【解决方案3】:

不确定这是否是最佳做法,但我遇到了同样的问题,我正在使用的解决方案(RC5 就绪)如下:

第 1 步)将您的设置类创建为 @Injectable:

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

   @Injectable()

   export class MyAppSharedSettings {

        appName: string = "My Application Name";
        appTitle: string = "My Application Title";
        appVersion: string = "1.0.0.0 beta";
        welcomeMessage: string = "Welcome";
        userName: string = "";
   }

第 2 步)在您的主模块上,如果您还没有这样做,请导入以下内容:

 //Imports required for NgModule directive
 import { NgModule }                          from '@angular/core';
 import { BrowserModule }                     from '@angular/platform-browser';
 import { HttpModule }                        from '@angular/http';

 //Imports required for your code to run
 import { MyAppMainComponent }               from './myapp.component';
 import { MyAppSharedSettings }              from './myapp.shared-settings';

第 3 步)因此,您已将您的类标记为可注入(第 1 步),并使其可用于任何想要使用它的组件(提供者)(第 2 步)。现在,下一步就是将它放入组件的构造函数中。

 //Imports: Angular & Packages Related
 import { Component, Inject }            from '@angular/core';

 //You must import your injectable class in every component you plan to use it
 import { MyAppSharedSettings }          from '../../myapp.shared-settings';

 //defining how our component will be presented/used
 @Component({
     selector: 'my-content',
     templateUrl: './app/components/content/content.component.html',
     styleUrls: ['./app/components/content/content.component.css']
 })

 //here you name your variable as you please
 export class MyContent {
     yourVariableName: MyAppSharedSettings;

     constructor(private eafSettings: MyAppSharedSettings) {
         this.yourVariableName = eafSettings;
  }
 }

最后一步)以及如何在 HTML 中使用它:

 <h3 class="page-title">
     {{ yourVariableName.welcomeMessage }}<small> {{ yourVariableName.userName}}</small>
    </h3>
    <div class="row about-header">
        <div class="col-md-12">
            <h1>{{ yourVariableName.appName}}</h1>
            <h2>{{ yourVariableName.appTitle }}</h2>
            <a href="#platform"><button type="button" class="btn btn-danger uppercase">Start</button></a>
        </div>
    </div>
 </div>

希望对你有帮助。

【讨论】:

  • 好,但是,如何更改共享变量的值?
猜你喜欢
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-10
  • 2016-07-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多