通过组件共享数据
Sharing Data through components
我想在登录到我的登录组件时将数据传递到我的导航栏组件,但我的导航栏内容没有更新。
我的导航栏组件在应用程序模块中,我的登录组件在另一个模块中。
我试过使用服务共享数据。
我的登录组件,这个组件在另一个模块中
export class LoginComponent {
userCredentials;
constructor(
private readonly _authService: AuthService,
) {
}
login() {
this._authService.auth(this.userCredentials)
.subscribe(
(response: any) => {
const dataForm = {
usuario: response.user,
rol: this.response.role,
};
this._authService.setSession(response);
},
error => {
console.log(error);
}
);
}
}
我的 NavBarComponent,这个组件在 app-module 里
export class NavbarComponent {
isLogged = false;
susbscription: Subscription;
constructor(
private readonly _authService: AuthService,
) {
this.suscripcion = this._authService
.changeState$
.subscribe(
(isLogged) => {
this.isLogged = isLogged;
},
error => console.log(error)
);
}
}
我的导航栏Html
<mat-toolbar color="primary">
<mat-toolbar-row>
<span>SUPERMERCADO</span>
<span class="spacer"></span>
<div *ngIf="!isLogged">
<button mat-button
Login
</button>
</div>
<div *ngIf="isLogged">
<p>Welcome</p>
</div>
</mat-toolbar-row>
</mat-toolbar>
我的服务,这个服务不在app-module中
@Injectable()
export class AuthService {
protected url = environment.url;
protected model = '/user';
isLogged = false;
private changeState = new Subject<boolean>();
changeState$ = this.changeState.asObservable();
constructor(
private readonly _router: Router,
protected readonly httpclient: HttpClient,
) {
}
setSession(data: any) {
this.isLogged = true;
this.changeState.next(this.isLogged);
}
auth(dataForm: any): Observable<any> {
const url = `${this.url}${this.model}/login`;
return this.httpclient.post(url, dataForm);
}
}
我正在使用 angular 8.2.0
来自组件
import { Component, OnInit, ViewChild} from '@angular/core';
import { dataService } from "src/app/service/data.service";
@Component( {
selector: 'app-sideWidget',
templateUrl: './sideWidget.html',
styleUrls: ['./linked-widget.component.css']
} )
export class sideWidget{
constructor( private LWTableColumnNames: dataService ) {
}
ngOnInit() {
this.LWTableColumnNames.refLWTableColumnNames = "patient"; //this line of code will pass the value through data service
}
}
数据服务
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class dataService {
refLWTableColumnNames: string;//creating an object for the data
}
到组件
import { Component, OnInit } from '@angular/core';
import { dataService } from "src/app/service/data.service";
@Component( {
selector: 'app-linked-widget',
templateUrl: './linked-widget.component.html',
styleUrls: ['./linked-widget.component.css']
} )
export class LinkedWidgetComponent implements OnInit {
constructor(private LWTableColumnNames: dataService) { }
ngOnInit() {
console.log(this.LWTableColumnNames.refLWTableColumnNames); // out put will be string "patient"
}
}
Stackbliz demo 这样你就可以将值发送到不同的兄弟组件(不仅是父子组件)
您的代码无法按预期工作可能有 2 个原因。
changeState
主题在 导航栏组件订阅它之前 发出数据。
据我所知,当你在登录页面时,导航栏组件不应该被加载。当你。在您的 LoginComponent
中,您 首先发出 数据,然后,当 NavbarComponent
加载时,您订阅刚刚发出的 observable。
但是,因为您使用了 Subject,您将 不会获得 last emitted 值。
为了减轻这种情况,您可以使用 BehaviorSubject,它将 retain last emitted value for 新订阅者.
主题与行为主题
const s = new Subject();
s.next('not seen...');
s.next('not seen...');
s.next('not seen...');
s.subscribe(d => console.log('SUBSCRIBER 1: ', d))
// You must first subscribe, as the `Subject` does not holds any values on itself
s.subscribe(d => console.log('SUBSCRIBER 2: ', d))
// `Subscriber 1` will also receive those
s.next('value1 !!');
s.next('value2 !!');
/*
SUBSCRIBER 1: value1 !!
SUBSCRIBER 2: value1 !!
SUBSCRIBER 1: value2 !!
SUBSCRIBER 2: value2 !!
*/
const bs = new BehaviorSubject(null);
bs.next('not seen');
// It will retain only the last value for the new subscribers
bs.next('hmmm!!')
bs.subscribe(v => console.log('subscriber 1 of BS: ', v))
bs.next('value1!')
bs.subscribe(v => console.log('subscriber 2 of BS: ', v))
/*
subscriber 1 of BS: hmmm!!
subscriber 1 of BS: value1!
subscriber 2 of BS: value1!
*/
如果您想探索,Here 是一个 StackBlitz 演示。
因此,如果您将 Subject
替换为 BehaviorSubject(null)
,它应该可以工作。
- 如您所述,
AuthService
不属于 AppModule
。可能 没有得到单例。
我认为你可以通过将 Injectable({ providedIn: 'root' })
装饰器添加到你的 AuthService
class 来修复它(这也将使服务可摇树)。
LoginComponent 是延迟加载模块的一部分吗?
如果是这样,您需要将 providedIn: 'root' 属性 添加到 AuthService:
@Injectable({
providedIn : 'root'
})
确保将其从模块的提供程序属性中删除。
如果您的 LoginComponent 不是延迟加载的,请确保您只在 AppModule 中导入一次 AuthService。否则你可能会得到多个 AuthService 实例。
如果您希望 AuthService 成为模块的一部分,您可以使用 forRoot 模式来确保服务仅导入一次:
@NgModule({
// declarations, imports and exports only
})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [// your services]
}
}
@NgModule({
imports: [SharedModule.forRoot()]
})
export class AppModule {}
如果在Angular8,你也可以这样做:
@Injectable({
providedIn: SharedModule
})
export class AuthService
您希望同一个 AuthService 实例可用于 AppModule 和您的 LoginComponent 所在的模块。
最后,如果这不是问题所在,您可能会遇到 NavBarComponent 在发出后订阅 changeState$ observable 的问题。在这种情况下,您需要将 changeState 更改为 BehaviorSubject,因此当 NavBarComponent 订阅时,它会收到最后发出的值。
将数据存储在本地存储中并在您想要的组件中的任何位置访问它,只需创建一个共享服务来获取信息并使用它。
通过{{}}字符串插值
服务部件
getUserInfo() {
const savedCredentials = localStorage.getItem(credentialsKey);
return JSON.parse(savedCredentials);
}
组成部分:
this.currentUser = this.authService.getUserInfo();
并像这样访问数据:
this.currentUser.BusinessDate
我想在登录到我的登录组件时将数据传递到我的导航栏组件,但我的导航栏内容没有更新。
我的导航栏组件在应用程序模块中,我的登录组件在另一个模块中。
我试过使用服务共享数据。
我的登录组件,这个组件在另一个模块中
export class LoginComponent {
userCredentials;
constructor(
private readonly _authService: AuthService,
) {
}
login() {
this._authService.auth(this.userCredentials)
.subscribe(
(response: any) => {
const dataForm = {
usuario: response.user,
rol: this.response.role,
};
this._authService.setSession(response);
},
error => {
console.log(error);
}
);
}
}
我的 NavBarComponent,这个组件在 app-module 里
export class NavbarComponent {
isLogged = false;
susbscription: Subscription;
constructor(
private readonly _authService: AuthService,
) {
this.suscripcion = this._authService
.changeState$
.subscribe(
(isLogged) => {
this.isLogged = isLogged;
},
error => console.log(error)
);
}
}
我的导航栏Html
<mat-toolbar color="primary">
<mat-toolbar-row>
<span>SUPERMERCADO</span>
<span class="spacer"></span>
<div *ngIf="!isLogged">
<button mat-button
Login
</button>
</div>
<div *ngIf="isLogged">
<p>Welcome</p>
</div>
</mat-toolbar-row>
</mat-toolbar>
我的服务,这个服务不在app-module中
@Injectable()
export class AuthService {
protected url = environment.url;
protected model = '/user';
isLogged = false;
private changeState = new Subject<boolean>();
changeState$ = this.changeState.asObservable();
constructor(
private readonly _router: Router,
protected readonly httpclient: HttpClient,
) {
}
setSession(data: any) {
this.isLogged = true;
this.changeState.next(this.isLogged);
}
auth(dataForm: any): Observable<any> {
const url = `${this.url}${this.model}/login`;
return this.httpclient.post(url, dataForm);
}
}
我正在使用 angular 8.2.0
来自组件
import { Component, OnInit, ViewChild} from '@angular/core';
import { dataService } from "src/app/service/data.service";
@Component( {
selector: 'app-sideWidget',
templateUrl: './sideWidget.html',
styleUrls: ['./linked-widget.component.css']
} )
export class sideWidget{
constructor( private LWTableColumnNames: dataService ) {
}
ngOnInit() {
this.LWTableColumnNames.refLWTableColumnNames = "patient"; //this line of code will pass the value through data service
}
}
数据服务
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class dataService {
refLWTableColumnNames: string;//creating an object for the data
}
到组件
import { Component, OnInit } from '@angular/core';
import { dataService } from "src/app/service/data.service";
@Component( {
selector: 'app-linked-widget',
templateUrl: './linked-widget.component.html',
styleUrls: ['./linked-widget.component.css']
} )
export class LinkedWidgetComponent implements OnInit {
constructor(private LWTableColumnNames: dataService) { }
ngOnInit() {
console.log(this.LWTableColumnNames.refLWTableColumnNames); // out put will be string "patient"
}
}
Stackbliz demo 这样你就可以将值发送到不同的兄弟组件(不仅是父子组件)
您的代码无法按预期工作可能有 2 个原因。
changeState
主题在 导航栏组件订阅它之前 发出数据。 据我所知,当你在登录页面时,导航栏组件不应该被加载。当你。在您的LoginComponent
中,您 首先发出 数据,然后,当NavbarComponent
加载时,您订阅刚刚发出的 observable。
但是,因为您使用了 Subject,您将 不会获得 last emitted 值。 为了减轻这种情况,您可以使用 BehaviorSubject,它将 retain last emitted value for 新订阅者.
主题与行为主题
const s = new Subject();
s.next('not seen...');
s.next('not seen...');
s.next('not seen...');
s.subscribe(d => console.log('SUBSCRIBER 1: ', d))
// You must first subscribe, as the `Subject` does not holds any values on itself
s.subscribe(d => console.log('SUBSCRIBER 2: ', d))
// `Subscriber 1` will also receive those
s.next('value1 !!');
s.next('value2 !!');
/*
SUBSCRIBER 1: value1 !!
SUBSCRIBER 2: value1 !!
SUBSCRIBER 1: value2 !!
SUBSCRIBER 2: value2 !!
*/
const bs = new BehaviorSubject(null);
bs.next('not seen');
// It will retain only the last value for the new subscribers
bs.next('hmmm!!')
bs.subscribe(v => console.log('subscriber 1 of BS: ', v))
bs.next('value1!')
bs.subscribe(v => console.log('subscriber 2 of BS: ', v))
/*
subscriber 1 of BS: hmmm!!
subscriber 1 of BS: value1!
subscriber 2 of BS: value1!
*/
如果您想探索,Here 是一个 StackBlitz 演示。
因此,如果您将 Subject
替换为 BehaviorSubject(null)
,它应该可以工作。
- 如您所述,
AuthService
不属于AppModule
。可能 没有得到单例。
我认为你可以通过将Injectable({ providedIn: 'root' })
装饰器添加到你的AuthService
class 来修复它(这也将使服务可摇树)。
LoginComponent 是延迟加载模块的一部分吗?
如果是这样,您需要将 providedIn: 'root' 属性 添加到 AuthService:
@Injectable({
providedIn : 'root'
})
确保将其从模块的提供程序属性中删除。
如果您的 LoginComponent 不是延迟加载的,请确保您只在 AppModule 中导入一次 AuthService。否则你可能会得到多个 AuthService 实例。
如果您希望 AuthService 成为模块的一部分,您可以使用 forRoot 模式来确保服务仅导入一次:
@NgModule({
// declarations, imports and exports only
})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [// your services]
}
}
@NgModule({
imports: [SharedModule.forRoot()]
})
export class AppModule {}
如果在Angular8,你也可以这样做:
@Injectable({
providedIn: SharedModule
})
export class AuthService
您希望同一个 AuthService 实例可用于 AppModule 和您的 LoginComponent 所在的模块。
最后,如果这不是问题所在,您可能会遇到 NavBarComponent 在发出后订阅 changeState$ observable 的问题。在这种情况下,您需要将 changeState 更改为 BehaviorSubject,因此当 NavBarComponent 订阅时,它会收到最后发出的值。
将数据存储在本地存储中并在您想要的组件中的任何位置访问它,只需创建一个共享服务来获取信息并使用它。 通过{{}}字符串插值 服务部件
getUserInfo() {
const savedCredentials = localStorage.getItem(credentialsKey);
return JSON.parse(savedCredentials);
}
组成部分:
this.currentUser = this.authService.getUserInfo();
并像这样访问数据:
this.currentUser.BusinessDate