Shawn Shawn - 19 days ago 20
TypeScript Question

Angular 2.1.2/2.2.0 dependency injection instance undefined

During moving my code from RC4 to 2.1.2, I encountered a strange problem: all my constructor parameters get their value undefined.

I have tried to move providers around from component to app.module.ts to app.component.ts. None of them works.

What's new in 2.1.2 that could make the dependency injector inject "undefined" instead of creating/providing a service instance?

Notes


  1. To make things simpler I changed my code to the following

  2. There is no error message.

  3. If I don't add @Injectable() to AppComponent I would get
    Can't resovle all parameters for AppComponent (?,?,?)

  4. Please note that the root injector failed to create both the user service and Router instance to feed the AppComponent constructor.

  5. AuthService used to inject Http but I removed it along with other code so that there are less variables to the puzzle.

  6. Tried in Angular 2.2.0 it does not work either.



Any further input?

app.component.ts

import { Component,Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../login/auth.service';

@Component({
selector: 'my-app',
template: `
<h1 class="title">Angular Router</h1>
<nav>
</nav>
<router-outlet></router-outlet>
`
})
@Injectable()
export class AppComponent {
constructor( // debug here
private auth: AuthService, // auth = undefined
private router: Router, // router = undefined
) {
console.log("AppComponent constructor");
}
}


app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { AuthService } from '../login/auth.service';

@NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot([
{ path: '', component: AppComponent },
])
],
declarations: [ AppComponent ],
exports: [RouterModule],
providers:[AuthService ],
bootstrap: [ AppComponent ]
})
export class AppModule {}


auth.service.ts

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

@Injectable()
export class AuthService { // the debugger can get to this line but never hit constructor
private _baseUrl: string;
loggedIn: boolean = false;
redirectUrl: string;

constructor() {
console.log("AuthService constuctor");
this.loggedIn = !!sessionStorage.getItem('auth_token');
}

}


main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './appShell/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);


systemjs.config.js

(function(global) {

var ngVer = '@2.1.2'; // lock in the angular package version; do not let it float to current!
var routerVer = '@3.1.2'; // lock router version

//map tells the System loader where to look for things
var map = {
'app': 'app',

// angular bundles
'@angular/core': 'https://npmcdn.com/@angular/core' + ngVer,
'@angular/common': 'https://npmcdn.com/@angular/common' + ngVer,
'@angular/compiler': 'https://npmcdn.com/@angular/compiler' + ngVer,
'@angular/platform-browser': 'https://npmcdn.com/@angular/platform-browser' + ngVer,
'@angular/platform-browser-dynamic': 'https://npmcdn.com/@angular/platform-browser-dynamic' + ngVer,
'@angular/http': 'https://npmcdn.com/@angular/http' + ngVer,
'@angular/router': 'https://npmcdn.com/@angular/router' + routerVer,
'@angular/forms': 'https://npmcdn.com/@angular/forms' + ngVer,
'@angular/upgrade': 'https://npmcdn.com/@angular/upgrade' + ngVer,

// Other libraries
'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.12',
'angular-in-memory-web-api': 'https://npmcdn.com/angular-in-memory-web-api', // get latest
'ts': 'https://npmcdn.com/plugin-typescript@4.0.10/lib/plugin.js',
'typescript': 'https://npmcdn.com/typescript@2.0.3/lib/typescript.js',

};

//packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.ts', defaultExtension: 'ts' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
};
var config = {
// DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
transpiler: 'ts',
meta: {
'typescript': {
"exports": "ts"
}
},
map: map,
packages: packages
};
System.config(config);
})(this);


package.json

{
"name": "TestApp",
"version": "1.0.0",
"scripts": {
"start": "tsc && concurrently \"tsc -w\" \"lite-server\" ",
"lite": "lite-server",
"tsc": "tsc",
"tsc:w": "tsc -w"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@angular/common": "~2.1.2",
"@angular/compiler": "~2.1.2",
"@angular/core": "~2.1.2",
"@angular/forms": "~2.1.2",
"@angular/http": "~2.1.2",
"@angular/platform-browser": "~2.1.2",
"@angular/platform-browser-dynamic": "~2.1.2",
"@angular/router": "~3.1.2",
"@angular/upgrade": "~2.1.2",

"angular-in-memory-web-api": "~0.1.13",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.8",
"rxjs": "5.0.0-beta.12",
"systemjs": "0.19.40",
"zone.js": "^0.6.26"
},
"devDependencies": {
"@types/core-js": "^0.9.34",
"@types/node": "^6.0.46",
"concurrently": "^3.1.0",
"lite-server": "^2.2.2",
"typescript": "^2.0.3"
},
"repository": {}
}

Answer

Finally I found it. In systemjs.config.js add the following and it worked fine.

typescriptOptions: {
  emitDecoratorMetadata: true
},