5
votes

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/[email protected]',
    'angular-in-memory-web-api':  'https://npmcdn.com/angular-in-memory-web-api', // get latest
    'ts':                         'https://npmcdn.com/[email protected]/lib/plugin.js',
    'typescript':                 'https://npmcdn.com/[email protected]/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": {}
}
3
You don't need @Injectable() when there is already @Directive(), @Component(), or @Pipe()Günter Zöchbauer
You should at least get an error message. Did you add FormsModule, and ReactiveFormsModule to imports of the @NgModule()? I don't think you need to add FormBuilder to providers. Adding FormsModule to imports should do.Günter Zöchbauer
Did you use @Injectable() in your service classes?lenny
Are you sure the double .. are correct here import { AuthService } from '../login/auth.service';?Günter Zöchbauer
yes. '../login/auth.service' is correct.Shawn

3 Answers

2
votes

In RC.5 @NgModule was introduced.
You need to declare additional services, modules etc. like this:

import {NgModule} from '@angular/core';
import {LoginComponent} from './login.component';
import {Router,RouterModule} from '@angular/router';
import {FormsModule, FormBuilder} from '@angular/forms';
import {AuthService} from './auth.service';
import {routing} from './app.routing.module';
import {MainComponent} from './main.component';

@NgModule({
  declarations: [LoginComponent], // specify your components here
  imports: [BrowserModule, FormsModule, RouterModule.forRoot([...]), routing],
  providers: [FormBuilder, AuthService, ...], // additional providers
  bootstrap: [MainComponent],
})
class AppModule {}

More info

0
votes

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

typescriptOptions: {
  emitDecoratorMetadata: true
},
0
votes

I have a little suggestion. Try not to use the @Injector decorator on a component, rather define a service and use it there. It makes your code much more readable.