Служба обмена данными Angular 6 Подписка не активирована - PullRequest
0 голосов
/ 18 февраля 2019

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

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

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

Я добавил Сервис в массиве @NgModule providers в файле 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;

 }

}

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

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

Компонент A: Get Value Here

@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.log('Trigger from ComponentB');
    console.log(data);

});

}

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

ОБНОВЛЕНИЕ :

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

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

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

Ответы [ 6 ]

0 голосов
/ 25 февраля 2019

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

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

  2. In 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;
 // }
}
0 голосов
/ 24 февраля 2019

Если я не ошибаюсь, вам нужно либо 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;
  }

}

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

@Component({
  selector: 'a-component',
  template: `Component A 
Data: {{data}}
`,}) класс экспорта AComponent {@Input () name: string;данные: наблюдаемые ;конструктор (личное 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)
  }
}

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

0 голосов
/ 22 февраля 2019

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

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

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

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

0 голосов
/ 18 февраля 2019

Вы можете эффективно использовать Subject вместе с маршрутизатором.Итак, Здесь - это живое решение для вашего сценария, использующее 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.log('Trigger from ComponentB');
    console.log(data);
})
0 голосов
/ 18 февраля 2019
getValue method should return observable.

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

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

Компонент:

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

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

0 голосов
/ 18 февраля 2019

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

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

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

}
...