Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
801 views
in Technique[技术] by (71.8m points)

typescript - Pass Page/Global Variables into Angular2 app for use with services

I am looking for some best practice here. My angular2 app will live inside an existing Content Managment System. As a result I need to capture some "variables" generated by this CMS (like auth tokens etc) and use them with http requests inside my angular2 app.

When the index.html page is displayed by the CMS it is pre-parsed by the CMS and some tokens (ie [ModuleContext:ModuleId]) are replaced before the page is sent to the browser.

Here is an example of my index.html page (abreviated):

<!-- 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>

Specifically the $.ServicesFramework is used for generating valid http web.api requests. I want to capture this in a service that can be injected into each component that uses it.

for example (I am using typescript):

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);
        };
    }

}

One problem is that the typescript compiler throws error that it cannot find "$" etc. I can force this to work by using declare before the typescript class declaration like the following:

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

Question:

What is a better way (if exists) of capturing these "global" variable for use in the app that will scale well.


EDIT - update to RC6

I used the following to work in the 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) }
]
})
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Update >= RC.6

In RC.6 with the introduction of @NgModule() providers are added there instead of in boostrap(...). Alsoprovide()` was deprecated and removed in favor of object literal syntax:

In a shared library define

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

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

Providers can also be added to components and directives

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

Inject it to components, directives, pipes, or services like

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

original

In a shared library define

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

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

In bootstrap() add

// import SF from shared library

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

Where you want to use it

// import SF from shared library

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

This utilizes Angulars DI and avoids hardcoded dependencies which makes the code hard to test.

See also

Hint: Instead of OpaqueToken a plain string can be used as well. Using OpaqueToken prevents name collisions for example if this is used in an open source package that is used by many users. If you control the full environment then you can ensure yourself that no collisions will happen and should be safe to use a string instead of OpaqueToken.

update

InjectionToken with generics support was introduced to replace OpaqueToken which is now deprecated.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...