我需要在一个组件(组件A)中设置“值”,并在另一个组件(组件B)中接收该值。组件A和组件B不是父级和子级。
我创建了一个共享服务以在两个组件之间共享数据。我可以从组件B设置值,但是当我订阅以在组件A中获取值时,它不会被触发。
这是我尝试过的:
我在@NgModule
文件的providers
appmodule.ts
数组中添加了Service,以便该服务可用于项目中的所有组件。
服务代码:
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在相同的Page(URL)中时,代码可以完美工作。
当两个组件位于2个不同的页面(URLS)中时,如何在两个组件之间发送数据。
示例:用户打开具有按钮的URL1(渲染组件A),用户单击按钮,然后在具有按钮的新标签页中重定向到URL2(渲染组件B),当用户单击按钮时,我需要将一些数据传递给ComponentA并关闭URL2。我需要检索在ComponentB中传递的数据并在URL1中使用它。可以使用服务吗?如果没有,我应该采用哪种方法?
答案 0 :(得分:4)
您可以有效地与路由器一起使用
Subject
。因此, Here 是使用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);
})
答案 1 :(得分:1)
我认为您需要一个ReplaySubject。您的订阅可观察对象的组件在发出值之后又不再发出可观察对象,因此该可观察对象没有任何价值。 ReplaySubject负责为订阅者提供即使在订阅完成之前发生的所有发射。
@Tushar Walzade解决方案有效,因为两个组件都在app组件内,所以两个观察者都在事件发出之前进行了订阅。 (订阅发生在两个组件的构造函数中,在您单击按钮之前调用)。但是,例如,如果您有一个延迟加载的模块,则只有在加载时才创建一个组件,然后仅当您使用ReplaySubject或rxjs运算符publish或share时才能获取数据
在这里看看:
publish and share operators subjects, behavior subjects and replay subjects
答案 2 :(得分:0)
在您的情况下,您需要订阅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');
});
}
答案 3 :(得分:0)
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
答案 4 :(得分:0)
如果我没有记错的话,您需要在组件a的模板中使用subsribe
或在模板中使用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)
}
}
答案 5 :(得分:0)
问题在于您的服务。设置数据时,主题已发出该值。这样做吧。
在您的服务中将import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private ArrayList<String> data = new ArrayList<String>();
private RecyclerViewWithHeaderFooterAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeData();
initializeRecyclerView();
}
private void initializeRecyclerView() {
mRecyclerView = findViewById(R.id.dummy_rv);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new RecyclerViewWithHeaderFooterAdapter(this, data);
mRecyclerView.setAdapter(adapter);
}
private void initializeData() {
for (int i = 0; i < 10; i++) data.add("Position :" + i);
}
}
设为公开,并且您不再需要BehaviorSubject
方法。
在getValue
中,您从ComponetA
接收数据,订阅CompoenetB
的{{1}}。
修改后的Service类如下。
BehaviorSubject