0

I'd like to have a variable called _contextPath, which is a Javascript evaluated variable in a JSP, and which is currently available in systemjs.config.js -- I'm trying to have this _contextPath variable available in a Typescript Service.

I'd like to know if the _contextPath variable can be passed onto the Typescript Service called job.service.ts

Here is my folder structure:

├── scripts
│   └── mec-irs
│       ├── app
|       |    ├── app.component.ts
|       |    ├── app.module.ts
|       |    ├── app.routes.ts
|       |    └── jobs
|       |          ├── job.ts
|       |          ├── job.routes.ts
|       |          └── job.service.ts     
│       ├── db.json
│       ├── GruntFile.js
│       ├── index.html
│       ├── node
│       ├── node_modules
│       ├── package.json
│       ├── style.css
│       ├── systemjs.config.js
│       ├── tsconfig.json
│       ├── typings
│       └── typings.json
├── views
│   ├── mec.jsp

The mec.jsp gets the context via Javascript call and stores it in a variable called _contextPath:

<html>
<head>
  <title>MEC IRS</title>
  <script>document.write('<base href="' + document.location + '" />');</script>
  <script>var _contextPath = "${pageContext.request.contextPath}";</script>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="..<%=request.getContextPath()%>/scripts/mec-irs/style.css">

  <!-- 1. Load libraries -->
  <!-- Polyfill(s) for older browsers -->
  <script src="..<%=request.getContextPath()%>/scripts/mec-irs/node_modules/core-js/client/shim.min.js"></script>
  <script src="..<%=request.getContextPath()%>/scripts/mec-irs/node_modules/zone.js/dist/zone.js"></script>
  <script src="..<%=request.getContextPath()%>/scripts/mec-irs/node_modules/reflect-metadata/Reflect.js"></script>
  <script src="..<%=request.getContextPath()%>/scripts/mec-irs/node_modules/systemjs/dist/system.src.js"></script>

  <!-- 2. Configure SystemJS -->
  <script src="..<%=request.getContextPath()%>/scripts/mec-irs/systemjs.config.js"></script>
  <script>
    System.import('app').catch(function(err){ console.error(err); });
  </script>
</head>

<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>

The _contextPath is used in systemjs.config.js:

/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      // paths serve as alias
      'npm:': _contextPath + '/scripts/mec-irs/node_modules/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: _contextPath + '/scripts/mec-irs/app',
      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
      // other libraries
      'rxjs':                      'npm:rxjs',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api',
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.js',
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);

The Java web application context is hardcoded though in job.service.ts as mec. I'd like to know how to pass the _contextPath to this Typescript Service called job.service.ts please. As seen below the context mec is hardcoded as /mec/admin/irs/jobs/, which is a web service endpoint:

import {Injectable, Inject}    from '@angular/core';
import {Http, Headers} from '@angular/http';
import 'rxjs/add/operator/map';

// Decorator to tell Angular that this class can be injected as a service to another class
@Injectable()
export class JobService {

      // Class constructor with Jsonp injected
      constructor( @Inject (Http)private http:Http) { }

      // Base URI for Spring Batch Admin
      private jobsUrl = '/batch/';

      //TODO wish not to have hardcoded context, like below
      //private mecUrl = '/' + _contextPath + '/admin/irs/jobs/';
      private mecUrl = '/mec/admin/irs/jobs/';

      // Stop Spring Batch Job by its name
      stopJobByName(name: string) {
        const endPoint = name + '/stopIrsJobPoller';
        return this.http.get(this.mecUrl + endPoint)
            .map(res => res.json());
    }
.
.
.    
2
  • Why do you need this variable? Commented Nov 12, 2016 at 20:15
  • I need this variable because in the service, I wish to call a web service via hostname/_contextPath/someRestfulWS Commented Nov 12, 2016 at 20:25

1 Answer 1

0

You need something that will run at the application initialization and get your server side settings. Here is how I am doing this.

Create a class to store your server side configuration:

export class AppConfig {
    public ContextPath: string;
};

Create a service to get your back-end configuration from your JSP:

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

import { AppConfig } from './app.config';

@Injectable()
export class ConfigService {
    private _config: AppConfig;

    constructor(private http: Http, private config: AppConfig) {
    }

    public Load(): Promise<AppConfig> {
        return new Promise((resolve) => {
            this.http.get('./views/mec.jspn').map(res=>res.json())
                .subscribe((config: AppConfig) => {
                    this._config = data;
                    resolve(this._config);
                }, (error: any) => {
                    this._config = new AppConfig();
                    resolve(this._config);
                });
        });
    }

    public Get(key: any): any {
      return this._config[key];
    }
}

Then boostrap it in your app module initialization by providing your ConfigService as the provider for the APP_INITIALIZER:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Http, HttpModule } from '@angular/http';
import { APP_INITIALIZER } from '@angular/core';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { ConfigService } from './shared/services/index';
import { AppConfig } from './app.config';

@NgModule({
    declarations: [
        AppComponent,
    ],
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule
    ],
    providers: [
        {
            provide: APP_INITIALIZER,
            useFactory: (configService: ConfigService) => () => configService.Load(),
            deps: [ConfigService, Http, AppConfig],
            multi: true
        },
        ConfigService,
        AppConfig
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}

Then simply using it by injecting the ConfigService in any other service:

import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Injectable } from '@angular/core';

import { ConfigService } from './config.service';

@Injectable()
export class AppService {
    constructor(
        private _http: Http,
        private _config: ConfigService
    ) {
      console.log(_config.Get('ContextPath'));
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

I purposely cannot access my JSP with a GET to localhost:8080/mec/views/mec.jsp. Even if I did expose localhost:8080/mec/views/mec.jsp via GET, can you explain how the ConfigService determines the Java web application's context?
I am not sure what you are trying to achieve exactly. The config service needs to know where to get the config from. I assumed you can get it by using this.http.get('./views/mec.jspn') or this.http.get('someUrl/mec.jspn'). If not, you can create a JSON file that lives inside your app/ and use that. On a side not, you don't need to set context path inside SystemJS, just set the baseHref in your index.html.
Hi Ben, How would you approach this in the Angular v4 of today? since there's no more APP_INITIALIZER in Angular. I could simply create another question for this purpose but your answer is the closest to what I've been looking for in the past 3 days. I'm working on a Rails + Angular + Shopify app. And I can't figure out a way to get access to the Response Params, especially the access_token on the client side in Angular. Please help me out. Thanks.
APP_INITIALIZER should still work in 4. See stackoverflow.com/questions/43639136/….

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.