Angular 4/5:在Angular组件之间共享数据

时间:2018-04-17 20:06:57

标签: angular angular5 angular-services angular-data

在我的角应用程序中,当我登录应用程序时,我获得了一个访问令牌,我需要在其他组件的API调用中使用它(不是父/子关系)。 我尝试使用共享服务,但它无法正常工作

数据服务:

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);
});

这里我无法获得使用登录组件更新的tocken。

在共享服务中,我尝试了主题和行为主题,但两者都没有效果。

我确保我只是在app.module.ts中提到这个DataService作为提供者。我在登录组件或任何其他组件中没有提到它

3 个答案:

答案 0 :(得分:0)

在请求中添加令牌的最佳方法是使用拦截器

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));
    }
}

<强>更新:

如果您需要创建可共享的服务 - 您可以尝试使用行为主题。请查看此example

<强> UPDATED2:

如果您想在不刷新页面的情况下使用可共享数据 - 您应该使用localstorage:

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 

答案 1 :(得分:0)

你能说明你如何使用BahviorSubject并解释这是什么意思吗?我认为它应该有用。

首先,您需要在服务中的某个位置声明它,例如

token: BegaviorSubject<type> = new BehaviorSubject(null);

然后在某个地方收到该令牌,您需要设置下一个

this.token.next(receivedToken);

最后,订阅其他组件

this.yourService.token.subscribe(token => {
   this.token = token;
}

如果您有任何错误,请展示。

答案 2 :(得分:0)

@indira:正如@JB Nizet解释的那样,在页面刷新时,您的整个应用程序都会刷新,因此您的主题中包含的任何内容都将丢失!

现在,一个简单的主题也应该在你的情况下工作,你在一个明确调用的函数中订阅主题吗?例如在ngOnInit()

ngOnInit() {
    this.dataService.currentuserInfo$.subscribe((data) => {
      console.log("data subscribed", data);
    })
}

我在我的机器上试过,上面的工作正常。

为什么主题不起作用?

简单Subject失败的可能原因可能是: 您只是测试主题的功能而不是进行实际登录。在您的方案中,您的login组件在实际完成订阅的其他组件之前加载。但是等一下:如果您在订阅之前已经将新数据推送到主题,那么您将无法获得订阅中的数据。只有在下一个this.dataService.updateUserInfo(data.userToken)之后,您才会获得订阅中的值。如果是这种情况,那么您绝对可以使用BehaviorSubject

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

例如:当您从登录组件更新主题时,将数据存储在localstorage中:

this.dataService.updateUserInfo(data.userToken)
localStorage.setItem('serviceData', String(data.userToken));

然后,除了在其他组件中收听主题外,您还可以在localStorage.getItem('serviceData')

上取出令牌ngOnInit()的值

我自己更喜欢localStorage而不是cookies。 Cookie具有每个域的大小和数量限制。见this link for more info。即使localStorage有一个大小限制,但这是巨大的。使用cookies或localStorage也可以清楚地看出SO question.您可以分析您的需求并实施其中任何一个。