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.

就保存主题的状态而言,您有以下选项:cookieslocalstorage

例如:当您从登录组件更新主题时,将数据存储在 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. 您可以分析您的需求并实施其中任何一个。