[英]Angular2 - Transfer data outside router-outlet to another component
Am new to Angular2 but I have already made 30+ component and services and used Input, Output, ChangeDetectorRef, Pipes. Angular2是新手,但我已经制作了30多种组件和服务,并使用了Input,Output,ChangeDetectorRef,Pipes。 So pretty much know about Angular2 by now. 到目前为止,对Angular2的了解非常多。 My app.component.ts looks like this 我的app.component.ts看起来像这样
import { Component } from '@angular/core';
@Component({
selector: 'soc',
template: `
<header-block></header-block>
<router-outlet></router-outlet>
`,
})
export class AppComponent { }
As I need my header-block in every page so I added it outside router-block so I don't have to add it everywhere. 因为我在每个页面中都需要标题块,所以我将其添加到路由器块之外,因此不必在任何地方添加它。 Now the problem I am having is changing the value of variable in the header-block after doing an action in view inside router-outlet. 现在,我遇到的问题是在路由器出口内的视图中执行操作后,更改了标头块中变量的值。
For example I have menu which will be visible to the user only after they login. 例如,我有一个菜单,该菜单只有在用户登录后才对用户可见。
{{ 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 is a variable whose value am getting from localStorage in header.block.component.ts user_is_logged是一个变量,其值从header.block.component.ts中的 localStorage 获取
user_is_logged:string = localStorage.getItem("logged");
When the user is not logged in ie user_is_logged is undefined for home.component.ts ( where login logic is written ), I ask the user to login and after successful login am updating the value of user_is_logged variable and also updating the localStorage value of the variable and then triggering detect changes by using the ChangeDetectionRef(cdr) and then routing to user profile 当用户未登录时,即未定义home.component.ts的user_is_logged (写有登录逻辑),我要求用户登录,并在成功登录后更新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
The problem is when I reach the user profile after successful login the value of {{ user_is_logged }} never updates even when am using the variable itself or using the value from localStorage or even calling for detection. 问题是,当我成功登录后到达用户配置文件时,{{user_is_logged}}的值永远不会更新,即使正在使用变量本身或使用localStorage的值,甚至调用检测也是如此。
Is it possible to do it this way or do I have to add header-block to every page separately? 是否可以通过这种方式执行此操作,还是必须将标题块分别添加到每个页面? Please ask for more information if I missed something. 如果我错过了一些东西,请询问更多信息。
EDIT ============> 编辑 ============>
So after going through Subject, BehaviourSubject, AsyncSubject, ReplaySubject, Observables and what not I just couldn't get this to work. 因此,在经历了主题,BehaviourSubject,AsyncSubject,ReplaySubject,Observables之后,还有一些我无法做到的事情。 This is the last code I have written : 这是我写的最后一个代码:
home.page.component.ts (where login happens and has to emit the event) 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 (which is imported by both component) 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 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);
});
}
My Log 我的日志
// 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
What am I missing in header.block.component.ts? 我在header.block.component.ts中缺少什么? As the value is successfully updated within the home.service.ts but never goes to header. 由于该值已在home.service.ts中成功更新,但从未转到标头。
Was asked to post this, it is a bare-bones event/subject service to get you started. 被要求发布此内容,这是一个准系统的事件/主题服务,可帮助您入门。 I use "notifier/notes/note" just so the nomenclature doesn't get confused with "events" and other framework-api mechanisms. 我使用“ notifier / notes / note”只是为了使命名法不会与“事件”和其他framework-api机制混淆。
// Constant of named "notes" analogous to named events.
// I always found it easier to have one event type with a "name",
// rather than creating a specific typed event for every action.
const Notes = {
HEADER_BUTTON_CLICKED : 'header_button_clicked'
};
// Any component that wants to send data creates a new "Note" to send.
// Just makes sure you know what all callbacks are getting.
class Note {
constructor ( name, data ) {
this.name = name; // Should be from your Notes constant.
this.data = data; // Can be anything at all.
}
}
// You inject this service into any component that needs it.
class NotifierService {
constructor() {
let Rx = require ( 'rx' );
// We'll use Subject here.
this.subject = new Rx.Subject ( );
}
// You only subscribe if you want to hear notes.
subscribe ( callback ) {
// Subscribing component feeds in a callback.
// The return of this can be used to unsubscribe as well.
return this.subject.subscribe ( b => callback ( b ) );
}
// Any component with access to this service can just create a note
// and send it to all subscribers to this service.
sendNote ( note ) {
// Component uses the service to emit a "note" with a
// named event and a payload. All subscribers hear it in the
// callbacks they subscribed with, and can filter on the name
// in the "note" to make sure it's the event they care about.
// This is pretty naive but should give the idea.
this.subject.onNext ( note );
}
}
export { NotifierService } // Service to inject
export { Note } // A useful type to send out to subscribers
export { Notes } // Constant of event/note names.
Typical usage: 典型用法:
import { NotifierService, Notes, Note } from './notifier.service';
... // inject in your constructor either TS or ES6 style...
// I want to hear notes
this.noteSvc.subscribe ( b => this.myCallback ( b ) );
// I want to send a note
this.noteSvc.sendNote ( new Note ( Notes.HEADER_BUTTON_CLICKED, { btnName : 'Home' } );
// In the callback
myCallback ( note ) {
if ( note.name === Notes.HEADER_BUTTON_CLICKED ) {
console.log ( note.data ); // whatever the payload is
}
}
If you provide HomeService
in homepage and header, you get 2 instances of HomeService
. 如果在首页和标题中提供HomeService
,则会获得2个HomeService
实例。 If you want to share a service, then provide it only once on the parent component. 如果要共享服务,请仅在父组件上提供一次。 If you want to share a single instance with your whole application, provide it only at @NgModule()
of AppModule
如果你想与你的整个应用程序共享一个实例,只提供它@NgModule()
的AppModule
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.