Angular 6 数据共享服务订阅未触发

Angular 6 Data Sharing Service Subscribe not triggered

我需要在一个组件(组件 A)中设置值并在另一个组件(组件 B)中接收值。组件 A 和组件 B 不是父子关系。

我创建了一个共享服务来在两个组件之间共享数据。我能够设置组件 B 的值,但是当我订阅以获取组件 A 中的值时,它没有被触发。

这是我尝试过的:

我在 appmodule.ts 文件的 @NgModule providers 数组中添加了服务,以便它可用于项目中的所有组件。

服务代码:

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: 在此处获取值

@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 加载数据 null 时,正在调用 ComponentA 中的触发器。但是当从 ComponentB 调用 buttonClick 时,它不会被调用。

更新:

我发现了问题,我应该正确地表达我的问题。 当 ComponentA 和 ComponentB 在同一个页面 (URL) 中时,代码可以完美运行。

当 2 个组件位于 2 个不同的页面 (URLS) 时,如何在它们之间发送数据。

示例:用户打开 URL1(呈现组件 A),其中有一个按钮,用户单击该按钮并被重定向到新选项卡中的 URL2(呈现组件 B),其中有一个按钮,当用户单击该按钮时,我需要将一些数据传递给 ComponentA 并关闭 URL2。我需要检索在 ComponentB 中传递的数据并在 URL1 中使用它。是否可以使用服务?如果不是,我应该遵循哪种方法?

在你的情况下,你需要订阅 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');
  });

}
getValue method should return observable.

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

您可以删除在 setValue() 方法中调用的 getValue()。

分量:

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

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

我想你需要一个 ReplaySubject。订阅可观察对象的组件在发出值后订阅,因此可观察对象不会再次发出,因此无法从该可观察对象中获得任何价值。 ReplaySubject 负责为订阅者提供甚至在订阅完成之前发生的每一次发射。

@Tushar Walzade 解决方案有效,因为两个组件都在应用程序组件内,因此两个观察者都在事件发出之前进行订阅。 (订阅发生在两个组件的构造函数中,它在您单击按钮之前被调用)。但是如果你有一个延迟加载的模块,例如,一个组件只会在加载时创建,然后你只会在你使用 ReplaySubject 或 rxjs 运算符发布或共享时获取数据

看这里:

publish and share operators subjects, behavior subjects and replay subjects

如果我没记错的话,您需要的是 subsribe 或在组件 a 的模板中使用 async 管道,以便您始终获得可观察流的最新值。

我创建了一个简单的应用程序来向您演示这一点。

假设我们有 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)
  }
}

Here's the snippet which demonstrates the above flow

问题出在您的服务上。当您设置数据时,主题已经发出了值。这样做吧。

  1. 在您的服务中 make BehaviorSubject public 并且您不再需要 getValue 方法。

  2. 在您从 CompoenetB 接收数据的 ComponetA 中,订阅 BehaviorSubjectvalueObs.

修改后的服务class如下。

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