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)
}
}
问题出在您的服务上。当您设置数据时,主题已经发出了值。这样做吧。
在您的服务中 make BehaviorSubject
public 并且您不再需要 getValue
方法。
在您从 CompoenetB
接收数据的 ComponetA
中,订阅 BehaviorSubject
即 valueObs
.
修改后的服务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;
// }
}
我需要在一个组件(组件 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 usingRouter
&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)
}
}
问题出在您的服务上。当您设置数据时,主题已经发出了值。这样做吧。
在您的服务中 make
BehaviorSubject
public 并且您不再需要getValue
方法。在您从
CompoenetB
接收数据的ComponetA
中,订阅BehaviorSubject
即valueObs
.
修改后的服务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;
// }
}