0

I am having such a difficulty inserting observable into an array. What am I doing wrong here..

app.component.ts

const secondNavList = [];
this.appService.issuerList$.subscribe(iss => {
   iss.forEach(value => {
       console.log(value) //prints {name: 'A', id:'1'} {name: 'B', id:'2'}
       secondNavList.push({
          config: {
              label: value.name
                 id: value.id
          },
          type: 'button'
       });
    });
};
console.log(secondNavList) // prints [] 
//But I want 
//(2)[{...}.{...}]

appService.ts

get issuerList$(): Observable<Issuer[]>{
    return this._issuerList.asObservable();
}

getIssuerList(){
    const url = DBUrl
    this.httpService.getData(url).subscribe((data:any[]) => {
         let issuerList = [];
         data.forEach(x=>{
              issuerList.push(<Issuer>{name: x.issuerName, id: x.issuerId.toString()});
         });
         this._issuerList.next(issuerList)
    })
}

Although inside my secondNavList, it contains data but I can't access it.

2 Answers 2

2

The fundamental issue you have is that you're trying to display the value of secondNavList before it is actually set in the subscriber. The rxjs streams are asynchronous, which implies that the the callback inside the subscribe method that appends to the list will get executed at some unknown point after subscribe is executed.

More importantly, I'd recommend that you try to take advantage of the map operator and array.map method, as well as the asyncronous pipes.

appService.ts

readonly issueUpdateSubject = new Subject<string>();
readonly issuerList$ = this.issueUpdateSubject.pipe(
  switchMap(url => this.httpService.getData(url)),
  map((data: any[]) => data.map(x => ({ name: x.issuerName, id: x.issuerId.toString() }))),
  shareReplay(1)
);

getIssuerList() {
  this.issueUpdateSubject.next(DBUrl);
}

app.component.ts

readonly secondNavList$ = this.appService.issuerList$.pipe(
  map(iss => iss.map(value => ({
    config: { label: value.name, id: value.id },
    type: 'button'
  }))
);
  • In the appService, instead of having an observable update a subject, I just had a subject emit update requests. Then instead of having to convert the subject to an observable, it just is an observable.
  • The shareReplay operator will share the most recently emitted list to any new subscribers.
  • Instead of appending to new arrays, I just use the array.map method to map each array element to the new desired object.
  • Instead of creating new array outside of the observable, and setting them in subscribe, I use the map operator to stream the latest instances of the arrays.

I find the more comfortable I got with rxjs the less I actually set the values of streams to instances of variables and rarely call subscribe - I just connect more and more streams and there values are used in components via async pipes. It's hard to get your head around it at first (or after a year) of using rxjs, but it's worth it in the end.

Sign up to request clarification or add additional context in comments.

4 Comments

Hi thank you for the reply. This answer seems great and I am slowly following your step. I am stuck in this line where you wrote, map((data: any[]) => data.map(x => ({ name: x.issuerName, id: x.issuerId.toString() }))). Does map have to be new Map instead?
No. map is imported from rxjs, or if you are using an older version of rxjs, rxjs/operators. import { map } from 'rxjs';
Oh okay. Thank you. And I am assuming I call getIssuerList() in app.component.ts inside ngOnInit() ? I was able to follow up until here but secondNavList prints AnonymousSubject.
You can call it in the ngAfterViewInit if the secondNavList$ is bound to an attribute of an element that will be part of the dom when the view is first created. Alternatively subscribe to issuerList$ within the service. The key here is there needs to be at least one subscription created when getIssuerList is called. After that the shareReplay will always return the last result to new subscribers even if the number of subscribers goes back down to 0. (btw, using an async pipe creates a subscription)
-1

The error is because the observable value is an object array, and you want to add this into a simple object.

Try this.

const secondNavList = [];
this.appService.issuerList$.subscribe(iss => {
    iss.forEach(value => {
        console.log(value) //prints {name: 'A', id:'1'} {name: 'B', id:'2'}
        value.forEach(v => {
                  
            secondNavList.push({
                config: {
                          label: v.name,
                          id: v.id
                      },
                type: 'button'
            });
        });
    });
 };
    console.log(secondNavList) // prints []

1 Comment

Hi, thank you for the reply. This doesn't work because 'value' is a type of "Issuer" and does not have property 'forEach'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.