我对angular2有点新,我理解所有的基础知识,但我有一个关于通过我不理解的服务绑定组件的问题。我真的很想知道在这种情况下我做错了什么,而不仅仅是有一个需要改变的基本答案。
我有一个app.component.ts来处理我的应用程序路由并触发我的登录组件
# app.component.ts
import {Component, OnInit} from "@angular/core";
import {LoginComponent} from "./authentication/login.component";
import {ROUTER_DIRECTIVES} from '@angular/router';
import {NavbarComponent} from "./navbar/navbar.component";
import {User} from "./authentication/user.model";
import {AuthService} from "./authentication/auth.service";
@Component({
moduleId: module.id,
selector: "app",
templateUrl: "./app.component.html",
directives: [
ROUTER_DIRECTIVES,
NavbarComponent,
LoginComponent
],
precompile: [
AppComponent,
NavbarComponent,
LoginComponent
]
})
export class AppComponent implements OnInit {
public user:User;
constructor(private authService:AuthService) {
}
ngOnInit() {
this.user = this.authService.getUser();
console.log("Application initialized ...");
}
}
由于这个类用于主路由并且登录是强制性的,因此我认为将用户对象放在那里作为公共属性是明智的,这样我就可以轻松地从任何地方到达它。登录(通过auth.guard转发)由以下Component和auth服务处理:
# login.component.ts
import {Component, OnInit} from '@angular/core';
import {Router, ROUTER_DIRECTIVES} from '@angular/router';
import {NgForm} from '@angular/forms';
import {User} from "./user.model";
import {AuthService} from "./auth.service";
@Component({
moduleId: module.id,
selector: 'authentication',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
directives: [ROUTER_DIRECTIVES]
})
export class LoginComponent implements OnInit {
constructor(public router:Router, private authService:AuthService) {
}
ngOnInit() {
}
login(event, username, password) {
this.authService.login(username, password);
this.router.navigate(['']);
}
}
服务:
# auth.service.ts
import {Injectable} from '@angular/core';
import {User} from "./user.model";
@Injectable()
export class AuthService {
public user:User;
login(username:string, password:string) {
this.user = new User();
this.user.id = 1;
this.user.username = 'dummy username';
this.user.email = 'foo@bar.com';
this.user.name = 'My dummy testname';
this.user.token = 'randomtokenverherefromwebserviceandstuff';
localStorage.setItem('user', JSON.stringify(this.user));
}
logout() {
localStorage.removeItem('user');
}
getUser() {
this.user = JSON.parse(localStorage.getItem('user'));
return this.user;
}
}
所有这一切都适合我至少的感觉。登录被很好地触发,登录后用户被重定向到在路由器插座中解析的通用组件,这很好。 app.component.html
中提供了此模板,如下所示:
# app.component.html
<app-navbar [user]="user"></app-navbar>
<div class="container-fluid">
<router-outlet></router-outlet>
</div>
这里的问题是登录后导航栏用户为空并且根本不显示。然而,一旦页面刷新,导航栏用户就可以从本地存储中获取用户。因此我猜它与绑定有关,它不会令人耳目一新,因为它会检索它onInit我认为?以下是导航栏本身的代码:
# navbar.component.ts
import {Component, Input} from "@angular/core";
import {User} from "../authentication/user.model";
import {ROUTER_DIRECTIVES, Router} from '@angular/router';
import {AuthService} from "../authentication/auth.service";
@Component({
moduleId: module.id,
selector: "app-navbar",
templateUrl: "./navbar.component.html",
directives: [ROUTER_DIRECTIVES]
})
export class NavbarComponent {
@Input() user:User;
constructor(public router:Router, private authService:AuthService) {
}
logout() {
this.authService.logout();
this.router.navigate(['login']);
}
}
我希望有人可以告诉我我做错了什么,或者甚至告诉我,我正在做的事情是正确的。
提前致谢
答案 0 :(得分:0)
尝试添加此修改
providers:[AuthService],
修改强>
这里也是Auth0配置https://github.com/auth0-samples/auth0-angularjs2-systemjs-sample
的git答案 1 :(得分:-1)
我已使用bi-directional communication
from angular documentation。我在下面的主题中添加了文字。
父组件及其子组件共享一个服务,其接口支持在系列内进行双向通信。
服务实例的范围是父组件及其子组件。此组件子树外的组件无法访问服务或其通信。
此MissionService
将MissionControlComponent
与多个AstronautComponent
子项相关联。
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MissionService {
// Observable string sources
private missionAnnouncedSource = new Subject<string>();
private missionConfirmedSource = new Subject<string>();
// Observable string streams
missionAnnounced$ = this.missionAnnouncedSource.asObservable();
missionConfirmed$ = this.missionConfirmedSource.asObservable();
// Service message commands
announceMission(mission: string) {
this.missionAnnouncedSource.next(mission);
}
confirmMission(astronaut: string) {
this.missionConfirmedSource.next(astronaut);
}
}
MissionControlComponent
都提供与其子代共享的服务实例(通过providers
元数据数组),并通过其构造函数将该实例注入其自身:
import { Component } from '@angular/core';
import { MissionService } from './mission.service';
@Component({
selector: 'mission-control',
template: `
<h2>Mission Control</h2>
<button (click)="announce()">Announce mission</button>
<my-astronaut *ngFor="let astronaut of astronauts"
[astronaut]="astronaut">
</my-astronaut>
<h3>History</h3>
<ul>
<li *ngFor="let event of history">{{event}}</li>
</ul>
`,
providers: [MissionService]
})
export class MissionControlComponent {
astronauts = ['Lovell', 'Swigert', 'Haise'];
history: string[] = [];
missions = ['Fly to the moon!',
'Fly to mars!',
'Fly to Vegas!'];
nextMission = 0;
constructor(private missionService: MissionService) {
missionService.missionConfirmed$.subscribe(
astronaut => {
this.history.push(`${astronaut} confirmed the mission`);
});
}
announce() {
let mission = this.missions[this.nextMission++];
this.missionService.announceMission(mission);
this.history.push(`Mission "${mission}" announced`);
if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
}
}
AstronautComponent
也会在其构造函数中注入服务。每个AstronautComponent
都是MissionControlComponent
的子级,因此会收到其父级的服务实例:
import { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'my-astronaut',
template: `
<p>
{{astronaut}}: <strong>{{mission}}</strong>
<button
(click)="confirm()"
[disabled]="!announced || confirmed">
Confirm
</button>
</p>
`
})
export class AstronautComponent implements OnDestroy {
@Input() astronaut: string;
mission = '<no mission announced>';
confirmed = false;
announced = false;
subscription: Subscription;
constructor(private missionService: MissionService) {
this.subscription = missionService.missionAnnounced$.subscribe(
mission => {
this.mission = mission;
this.announced = true;
this.confirmed = false;
});
}
confirm() {
this.confirmed = true;
this.missionService.confirmMission(this.astronaut);
}
ngOnDestroy() {
// prevent memory leak when component destroyed
this.subscription.unsubscribe();
}
}
请注意,我们捕获
subscription
并取消订阅AstronautComponent
被摧毁。这是一个内存泄漏保护步骤。 此应用程序中没有实际风险,因为a的生命周期AstronautComponent
与应用程序本身的生命周期相同。那 在更复杂的应用程序中并不总是如此。我们不会将此警卫添加到
MissionControlComponent
因为,因为 父,它控制MissionService
的生命周期。
历史记录日志表明,在服务的推动下,邮件在父MissionControlComponent
和AstronautComponent
子女之间双向传播:
点击父MissionControlComponent
和AstronautComponent
子项的点击按钮,验证历史符合预期:
// ...
it('should announce a mission', function () {
let missionControl = element(by.tagName('mission-control'));
let announceButton = missionControl.all(by.tagName('button')).get(0);
announceButton.click().then(function () {
let history = missionControl.all(by.tagName('li'));
expect(history.count()).toBe(1);
expect(history.get(0).getText()).toMatch(/Mission.* announced/);
});
});
it('should confirm the mission by Lovell', function () {
testConfirmMission(1, 2, 'Lovell');
});
it('should confirm the mission by Haise', function () {
testConfirmMission(3, 3, 'Haise');
});
it('should confirm the mission by Swigert', function () {
testConfirmMission(2, 4, 'Swigert');
});
function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) {
let _confirmedLog = ' confirmed the mission';
let missionControl = element(by.tagName('mission-control'));
let confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
confirmButton.click().then(function () {
let history = missionControl.all(by.tagName('li'));
expect(history.count()).toBe(expectedLogCount);
expect(history.get(expectedLogCount - 1).getText()).toBe(astronaut + _confirmedLog);
});
}
// ...