3

I am quite new to RxJS so I apologize in advance if this has been answered already.

I have an Angular 2 application and in one of the components I have a plain object. I am binding the UI to this object. What I would like to do is to be able to capture all changes to this object regardless if they come from code or from the user changing one of the fields.

I was looking at the observable object but it seems that the subscribers can only receive notifications if the new is pushed via the Emit method. How would this work in the case of a property bound to a input field for example?

Is there a better way of doing this?

Here is what my code looks like:

export class MyComponent {
  app: ApplicationModel = new ApplicationModel(); <--- this is the object I want to track
  
  constructor(api: APIService) {
    api.getApplication().then((data) => {
      this.app = data; 
    });
  }
}

I am looking for something similar to the way Knockout allows you to receive change notifications:

myViewModel.personName.subscribe(function(newValue) {
    alert("The person's new name is " + newValue);
});

Thank you.

dpdragnev
  • 2,011
  • 2
  • 28
  • 55
  • Possible duplicate of [How to detect when an @Input() value changes in Angular2](http://stackoverflow.com/questions/38571812/how-to-detect-when-an-input-value-changes-in-angular2) – Estus Flask Mar 23 '17 at 22:00
  • I don't think so. In my case the object is created in the component itself, it is not imported via @Input – dpdragnev Mar 23 '17 at 22:05
  • You're going the wrong way because this cannot be done. That's why Angular relies on observables and has all these inputs. – Estus Flask Mar 23 '17 at 22:14
  • ok, I guess, I have to rethink the architecture and pass the object with @Input() and then use ngOnChanges. – dpdragnev Mar 23 '17 at 22:17
  • 1
    With the death of `Object.observe()`, this is tricky to do. It would be better to do it properly and use an immutable object and emit every new version of the object via an observable. – GregL Mar 23 '17 at 22:17
  • 1
    Yes, this likely will help. Or ApplicationModel can expose observable(s) and push values to them through prop getters/setters. This depends on how it is being used. – Estus Flask Mar 23 '17 at 22:23

1 Answers1

5

Either when using @Input or simply tracking changes from a service or even the same component, you can use BehaviorSubject.

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

appModel = new BehaviorSubject(new ApplicationModel());

Push new changes:

appModel.next(applicationModelModified);

Subscribe to new changes:

appModel.subscribe(val => ...)

Read value at any point:

appModel.value
zurfyx
  • 31,043
  • 20
  • 111
  • 145
  • Thanks @zurfyx. How would that work with properties that are bound to UI elements (e.g. an input)? do I still have to manually call the next method? – dpdragnev Mar 24 '17 at 14:58
  • @dpdragnev because of how `BehaviorSubject` works, yes. I'm not sure if there's a more direct alternative. Though, for groups of elements (like forms), you might want to listen to changes that affect any of the group (i.e. `this.myForm.valueChanges.subscribe`) and push the changes after you have processed them. – zurfyx Mar 24 '17 at 15:40