Как обмениваться данными между службами и компонентами angular?

Как связать данные между сервисами и компонентами в режиме реального времени.

давайте предположим isAuthenticated общедоступная переменная для службы аутентификации, которая влияет на некоторое представление в компоненте. Мой вопрос: как подписаться на переменную isAuthenticated?

Оказание услуг:

import { Injectable } from '@angular/core';

@Injectable()
export class Authentication {

  isAuthenticated:boolean = false;

  login() {
    localStorage.setItem('access_token', 'true');
    this.isAuthenticated = true;
  }
}

Компонент:

...
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
private isAuthenticated:boolean = false;
  constructor(public authService: Authentication) { 
   this.isAuthenticated = this.authService.isAuthenticated'
  }
}

home.html

...
<div *ngIf = "isAuthenticated">Authentication view</div>
<div *ngIf = "!isAuthenticated">Unauthentication view</div>
...

Судя по текущему потоку выше, привязка работает хорошо, но не в реальном времени.

Итак, каков наилучший подход:

1- Создайте наблюдаемую внутри службы аутентификации, чтобы подписаться на нее внутри компонента.

2- Связывание следующим образом:

...
<div *ngIf = "authService.isAuthenticated">Authentication view</div>
<div *ngIf = "!authService.isAuthenticated">Unauthentication view</div>
...

The second approach is working well but I don't know if it is the best practice.

Спасибо.

Не выполняйте запросы в конструкторе (т. е. вызывайте службу для проверки подлинности). Вместо этого внедрите OnInit в свой компонент и сделайте это там.

Igor 12.03.2019 20:44
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
267
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Я предполагаю, что из вашего тега вы используете Ionic framework? Можно ли это сделать с помощью событий?

    // first page (publish an event when a user is created)
constructor(public events: Events) {}
createUser(user) {
  console.info('User created!')
  this.events.publish('user:created', user, Date.now());
}


// second page (listen for the user created event after function is called)
constructor(public events: Events) {
  events.subscribe('user:created', (user, time) => {
    // user and time are the same arguments passed in `events.publish(user, time)`
    console.info('Welcome', user, 'at', time);
  });
}

Пример кода взят из: https://ionicframework.com/docs/v3/api/util/Events/

можно ли создать событие в провайдере (сервисе)?

Khaled Ramadan 12.03.2019 20:48

Это должно быть возможно, но я не уверен, что это лучшая практика, что вызывает метод «логин»? Это можно изменить так, чтобы он возвращал наблюдаемое или обещание, а затем из этого вызова событие Ionic (при условии, что то, что вызывает его, находится не на той же странице, с которой вы вызываете «вход», и в этом случае событие не будет необходимо ).

WebFletch 12.03.2019 20:52

Я не думаю, что вы можете изменить значение события, например ... next (false) или что-то в этом роде.

Khaled Ramadan 12.03.2019 21:02
Ответ принят как подходящий

Я бы рекомендовал использовать BehaviorSubject. Это Observable, поэтому вы можете подписаться на него, но вы также можете контролировать, когда он выдает новые значения, вызывая behaviorSubject.next(newValue). При создании BehaviorSubject вы должны передать ему начальное значение. В вашем случае это false.

@Injectable()
export class Authentication {

  isAuthenticated = new BehaviorSubject<boolean>(false);

  login() {
    localStorage.setItem('access_token', 'true');
    this.isAuthenticated.next(true);
  }

}

-

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  private isAuthenticated:boolean;

  constructor(public authService: Authentication) { 
   this.authService.isAuthenticated
    .subscribe(isAuthenticated => this.isAuthenticated = isAuthenticated)
  }

}

или вы можете подписаться в html с помощью Async Pipe

export class HomePage {

  private isAuthenticated: BehaviorSubject<boolean>;

  constructor(public authService: Authentication) { 
   this.isAuthenticated = this.authService.isAuthenticated;
  }

}

-

<div *ngIf = "isAuthenticated | async">Authentication view</div>
<div *ngIf = "!(isAuthenticated | async)">Unauthentication view</div>

В отличие от обычного Observable, когда вы вызываете subscribe для BehaviorSubject, функция, которую вы передали в качестве аргумента для подписки, будет немедленно выполнена. Это связано с тем, что BehaviorSubject всегда имеет значение. Вы можете получить к нему доступ с помощью this.authService.isAuthenticated.value, но здесь это не очень полезно.

Как импортировать BehaviorSubject?

Khaled Ramadan 12.03.2019 21:07

какую версию RxJS вы используете?

displayName 12.03.2019 21:11

для RxJS v6+ вы можете импортировать его вот так import { BehaviorSubject } from 'rxjs';

displayName 12.03.2019 21:12

Используйте RXJS. Использование BehaviourSubjects позволяет вам передавать состояние и подписываться на изменения состояния в нескольких компонентах, которые внедряют службу и имеют начальное состояние. При определении BehaviourSubject вы также должны определить начальное значение, которое здесь равно false. Все, что вам нужно сделать, это вызвать .next(true) в BehaviourSubject для отправки состояния, как показано ниже:

...
@Injectable()
export class Authentication {

  private _isAuthenticated: BehaviourSubject<boolean> = new BehaviourSubject(false);

  public get isAuthenticated(): Observable<boolean> {
    return this._isAuthenticated.asObservable();
  }

  login() {
    localStorage.setItem('access_token', 'true');
    this._isAuthenticated.next(true);
  }
}

Использование метода get в вашей службе позволяет вам возвращать наблюдаемое без публичного раскрытия методов BehaviourSubject.

Затем в вашем компоненте:

...
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage implements OnInit {
  private isAuthenticated:boolean = false;
  private readonly _authService: Authentication;
  constructor(authService: Authentication) {
    this._authService = authService;
  }

  public ngOnInit(): void {
   this._authService.isAuthenticated
     .subscribe((isAuthenticated) => this.isAuthenticated = isAuthenticated)
  }
}

На данный момент я использую это решение:

import { DoCheck } from '@angular/core';

//...

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  private isAuthenticated:boolean = false;
  constructor(public authService: Authentication) { }

  ngDoCheck() {
      if (this.authService.isAuthenticated)) {
        //..if authenticated do this
      } else {
        //..if not do this
      }
  }
}

Даже если я не уверен, что это хороший способ.

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