Angular2:为什么我必须在子组件中导入服务(如果它已包含在应用程序组件中)?

时间:2016-05-26 09:49:12

标签: javascript angular

所以我有一个名为AuthService的身份验证服务。它处理JWT身份验证并具有属性loggedIn。此服务已导入我的App Component。

在应用程序组件中,我还包括一个Navbar组件,它显示一些导航。我使用* ngIf来显示登录按钮或注销按钮以及当前登录的用户。其值由AuthService提供。

如果我在Navbar Component中导入AuthService,一切正常。但不是如果它仅包含在App组件中。我认为Angular 2中的导入工作是层次化的,我在父级别导入的内容应该在子级别上可用。或者我错了?

这就是我认为应该如何运作,但事实并非如此:

// app.component.ts

import { Component } from 'angular2/core';
import { ROUTER_DIRECTIVES, RouteConfig } from 'angular2/router';

import { NavbarComponent } from './navbar.component';
import { LoginComponent } from './login.component';
import { HomeComponent } from '../+home/index';
import { Admin } from '../shared/models/admin.model';
import { AuthService } from '../shared/services/auth.service';

@Component({
  selector: 'fac-app',
  providers: [AuthService, Admin],
  templateUrl: 'app/components/app.component.html',
  directives: [ROUTER_DIRECTIVES, NavbarComponent, SecretComponent]
})
@RouteConfig([
  {
    path: '/',
    name: 'Home',
    component: HomeComponent,
    useAsDefault: true
  },
  {
    path: '/login',
    name: 'Login',
    component: LoginComponent
  },
  {
    path: '/secret',
    name: 'Secret',
    component: SecretComponent
  }
])
export class AppComponent {

  constructor(private authService: AuthService) {}

}
// navbar.component.ts

import { Component } from 'angular2/core';
import {ROUTER_DIRECTIVES} from 'angular2/router';

@Component({
  selector: 'fac-navbar',
  templateUrl: 'app/components/navbar.component.html',
  styleUrls: ['app/components/navbar.component.css'],
  directives: [ROUTER_DIRECTIVES]
})
export class NavbarComponent {

}
// navbar.component.html

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>

    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a [routerLink]="['Home']">Home</a></li>
        <li><a *ngIf="!authService.loggedIn" [routerLink]="['Login']">Login</a></li>
        <li><a *ngIf="authService.loggedIn" href="#">Logout</a></li>
      </ul>
      <p *ngIf="authService.loggedIn" class="navbar-text navbar-right">Signed in as {{authService.currentUserDisplayName()}}</p>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
// auth.service.ts

import { Http, Headers } from 'angular2/http';
import { Router } from 'angular2/router';
import { Injectable } from 'angular2/core';
import { JwtHelper, AuthHttp, AuthConfig, tokenNotExpired } from 'angular2-jwt';
import { Admin } from '../models/admin.model';

@Injectable()
export class AuthService {
  token: any;
  jwtHelper: JwtHelper = new JwtHelper();

  private loggedIn: boolean = false;

  constructor(private http: Http, private router: Router, private authHttp: AuthHttp, private admin: Admin) {
    this.loggedIn = tokenNotExpired('auth_token');
  }

  saveJwt(jwt: any) {
    if(jwt) {
      localStorage.setItem('auth_token', jwt);
      this.token = localStorage.getItem('auth_token');
      this.loggedIn = true;
    }
  }

  getJwt() {
    if(this.isAuth()) {
      return localStorage.getItem('auth_token');
    }
  }

  deleteJwt() {
    localStorage.removeItem('auth_token');
    this.token = localStorage.getItem('auth_token');
  }

  isAuth() {
    return tokenNotExpired('auth_token');
  }

  login(admin: Admin) {
    var header = new Headers();
    header.append('Content-Type', 'application/json');
    return this.authHttp.post('http://localhost:4000/api/v1/sessions', JSON.stringify({data: {attributes: { email: admin.email, password: admin.password } }}), {
      headers: header
    });
  }

  logout() {
    this.deleteJwt();
    this.loggedIn = false;
    this.router.navigate(['Home']);
  }

  currentUserDisplayName() {
    var jwt: any = this.getJwt();
    var decodedToken: any = this.jwtHelper.decodeToken(jwt);
    return decodedToken.displayname;
  }

}

这是工作版本:

// navbar.component.ts

import { Component } from 'angular2/core';
import {ROUTER_DIRECTIVES} from 'angular2/router';

import { AuthService } from '../shared/services/auth.service';

@Component({
  selector: 'fac-navbar',
  templateUrl: 'app/components/navbar.component.html',
  styleUrls: ['app/components/navbar.component.css'],
  directives: [ROUTER_DIRECTIVES]
})
export class NavbarComponent {
  constructor(private authService: AuthService) {  }

}

1 个答案:

答案 0 :(得分:1)

  1. *ngIf="!authService.loggedIn"等模板中的表达式在组件实例的范围内进行评估。所以,它实际上是navbarComponentInstance.authService.logged。当您在构造函数中省略private authService: AuthService时,navbarComponentInstance.authService显然是未定义的。

  2. “我在父级别导入的内容应该在子级别上可用。”是的,当且仅当您在子构造函数中声明服务属性时,才可以将服务实例注入子组件。并且,如果已将该服务添加到父组件的providers,请不要将该服务添加到该组件中。