Passing Data with Subjects and Proxies

2019-01-08 01:29发布

Is it possible to have a 2 way data flow using Subjects in a service? Suppose for example that I want some component to retrieve information and then post it through the service Subject for other another component to consume.

The consuming component then makes some changes to this information and then re-posts it so that the original component can retrieve changes.

Is this possible using the Observer pattern?

Also, if I wanted to watch this data for changes (let's say that the data came in through an array), would I have to use a proxy to accomplish this?

标签: angular rxjs
2条回答
戒情不戒烟
2楼-- · 2019-01-08 01:55

When passing data between components, I find the RxJS BehaviorSubject very useful.

You can also use a regular RxJS Subject for sharing data via a service, but here’s why I prefer a BehaviorSubject.

  1. It will always return the current value on subscription - there is no need to call onnext().
  2. It has a getValue() function to extract the last value as raw data.
  3. It ensures that the component always receives the most recent data.
  4. you can get an observable from behavior subject using the asobservable() method on behavior subject.
  5. Refer this for more

Example

In a service, we will create a private BehaviorSubject that will hold the current value of the message. We define a currentMessage variable to handle this data stream as an observable that will be used by other components. Lastly, we create the function that calls next on the BehaviorSubject to change its value.

The parent, child, and sibling components all receive the same treatment. We inject the DataService in the components, then subscribe to the currentMessage observable and set its value equal to the message variable.

Now if we create a function in any one of these components that changes the value of the message. The updated value is automatically broadcasted to all other components.

shared.service.ts

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

@Injectable()
export class SharedService {

  private messageSource = new BehaviorSubject<string>("default message");
  currentMessage = this.messageSource.asObservable();

  constructor() { }

  changeMessage(message: string) {
    this.messageSource.next(message)
  }

}

parent.component.ts

import { Component, OnInit } from '@angular/core';
import { SharedService } from "../shared.service";

@Component({
  selector: 'app-sibling',
  template: `
    {{message}}
    <button (click)="newMessage()">New Message</button>
  `,
  styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {

  message: string;

  constructor(private service: sharedService) { }

  ngOnInit() {
    this.service.currentMessage.subscribe(message => this.message = message)
  }

  newMessage() {
    this.service.changeMessage("Hello from Sibling")
  }

}

sibling.component.ts

import { Component, OnInit } from '@angular/core';
import { SharedService } from "../shared.service";

@Component({
  selector: 'app-sibling',
  template: `
    {{message}}
    <button (click)="newMessage()">New Message</button>
  `,
  styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {

  message: string;

  constructor(private service: SharedService) { }

  ngOnInit() {
    this.service.currentMessage.subscribe(message => this.message = message)
  }

  newMessage() {
    this.service.changeMessage("Hello from Sibling");
  }

}
查看更多
Lonely孤独者°
3楼-- · 2019-01-08 01:59

Thats totally possible:

  1. Figure out what type of subject you need, normal subject, Behaviour Subject or Replay subject. Each has its own use case, I'd recommend taking a look at this question for a clear and concise explanation: Angular 2 special Observables (Subject / Behaviour subject / ReplaySubject).

  2. Declare your subject in a service.

  3. Call a next() value in your main component which your second component will listen to.

  4. You can then subscribe to that subject from your secondary component and modify it.

  5. From here you can either call the next() value on the same subject using the modified data or create a separate subject in your service and use that to pass your modified data into. Either case you can subscribe in your main component to get that data. I'd recommend the later option though as I'm assuming if you modify the data you'll change the object and it's good to strictly type your subjects to catch errors.

Hope this helps.

查看更多
登录 后发表回答