1

I will try to keep this as short as possible.

The problem I am having is an extension of this SO question

I am trying to pass javascript variable from the "page level" into a service in my angular 2 app. I followed the direction of Gunter in the answer in the above SO question.

I used an opaque token to capture page variable names and pass them into the app constructor. This works perfectly when I am in development, but once I try to bundle the app it stops working. I use gulp-jspm-build to bundle my app and I have mangle set to false to avoid some other errors.

My app lives inside a CMS and the cms pre-processes my apps's index.html and replaces certain tokens with values.

Here is the part of the index.html of my angular app that gets pre processed with token replacement:

<!-- 2. Capture values to pass to app -->
<script type="text/javascript">
    var moduleId = parseInt("[ModuleContext:ModuleId]");
    var portalId = parseInt("[ModuleContext:PortalId]");
    var tabId = parseInt("[ModuleContext:TabId]");
    var dnnSF = $.ServicesFramework(moduleId);
    if ("[ModuleContext:EditMode]" === 'True') {
        var editMode = true;
    }
    // console.log('editMode = ' + editMode);
</script>

<!-- 3. Replaces with actual path to ststem.config.js -->
[Javascript:{path: "~/my-app/systemjs.config.js"}]

<!-- 4. APP selector where is it rendered-->
<my-app>Loading...</my-app>

Notice the [ModuleContext:ModuleId] - this gets replaced with a number value that I need to use in the angularApp that gets bootstrapped on this page.

So my main.ts file looks like this:

import {bootstrap} from '@angular/platform-browser-dynamic';
import {provide} from '@angular/core';
import {AppComponent} from './app.component';
import {dnnModId, dnnSF, dnnPortalId} from './shared/dnn/app.token';
import {HashLocationStrategy, LocationStrategy} from '@angular/common';
import {ROUTER_PROVIDERS} from '@angular/router';
import {HTTP_PROVIDERS} from '@angular/http';

// declare 
declare var $: any;
declare var moduleId: any;
declare var portalId: any;

// the providers & services bootstrapped in this root component
// should be available to the entire app
bootstrap(AppComponent, [
    ROUTER_PROVIDERS,
    HTTP_PROVIDERS,
    provide(LocationStrategy, { useClass: HashLocationStrategy }),
    provide(dnnModId, { useValue: moduleId }),
    provide(dnnPortalId, { useValue: portalId }),
    provide(dnnSF, { useValue: $.ServicesFramework(moduleId) })
]);

I added declare var moduleId: any; so that typescript does not throw compilation errors. But this part is lost when bundled.

Here is how I define my opaque tokens:

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

// Opaque tokens create tokens that can be used in the Dependency Injection Provider
export let dnnModId: any = new OpaqueToken('moduleId');
export let dnnPortalId: any = new OpaqueToken('portalId');
export let dnnTabId: any = new OpaqueToken('tabId');
export let dnnSF: any = new OpaqueToken('sf');

MY ERROR

I get an error on the following line:

core_1.provide(app_token_1.dnnModId, { useValue: moduleId

In my bundled .js file for the app.
the error is

app.min.js Uncaught ReferenceError: moduleId is not defined

QUESTION:

Can someone help me figure out why this works in development but not once I bundle my files together?

A huge thanks in advance

Community
  • 1
  • 1
J King
  • 4,108
  • 10
  • 53
  • 103
  • Can you show us source code in browser that is generated cms? This line `var moduleId = parseInt("[ModuleContext:ModuleId]");` Maybe it related with minification. I can't reproduce it https://plnkr.co/edit/QbPbibahnS9NARq4fuzy?p=preview – yurzui May 30 '16 at 20:39
  • the index.html file that contains the token you mentioned does not get minified or changed in any way other than the tokens being replaced with actual values by the CMS. – J King May 30 '16 at 21:03
  • Could you fix this? We are also using angular with DNN – DAG May 24 '17 at 07:35
  • How did you get the references under `'./shared/dnn/app.token'` ? – DAG May 24 '17 at 07:45
  • @dag I have moved all of my development into angular-cli projects. I highly recommend this as it solves many issues I encountered trying to set up my own build process. There are also a number of things to consider, like if there is more than one module of this type on a DNN page. You have to make sure you have a unique "page" variable that captures the moduleID for each module. the following thread might help: https://stackoverflow.com/questions/35215112/pass-page-global-variables-into-angular2-app-for-use-with-services – J King May 24 '17 at 15:09
  • @JKing We are already using Angular (latest release), but we still have no Idea of how to get the `ModuleId` passed from DNN to our Angular app. Our DNN Module is separated from the Angular project and then we reference the JS files from `/dist` folder in an `ascx` which is our main module page. Does this make sense? Do you have or could you provide a sample project? Unfortunately there are not many infos out there – DAG May 24 '17 at 15:46
  • @dag you have to capture the dnn variable, I use DNN's built in token replace in a html file to assign it to ta page varibale. that is what is happening here: var moduleId = parseInt("[ModuleContext:ModuleId]"); after that you have to get that varibale into angular. There are some issues I am working through with the cli prod build that does not allow me to use the inject tokens. so I am just capturing them directly in the constructor of a service in my app like so this._dnnModId = parseInt(moduleId); this is not ideal and I am trying to find a better way of doing it. – J King May 25 '17 at 16:45
  • @JKing I managed to intercept the ModuleId like so: `dnn.setVar("ModuleId", <%= ModuleId %>);` In my Angular I only need to: `declare let dnn;` `dnn.getVars()` Does this make sense? For now this is working, so we didn't need to use OpaqueToken (now InjectionToken), but as we are using Angular 4, your samples are no longer uptodate, correct? – DAG May 31 '17 at 13:53

2 Answers2

1

This turned out to be an issue with my CMS. My CMS took the javascript files and added them to the top of the page.

I had to change

[Javascript:{path: "~/my-app/systemjs.config.js"}]

to

<script src="/DesktopModules/regentsigns-app/systemjs.config.js"></script>

The top example is used by the CMS token replace function that parses the html page, it placed the bundled angular.min.js file above the selector and inline javascript that captured the global variables.

So by using the simple manual script tag import of the app.js files I fixed the load order issue.

VDWWD
  • 35,079
  • 22
  • 62
  • 79
J King
  • 4,108
  • 10
  • 53
  • 103
0

In tsconfig.json, you should have "module": "commonjs" under "compilerOptions"

Igor Ilić
  • 196
  • 1
  • 2
  • 11
  • I can see why you posted that, but It already is commonjs. and this module id is from the CMS, not the module id used to scope the module in angular2 commonjs. – J King May 31 '16 at 15:49