【发布时间】:2017-01-28 14:01:39
【问题描述】:
我是 Angular2 的新手,但我已经制作了 30 多个组件和服务,并使用了 Input、Output、ChangeDetectorRef、Pipes。到目前为止,对 Angular2 已经非常了解了。我的 app.component.ts 看起来像这样
import { Component } from '@angular/core';
@Component({
selector: 'soc',
template: `
<header-block></header-block>
<router-outlet></router-outlet>
`,
})
export class AppComponent { }
因为我在每个页面中都需要我的标题块,所以我将它添加到路由器块之外,所以我不必在任何地方添加它。现在我遇到的问题是在路由器出口内的视图中执行操作后更改标头块中变量的值。
例如,我有一个菜单,只有在用户登录后才能看到。
{{ user_is_logged }}
<ul class="nav navbar-nav navbar-right" *ngIf="user_is_logged == '1'">
<li><a href="#" (click)="logout($event)">Logout</a></li>
</ul>
user_is_logged 是一个变量,其值来自 header.block.component.ts
中的 localStorageuser_is_logged:string = localStorage.getItem("logged");
当用户未登录时,即 home.component.ts 未定义 user_is_logged (其中写入登录逻辑),我要求用户登录并在成功登录后更新值user_is_logged 变量并更新变量的 localStorage 值,然后使用 ChangeDetectionRef(cdr) 触发检测更改,然后路由到用户配置文件
this.user_is_logged = "1";
localStorage.setItem('logged', '1');
this.cdr.detectChanges();
this.router.navigate(['u/'+user_id']); //user_id is from login response from server
问题是当我成功登录后到达用户配置文件时,即使使用变量本身或使用 localStorage 中的值甚至调用检测,{{ user_is_logged }} 的值也不会更新。
是否可以这样做,或者我必须分别为每个页面添加标题块?如果我遗漏了什么,请询问更多信息。
编辑 ============>
所以在经历了 Subject、BehaviourSubject、AsyncSubject、ReplaySubject、Observables 等等之后,我就是无法让它工作。这是我写的最后一个代码:
home.page.component.ts(登录发生并且必须发出事件的地方)
import { HomeService } from '../services/home.service';
// No observable or subject imported here.
login() {
// Sending status 1 to HomeService
this.HomeService.changeStatus("1");
}
home.service.ts(由两个组件导入)
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
// I imported Subject, BehaviourSubject, Observables but cant get it to work
export class HomeService {
// This looked more reliable than Subject so used this; init with value "0"
public subjectStream = new BehaviorSubject<string>('0');
constructor(
){
this.subjectStream.subscribe(value => {
// Successfully logs value "1" sent by changeStatus below
console.log(value);
});
}
changeStatus(value: any){
// Gives value "1" when called by home.page.component.ts
console.log(value);
// Looks correct because it successfully sent value to construct
this.subjectStream.next(value);
}
}
header.block.component.ts
import { HomeService } from '../services/home.service';
// No observable or subject imported here also.
constructor(
){
this.HomeService.subjectStream.subscribe(value => {
// Logs value "0" at beginning but never logs value "1"
console.log(value);
});
}
我的日志
// logged by constructor when imported by header.block.component
home.service.ts:31 0
// logged by constructor of header.block.component itself
header.block.component.ts:25 0
// logged by constructor when imported by home.page.component (I think)
home.service.ts:31 0
// ===================
// Login called here
// ===================
// logged by changeStatus after login after called by home.component
home.service.ts:36 1
// logged by constructor after getting event from changeStatus
home.service.ts:31 1
我在 header.block.component.ts 中缺少什么?由于值已在 home.service.ts 中成功更新,但从未进入标题。
【问题讨论】:
-
只需创建一个服务。将它注入到两个组件中,让它们都订阅服务持有的发射器(EventEmitter 或 Subject,甚至只是一个简单的小观察者模式)。当一个人需要通知另一个人时,一个人只需告诉服务,“发出一个事件”。订阅它的所有东西都会听到它。使用常量能够按名称过滤事件,或者使用一个小工厂来发出类型化的事件,但是你想去做。网络上有很多例子,主要是在标题下,“在没有父/子关系的组件之间发送数据”。
-
仅供参考,我做的和你做的一样;我的大多数应用程序中都有页眉、路由器插座和页脚。路由器出口发生变化,页眉和页脚保持不变,它们完全通过发射器服务进行通信,这使得整个事情变得如此简单。
-
@TimConsolazio 您是在使用 Günter 在他的评论中建议的 Observables,还是在使用 EventEmitter?
-
我目前使用 EventEmitter(我问了一下,这并不罕见),因为它扩展了 Subject(所以它是可观察的)。但是,我知道这可能会发生变化,并且 EventEmitter 可能不再以这种方式构建。我猜你可能会担心它是否以及何时发生,但对于向前移动的代码,最好靠近 RxJS 并远离 Angular 事件机制,所以使用 Subject 是合理的。
标签: angular