Подписка на службу обмена данными Angular 6 не активирована

Мне нужно установить значение в одном компоненте (компонент A) и получить значение в другом компоненте (компонент B). Компонент A и компонент B не являются родительским и дочерним.

Я создал общий сервис для обмена данными между двумя компонентами. Я могу установить значение из компонента B, но когда я подписываюсь, чтобы получить значение в компоненте A, оно не запускается.

Вот что я пробовал:

Я добавил Сервис в массив @NgModuleproviders в файл appmodule.ts, чтобы он был доступен для всех компонентов в проекте.

Код услуги:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from '../../node_modules/rxjs';

@Injectable({
  providedIn: 'root'
})
export class SocialService {

  constructor() { }

  private valueObs: BehaviorSubject<string> = new BehaviorSubject<string>(null);

 public setValue(value: string):void {
     this.valueObs.next(value);
     this.getValue();
 }

 public getValue():Observable<string> {
     return this.valueObs;

 }

}

Компонент Б: Значение настройки здесь

@Component({
  selector: 'app-componentb',
  templateUrl: './componentb.component.html',
  styleUrls: ['./componentb.component.scss']
})


constructor(private socialService: SocialService, private http: HttpClient) {



}

 buttonClick()
 {

    this.socialService.setValue("linked successfully");
 }

Компонент А: Получить значение здесь

@Component({
  selector: 'app-componenta',
  templateUrl: './componenta.component.html',
  styleUrls: ['./componenta.component.scss']
})


constructor(private socialService: SocialService, private http: HttpClient) {

       this.socialService.getValue().subscribe(data=>{

    console.info('Trigger from ComponentB');
    console.info(data);

});

}

Триггер в ComponentA вызывается, когда ComponentA загружается с данными null. Но он не вызывается, когда buttonClick вызывается из ComponentB.

ОБНОВИТЬ:

Я понял проблему, я должен был правильно сформулировать свой вопрос. Когда ComponentA и ComponentB находятся на одной странице (URL), код работает отлично.

Как отправить данные между двумя компонентами, когда они находятся на двух разных страницах (URLS).

Пример: пользователь открывает URL1 (рендеринг ComponentA), у которого есть кнопка, пользователь нажимает кнопку и перенаправляется на URL2 (рендеринг ComponentB) на новой вкладке с кнопкой, когда пользователь нажимает на кнопку, мне нужно передать некоторые данные в ComponentA и закрыть URL2. Мне нужно получить данные, переданные в ComponentB, и использовать их в URL1. Можно ли использовать Сервисы? Если нет, то какой подход мне следует использовать?

Укажите минимальный воспроизводимый пример, так как это должно работать.

user4676340 18.02.2019 08:55

Вы можете сделать это stackblitz.com

user4676340 18.02.2019 08:55

@trichetriche, я обновил свой вопрос, не могли бы вы проверить.

Anirudh 19.02.2019 09:50

@TusharWalzade, не могли бы вы указать мне какой-нибудь пример кода или учебник?

Anirudh 20.02.2019 15:28

@RafaelLima, пожалуйста, посмотрите обновление в моем вопросе.

Anirudh 20.02.2019 15:53

может это поможет angular.io/guide/component-interaction

Rafael Lima 20.02.2019 15:53

Вы пробовали ReplaySubject?

Erbsenkoenig 26.02.2019 09:31

это сработало и для меня в ionic4

saber tabatabaee yazdi 12.12.2019 08:35
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
8
8
7 785
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

В вашем случае вам нужно подписаться на this.valueObs, а не на метод, включающий это, поскольку ваша переменная valueObs имеет наблюдаемый тип, поэтому вы можете напрямую подписаться на это следующим образом:

constructor(private socialService: SocialService, private http: HttpClient) {

  this.socialService.getValue().subscribe(data=>{
    console.info('Trigger from ComponentB');
    console.info(data);
  });
  this.socialService.valueObs.subscribe(data=>{
    console.info('Trigger from ComponentB on Next called');
  });

}
valueObs.subscribe метод вообще не вызывается. Также не вызывается метод getValue().subscribe.
Anirudh 18.02.2019 09:38
getValue method should return observable.

public getValue():Observable<string> {
     return this.valueObs.asObservable();
}

Вы можете удалить getValue(), который вызывается в методе setValue().

Компонент:

this.socialService.getValue().subscribe(data=>{
    console.info('Trigger from ComponentB');
    console.info(data);
  });

StackBlitz: https://stackblitz.com/edit/angular-e6uxlo?file=src%2Fapp%2Fhello.component.ts

Тоже пробовал, не работает. Есть ли что-то еще, что я могу упустить?

Anirudh 18.02.2019 09:11

вместо вызова конструктора() внутри ngOnInit

Suresh Kumar Ariya 18.02.2019 09:14

Обновлен стекблиц

Suresh Kumar Ariya 18.02.2019 09:51

Если вы хотите обмениваться данными между компонентами в Tab. Лучше сохранять данные в локальном хранилище и получать к ним доступ в других местах.

Suresh Kumar Ariya 19.02.2019 18:07
Ответ принят как подходящий

You could effectively use Subject along with the router. So, Here is a live solution for your scenario using Router & Subject.

Ваш сервис будет просто содержать -

public setValue(value: string): void {
    this.valueObs.next(value);
}

public getValue(): Observable < string > {
    return this.valueObs;
}

Тогда ваш ComponentB будет содержать -

buttonClick() {
    this.socialService.setValue("linked successfully");
    this.router.navigate(['/a']);
}

И ваш конструктор ComponentA будет содержать -

this.socialService.getValue().subscribe(data => {
    this.dataFromB = data;
    console.info('Trigger from ComponentB');
    console.info(data);
})

Я думаю, вам понадобится ReplaySubject для этого. Ваш компонент, подписавшийся на наблюдаемое, подписывается после того, как значение было испущено, и, следовательно, наблюдаемое больше не испускается, нет никакого значения, которое можно было бы получить от этого наблюдаемого. ReplaySubject заботится о том, чтобы предоставить подписчику все выбросы, которые произошли еще до того, как подписка будет завершена.

Решение @Tushar Walzade работает, потому что оба компонента находятся внутри компонента приложения, поэтому оба наблюдателя подписываются до того, как событие было отправлено. (Подписка происходит внутри конструктора для обоих компонентов, который вызывается перед нажатием кнопки). Но если у вас есть лениво загруженный модуль, например, один компонент будет создан только при загрузке, а затем вы получите данные только в том случае, если вы используете ReplaySubject или оператор rxjs для публикации или совместного использования.

Посмотрите здесь:

публиковать и делиться операторамисубъекты, субъекты поведения и субъекты воспроизведения

Ваш комментарий только что спас мой день. Спасибо!

Juanma 24.08.2020 19:03

Если я не ошибаюсь, вам нужно либо subsribe, либо использовать async канал в шаблоне для компонента a, чтобы вы всегда получали последнее значение наблюдаемого потока.

Я создал простое приложение, чтобы продемонстрировать вам это.

Допустим, у нас есть 2 маршрута, каждый из которых отрисовывает соответствующий компонент (a, b).

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

Injectable()
export class MyService {

  private _data = new BehaviorSubject<string>(null);

  setValue(value: string): void {
    this._data.next(value)
  }

  get data(): Observable<string> {
    return this._data;
  }

}

Затем в компоненте a мы прослушиваем изменения наблюдаемого потока службы.

@Component({
  selector: 'a-component',
  template: `Component A <br> Data: <pre>{{data}}</pre>`,
})
export class AComponent {
  @Input() name: string;

  data: Observable<string>;

  constructor(private myService: MyService) {
    this.myService.data.subscribe(data => this.data = data);
  }

В компоненте b мы просто редактируем данные с помощью сервиса setValue.

@Component({
  selector: 'b-component',
  template: `Component B <br> 
  <input type = "text" placeholder = "set data for component a" [(ngModel)] = "modifiedData" (ngModelChange) = "editServiceData($event)"/>`,
})
export class BComponent  {
  @Input() name: string;
  modifiedData;

  constructor(private myService: MyService) {}

  editServiceData(data: string) {
    this.myService.setValue(data)
  }
}

Вот фрагмент, демонстрирующий приведенный выше поток

Проблема в вашем сервисе. Когда вы устанавливаете данные, субъект уже выдал значение. Делай так.

  1. В вашем сервисе сделайте BehaviorSubject общедоступным и вам больше не нужен getValue метод.

  2. В ComponetA, где вы получаете данные от CompoenetB, сделайте подписку на BehaviorSubject, который является valueObs.

Модифицированный класс обслуживания следующим образом.

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable()
export class SocialService {

  public valueObs: BehaviorSubject<string> = new BehaviorSubject<string>(null);

  constructor() {}

  public setValue(value: string):void {
     this.valueObs.next(value);
     // this.getValue();
  }

 // public getValue():Observable<string> {
 //     return this.valueObs;
 // }
}

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