3

Ok can someone please please help me here I feel I'm going crazy!!!

I am having problems getting a list to update in angular2 it seems from looking around I should be using Observables of some sort?

All sounds good but I'm having lots of problems implementing them.

I need help on how to use an observable array and bind to it in angular2 and what are the benefits of using an observable array?

For example I have a list of comments in a model

  this.comments = new Array<IComment>;
  this.observableComments = Observable.from(this.comments);
  // Note what is really odd with the above is typescript thinks 
  // the above is Observable<IComment> ??? not Observable<IComment[]>
  // but when i debug it is ObservableArray with array property - ??

I have the following div in my template

 <div *ngFor="let comment of comments | async | reverseOrder let i = index" >

Ok so far so good but there appears to be NO ability to push or do an onNext with my observable ?!??!!

I have a function called addComment. All I want to do is add a value to my observable array so that my UI updates. I'm not using any data services here..

addComment(comment: IComment) {
  this.comments.push(comment);
  this.observableComments.onNext(this.comments);
  // The above does not work
  // neither onNext - next - push is a function on my observable array??
}

I have done lots of searching and there are suggestions of using Rx Subjects and behaviourSubjects but no examples of how to bind to these in my UI. I get that these are streams but I can't grasp how this would work with my pipes and ordering again no example of this

If I bind directly to my array Angular2 does not detect the changes of the push because it is the same reference.

Other suggestion have been to not use observables at all and just do array.concat to create a new array and a new reference. This seems nuts to me!!!

ObservableArrays seem pointless to me what am I not getting? They certainly don't seem to observe the array, allow me to set a new array value or give me any ability to push onto the array.

Lenny D
  • 1,734
  • 4
  • 22
  • 43
  • Does your component has onPush change detection? Observable can't emit event like onNext. You should use Subject or BehaviorSubject. With Observable you can try to call `this.observableComments = Observable.from(this.comments);` after adding again – yurzui Mar 06 '17 at 13:23
  • No, not using onPush, I can get this to update by subscribing to an event and using the changedDetectorRef and by changing the reference of the array. But I wan't to understand observables and the advantages of using them – Lenny D Mar 06 '17 at 13:24
  • Here is example of using BehaviorSubject in service https://github.com/jhades/angular2-rxjs-observable-data-services/blob/master/src/state/TodoStore.ts – yurzui Mar 06 '17 at 13:27
  • @yurzui. Yes as mentioned this (subject) is what I have seen as a suggestion but I had no success because my template does not seem to like enumerating a Subject and even if i get it working will my ordering pipes then work as these are streams ? – Lenny D Mar 06 '17 at 13:28
  • I would omit using observable and async in your case. http://stackoverflow.com/questions/39757603/unraveling-angular-2-book-chapter-1-example-5/39761822#39761822 So i would replace `push` to `concat` or `spread` operator – yurzui Mar 06 '17 at 13:30
  • @yurzui. Thanks -Have looked at the example you sent. If you look at the backend store all this is doing is saving the value to using the http post and i'm guessing returning the full todo list. Effectively replacing the whole array. This seems very inefficient to me. it will cause Angular to regenerate the whole list again and re-render everything. I'd have thought the point of observables is to detect changes and allow angular to render only these changes. or am i being too granular ? – Lenny D Mar 06 '17 at 13:38

1 Answers1

9

You can try this approach:

private comments: IComment[];
private observableComments: BehaviorSubject<IComment[]>;  

constructor() {
  this.comments = new Array<IComment>;  
  this.observableComments = <BehaviorSubject<IComment[]>>new BehaviorSubject([]);
}

get comments() {
  return this.observableComments.asObservable();
}

addComment(comment: IComment) {
  this.comments.push(comment);
  this.observableComments.next(Object.assign({}, this.comments));
}
Adnan A.
  • 1,932
  • 1
  • 13
  • 18
  • @Annan A. Thanks - This looks much closer to what I want. Whats the benefit of the Object.assign vs just passing this.comments ? – Lenny D Mar 06 '17 at 13:58
  • 1
    This is a part of more functional approach, trying to keep the state somewhat immutable - passing a copy instead of reference. – Adnan A. Mar 06 '17 at 14:04
  • 2
    Shouldn't you be using `Object.assign([], this.comments)` – Jimmy Kane Mar 18 '20 at 19:48