简体   繁体   English

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

[英]Angular 4/5 : Share data between Angular components

In my angular app, when I login in to the app, I get an access token which I need to use it in my API calls in other components (not parent/child relationship). 在我的角度应用程序中,当我登录到该应用程序时,我获得了一个访问令牌,我需要在其他组件的API调用中使用它(不是父/子关系)。 I tried using Shared service but it's not working 我尝试使用共享服务,但无法正常工作

Data Service: 数据服务:

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

}

In my login component I have 在我的登录组件中,我有

this.dataService.updateUserInfo(data.userToken);

Other Component 其他成分

this.dataService.currentuserInfo$.subscribe((data: any) => { 
  console.log(data);
});

Here I am unable to get the tocken that was updated with the login component. 在这里,我无法获取使用登录组件更新的令牌。

In the shared Service I tried both Subject and Behavior Subject but both didn't work. 在共享服务中,我尝试了主题和行为主题,但是都没有用。

I made sure that I just mentioned this DataService as a provider only in app.module.ts. 我确保仅在app.module.ts中提到此DataService作为提供程序。 I didn't mentioned it in login component or in any other component 我没有在登录组件或任何其他组件中提到它

the best way to add token in requests is to use interceptor 在请求中添加令牌的最佳方法是使用拦截器

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

UPDATED: 更新:

if you need to create a shareable service - you can try to use the behavior subject. 如果您需要创建可共享的服务-您可以尝试使用行为主题。 Please look at this example 请看这个例子

UPDATED2: UPDATED2:

if you want to use shareable data in spite of the page refreshing - you should use localstorage: 如果尽管页面刷新但仍要使用可共享的数据,则应使用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 

Can you show how you have been using BahviorSubject and explain what means that this is not working? 您能说明一下您如何使用BahviorSubject并解释这意味着什么不起作用吗? I think that it should work. 我认为应该可以。

First, you need to declare it somewhere in the service, for example 首先,您需要在服务中的某个位置声明它,例如

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

Then somewhere where you receive that token you need to set next 然后在您收到该令牌的地方,接下来需要设置

this.token.next(receivedToken);

And finally, subscribe to it form other components 最后,通过其他组件进行订阅

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

If you have some errors please show it. 如果您有任何错误,请显示出来。

@indira: As @JB Nizet has explained, on a page refresh, your whole application refreshes so whatever in your is contained in your subject, will be lost! @indira:正如@JB Nizet解释的那样,在页面刷新时,整个应用程序都会刷新,因此您主题中包含的所有内容都将丢失!

Now, a Simple subject should also have been working in your case, are you subscribing to the Subject inside a function which is definitely called? 现在,一个简单的主题在您的情况下也应该一直在工作,您是否在某个函数中订阅了Subject,该函数肯定被称为? for example inside ngOnInit() 例如在ngOnInit()内部

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

I tried on my machine and the above works fine. 我在我的机器上尝试过,以上工作正常。

Why was Subject not working? 为什么主题不起作用?

A possible reason for the Simple Subject to fail could be: You are just testing the functionality of the Subject and not doing an actual login. 简单Subject失败的可能原因可能是:您只是测试主题的功能而未进行实际登录。 And in your scenario, your login component is loading before other components which have actually done the subscription. 在您的方案中,您的login组件将在实际完成订阅的其他组件之前加载。 But wait: If you have already pushed new data to the Subject before it has been subscribed, you won't get the data in the subscription. 但是请稍等:如果您已在订阅之前将新数据推送到主题,则不会在订阅中获取数据。 Only after the next this.dataService.updateUserInfo(data.userToken) , you will get the values in the Subscription. 仅在下一个this.dataService.updateUserInfo(data.userToken) ,您才可以在订阅中获取值。 If this is the case, then you can definitely use the BehaviorSubject . 如果是这种情况,那么您绝对可以使用BehaviorSubject

As far as saving the state of the Subject is concerned, you have options like: cookies , localstorage . 就保存主题的状态而言,您可以选择以下选项: cookieslocalstorage

for example: when you are updating the Subject from your login component, store the data in localstorage : 例如:从登录组件更新主题时,将数据存储在localstorage

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

And then apart from listening to the Subject in your other components, you can also take out the value of the token localStorage.getItem('serviceData') upon ngOnInit() 然后,除了侦听其他组件中的Subject之外,您还可以根据ngOnInit()令牌localStorage.getItem('serviceData')ngOnInit()

I myself prefer localStorage over cookies. 我自己更喜欢localStorage而不是cookie。 Cookies have a size and a number limit per domain. Cookie在每个域中都有大小和数量限制。 See this link for more info . 有关更多信息,请参见此链接 Even localStorage has a size limit, but that's huge. 即使localStorage也有大小限制,但这是巨大的。 Using cookies or localStorage can also be clear from this SO question. 从这个SO问题也可以很清楚地使用cookie或localStorage You can analyze your requirement and implement either of them. 您可以分析您的需求并实现它们中的任何一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM