Angular 4/5: обмен данными между угловыми компонентами

В моем угловом приложении, когда я вхожу в приложение, я получаю токен доступа, который мне нужен, чтобы использовать его в своих вызовах 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);
});

Здесь я не могу получить токен, который был обновлен с компонентом входа в систему.

В общедоступном Сервисе я пробовал и Subject, и Behavior Subject, но оба не работали.

Я удостоверился, что только что упомянул этот Data Service как провайдер только в app.module.ts. Я не упоминал об этом ни в компоненте входа, ни в каком-либо другом компоненте

3 ответа

Решение

Лучший способ добавить токен в запросах - использовать перехватчик

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

ОБНОВЛЕНО:

если вам нужно создать расшаренный сервис - вы можете попробовать использовать тему поведения. Пожалуйста, посмотрите на этот пример

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 

Можете ли вы показать, как вы использовали BahviorSubject и объяснить, что означает, что это не работает? Я думаю, что это должно работать.

Во-первых, вам нужно объявить это где-нибудь в сервисе, например

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

Затем где-то, где вы получаете этот токен, вам нужно установить следующий

this.token.next(receivedToken);

И наконец, подписывайтесь на него из других компонентов

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

Если у вас есть ошибки, пожалуйста, покажите это.

@indira: Как объяснил @JB Низет, при обновлении страницы все ваше приложение обновляется, поэтому все, что в вас содержится в вашей теме, будет потеряно!

Теперь простая тема также должна была работать в вашем случае. Вы подписываетесь на тему внутри функции, которая определенно вызывается? например внутри ngOnInit()

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

Я попробовал на своей машине и выше работает отлично.

Почему Тема не работает?

Возможная причина для Простого Subject может произойти сбой: вы просто тестируете функциональность Субъекта и не выполняете фактический вход в систему. И в вашем сценарии ваш login Компонент загружается раньше других компонентов, которые фактически сделали подписку. Но подождите: если вы уже отправили новые данные в Subject до того, как он был подписан, вы не получите данные в подписке. Только после следующего this.dataService.updateUserInfo(data.userToken), вы получите значения в подписке. Если это так, то вы можете использовать BehaviorSubject,

Что касается сохранения состояния субъекта, у вас есть варианты, такие как: cookies, localstorage,

например: когда вы обновляете тему из вашего компонента входа, сохраняйте данные в localstorage:

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

И затем, кроме прослушивания темы в других ваших компонентах, вы также можете извлечь значение токена localStorage.getItem('serviceData') на ngOnInit()

Я сам предпочитаю localStorage, а не куки. Файлы cookie имеют размер и ограничение по количеству на домен. Смотрите эту ссылку для получения дополнительной информации. Четное localStorage имеет ограничение по размеру, но это огромно. Использование куки или localStorage также может быть ясно из этого вопроса SO. Вы можете проанализировать ваши требования и реализовать любой из них.

Другие вопросы по тегам