angular 2 update app component from router outlet

2019-04-29 14:42发布

问题:

I'm using angular 2 rc1 and the new router @angular/router

In app component I have a nav section and router outlet

<nav>   
    <a *ngIf="auth?.userName == null" [routerLink]="['/login']">Login</a>
    <a *ngIf="auth?.userName != null" (click)="logout()">Logout</a>
    {{auth?.userName}}
</nav> 
<router-outlet></router-outlet>

I inject a loginService into app component and subscribe to an event in ngOnInit

ngOnInit() {
    this.loginService.loginSuccess.subscribe(this.loginSuccess);

} 
ngOnDestroy() {
    this.loginService.loginSuccess.unsubscribe();
}
private loginSuccess(res: IAuthResponse) {
    this.auth = res;
}  

when I navigate to my '/login' route page/component my loginService is inject and loginService defines an event

@Output() loginSuccess = new EventEmitter<IAuthResponse>();

and after successful login in my service, the login service raises the event

this.loginSuccess.next(response);

I'm able to set a breakpoint in app component on the subscribed loginSucess and the data is passed along, however 'this' is undefined.

private loginSuccess(res: IAuthResponse) {
    this.auth = res;  //this is undefind
} 

how can I update the app component from events that are triggerd from services used in components that are hosted in the router outlet

回答1:

Not sure what you mean by "and the data is passed".

@Output() loginSuccess = new EventEmitter<IAuthResponse>();

in the component added by the router (LoginComponent) doesn't do anything. @Input() and @Output() in routed components are not supported.

Just inject LoginService to the routed component and emit the event using an observable in the login component.

@Injectable() 
export class LoginService {
  changes:BehaviorSubject = new BehaviorSubject(false);
}
export class LoginComponent {
  constructor(private loginService:LoginService) {}

  onLogin() {
    this.loginService.changes.next(true);
  }
}
export class NavComponent {
  constructor(private loginService:LoginService) {}

  onLogin() {
    this.loginService.changes.subscribe(status => this.isLoggedIn = status);
  }
}


回答2:

This looks like it could be the solution to my problem: passing events from child to parent that uses router-outlet, however it looks like RC1 has changed how BehaviorSubject works. Using the method above:

changes:BehaviorSubject = new BehaviorSubject(false);

gives an error saying BehaviorSubject needs a type declaration, so I tried both

changes:BehaviorSubject<boolean> = new BehaviorSubject(false);
    as well as
changes:BehaviorSubject<any> = new BehaviorSubject(false);

and it compiles fine, but when running the app, it gives a non-descriptive error of:

zone.js:323 SyntaxError: Unexpected token <
Evaluating http://localhost:3000/node_modules/rxjs/index.js
Error loading http://localhost:3000/app/main.js
at SystemJSLoader.__exec
(http://localhost:3000/node_modules/systemjs/dist/system.src.js:1395:16)
at entry.execute 

I'm assuming something has changed with rxjs and BehaviorSubject