Angular 4/5:在 Angular 个组件之间共享数据
Angular 4/5 : Share data between Angular components
在我的 angular 应用程序中,当我登录该应用程序时,我获得了一个访问令牌,我需要在其他组件的 API 调用中使用它(不是 parent/child 关系)。
我尝试使用共享服务,但它不起作用
数据服务:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class DataService {
private userInfo = new Subject<any>();
currentuserInfo$ = this.userInfo.asObservable();
constructor() { }
updateUserInfo(message: any) {
this.userInfo.next(message)
}
}
在我的登录组件中我有
this.dataService.updateUserInfo(data.userToken);
其他组件
this.dataService.currentuserInfo$.subscribe((data: any) => {
console.log(data);
});
这里我无法获取使用登录组件更新的令牌。
在共享服务中,我尝试了 Subject 和 Behavior Subject,但都没有用。
我确保我只是在 app.module.ts 中将此 DataService 作为提供者提及。我没有在登录组件或任何其他组件中提到它
在请求中添加令牌的最佳方式是使用拦截器
import { Injectable, Injector, EventEmitter } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { AuthService } from '../services/auth.service';
@Injectable()
export class HttpsRequestInterceptor implements HttpInterceptor {
private actionUrl: string;
constructor(
private injector: Injector
) {
this.actionUrl = 'https://test.com/dev';
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const _req = {
url: this.actionUrl + req.url,
headers: req.headers.set('Content-Type', 'application/json')
};
const user = this.injector.get(AuthService).getAuthenticatedUser();
if (user) {
user.getSession((err: any, session: any) => {
if (session) {
const token = session.getIdToken().getJwtToken();
_req.headers = req.headers
.set('Content-Type', 'application/json')
.set('Authorization', token);
}
});
}
return next.handle(req.clone(_req));
}
}
更新:
如果你需要创建一个共享服务——你可以尝试使用行为主题。请看这个
更新2:
如果你想在页面刷新的情况下使用可共享数据 - 你应该使用本地存储:
localStorage.setItem('str', 'whatever string'); // set string
localStorage.setItem('obj', JSON.stringify(obj)); // set object
const str = localStorage.getItem('str'); // get string
const obj = JSON.parse(localStorage.getItem('obj')); // get object
const str = localStorage.removeItem('str'); // remove
你能展示一下你是如何使用 BahviorSubject 并解释这不起作用的原因吗?我认为它应该有效。
首先需要在服务的某处声明,例如
token: BegaviorSubject<type> = new BehaviorSubject(null);
然后在您收到该令牌的地方接下来需要设置
this.token.next(receivedToken);
最后,从其他组件订阅它
this.yourService.token.subscribe(token => {
this.token = token;
}
如有错误请指出。
@indira:正如@JB Nizet 所解释的,在页面刷新时,您的整个应用程序都会刷新,因此您的主题中包含的任何内容都将丢失!
现在,一个简单的主题也应该在你的情况下工作,你是否在一个肯定被调用的函数中订阅了主题?例如在 ngOnInit()
里面
ngOnInit() {
this.dataService.currentuserInfo$.subscribe((data) => {
console.log("data subscribed", data);
})
}
我在我的机器上试过,上面的工作正常。
为什么主题不起作用?
简单 Subject
失败的一个可能原因可能是:
您只是在测试 Subject 的功能,而不是进行实际登录。在您的场景中,您的 login
组件在实际完成订阅的其他组件之前加载。但是等等:如果您在订阅之前已经将新数据推送到 Subject,您将不会获得订阅中的数据。只有在下一个 this.dataService.updateUserInfo(data.userToken)
之后,您才会获得 Subscription 中的值。如果是这种情况,那么您绝对可以使用 BehaviorSubject
.
就保存主题的状态而言,您有以下选项:cookies
、localstorage
。
例如:当您从登录组件更新主题时,将数据存储在 localstorage
:
this.dataService.updateUserInfo(data.userToken)
localStorage.setItem('serviceData', String(data.userToken));
然后除了在你的其他组件中监听Subject,你还可以在ngOnInit()
时取出令牌localStorage.getItem('serviceData')
的值
我自己更喜欢 localStorage 而不是 cookie。每个域的 Cookie 都有大小和数量限制。请参阅 this link for more info. Even localStorage
has a size limit, but that's huge. Using cookies or localStorage can also be clear from this SO question. 您可以分析您的需求并实施其中任何一个。
在我的 angular 应用程序中,当我登录该应用程序时,我获得了一个访问令牌,我需要在其他组件的 API 调用中使用它(不是 parent/child 关系)。 我尝试使用共享服务,但它不起作用
数据服务:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class DataService {
private userInfo = new Subject<any>();
currentuserInfo$ = this.userInfo.asObservable();
constructor() { }
updateUserInfo(message: any) {
this.userInfo.next(message)
}
}
在我的登录组件中我有
this.dataService.updateUserInfo(data.userToken);
其他组件
this.dataService.currentuserInfo$.subscribe((data: any) => {
console.log(data);
});
这里我无法获取使用登录组件更新的令牌。
在共享服务中,我尝试了 Subject 和 Behavior Subject,但都没有用。
我确保我只是在 app.module.ts 中将此 DataService 作为提供者提及。我没有在登录组件或任何其他组件中提到它
在请求中添加令牌的最佳方式是使用拦截器
import { Injectable, Injector, EventEmitter } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { AuthService } from '../services/auth.service';
@Injectable()
export class HttpsRequestInterceptor implements HttpInterceptor {
private actionUrl: string;
constructor(
private injector: Injector
) {
this.actionUrl = 'https://test.com/dev';
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const _req = {
url: this.actionUrl + req.url,
headers: req.headers.set('Content-Type', 'application/json')
};
const user = this.injector.get(AuthService).getAuthenticatedUser();
if (user) {
user.getSession((err: any, session: any) => {
if (session) {
const token = session.getIdToken().getJwtToken();
_req.headers = req.headers
.set('Content-Type', 'application/json')
.set('Authorization', token);
}
});
}
return next.handle(req.clone(_req));
}
}
更新:
如果你需要创建一个共享服务——你可以尝试使用行为主题。请看这个
更新2:
如果你想在页面刷新的情况下使用可共享数据 - 你应该使用本地存储:
localStorage.setItem('str', 'whatever string'); // set string
localStorage.setItem('obj', JSON.stringify(obj)); // set object
const str = localStorage.getItem('str'); // get string
const obj = JSON.parse(localStorage.getItem('obj')); // get object
const str = localStorage.removeItem('str'); // remove
你能展示一下你是如何使用 BahviorSubject 并解释这不起作用的原因吗?我认为它应该有效。
首先需要在服务的某处声明,例如
token: BegaviorSubject<type> = new BehaviorSubject(null);
然后在您收到该令牌的地方接下来需要设置
this.token.next(receivedToken);
最后,从其他组件订阅它
this.yourService.token.subscribe(token => {
this.token = token;
}
如有错误请指出。
@indira:正如@JB Nizet 所解释的,在页面刷新时,您的整个应用程序都会刷新,因此您的主题中包含的任何内容都将丢失!
现在,一个简单的主题也应该在你的情况下工作,你是否在一个肯定被调用的函数中订阅了主题?例如在 ngOnInit()
ngOnInit() {
this.dataService.currentuserInfo$.subscribe((data) => {
console.log("data subscribed", data);
})
}
我在我的机器上试过,上面的工作正常。
为什么主题不起作用?
简单 Subject
失败的一个可能原因可能是:
您只是在测试 Subject 的功能,而不是进行实际登录。在您的场景中,您的 login
组件在实际完成订阅的其他组件之前加载。但是等等:如果您在订阅之前已经将新数据推送到 Subject,您将不会获得订阅中的数据。只有在下一个 this.dataService.updateUserInfo(data.userToken)
之后,您才会获得 Subscription 中的值。如果是这种情况,那么您绝对可以使用 BehaviorSubject
.
就保存主题的状态而言,您有以下选项:cookies
、localstorage
。
例如:当您从登录组件更新主题时,将数据存储在 localstorage
:
this.dataService.updateUserInfo(data.userToken)
localStorage.setItem('serviceData', String(data.userToken));
然后除了在你的其他组件中监听Subject,你还可以在ngOnInit()
localStorage.getItem('serviceData')
的值
我自己更喜欢 localStorage 而不是 cookie。每个域的 Cookie 都有大小和数量限制。请参阅 this link for more info. Even localStorage
has a size limit, but that's huge. Using cookies or localStorage can also be clear from this SO question. 您可以分析您的需求并实施其中任何一个。