Reputation: 13204
I'm trying to watch for an array collection change inside an Angular Service and I can't seem to figure out on how to do that in Angular 5. Basically, I am looking for the same thing as $watchCollection
that we used to have in AngularJS, which is dirty checking and I'm aware of that.
I want to detect changes from within a Service, so I don't think I can or should use @Input
. Also the array that I want to watch for changes, is a property inside an object. The reference that I have inside the Service is this.columnDefinition.collection
(which the collection
is an array of objects). Basically if I push a new object to the collection
array, I want to detect it and do another action.
I tried to use IterableDiffers
and DoCheck
but that doesn't seem to detect or trigger when the collection
array changes.
I also tried using Observable.of
on the array (with RxJS 5
), but this gets executed only on the first time
const observer = Observable.of(this.columnDefinition.collection);
observer.subscribe((col) => console.log(col))
I thought I could use ofArrayChanges
but that got removed from ES6 consideration, and so it also got removed from RxJS 5
and up
I'm also trying to do this without using Subject
since I want the user to only manipulate the array. They shouldn't know there's an observer attach to it
If I compare to the Aurelia framework, I can do exactly that with the following
this.bindingEngine
.collectionObserver(this.columnDefinition.collection)
.subscribe((changes: { index: number, addedCount: number, removed: any[] }[]) => {
console.log('changes ', changes);
console.log('updated collection', this.columnDefinition.collection);
});
and it works, there's nothing fancy here.
EDIT
Just to clarify, the question is more about, can this be done without any special functions or any changes to the array? I know that I can do it with a Subject
and an next
but I'm trying to avoid that (if possible). I want the user to still use regular array push
, pop
, slice
, ... If Aurelia can do it, is that also doable in Angular? ...it used to with $watchCollection
in AngularJS so is there an equivalent in Angular 5?
Upvotes: 0
Views: 1951
Reputation: 527
Because Array is using reference
this.columnDefinition.collection.push(// something);
This will affect the data inside array of course, but the reference
to that array in this case collection
is not changed.
Therefor if you want others component that subscribe to your observable to notify the change, you should also change the reference
itself.
For example:
Service:
private collections: Collection[];//the data that will be emit
private collectionsSubject: BehaviorSubject<Collection[]>;//The subject to emit data
collections$: Observable<Collection[]>;//The public observable that other components will subscribe to
constructor() {
this.collections = [];
this.collectionsSubject = new BehaviorSubject<Collection[]>(this.collections);
this.collections$ = this.collectionsSubject.asObservable();
}
//When ever other place all to this service to add new collection emit new data with new reference
addCollection(collection: Collection) {
this.collections.push(collection);
//Here we will renew the reference and passing it to others component using spread operator
this.fetchOptionsSubject.next([...this.collections]);
}
Component:
this.collectionService.collections$.subscribe((collections: Collection[]) => {
this.collections = collections;
});
You could learn more about Spread syntax
Upvotes: 1