-1

I have a service that connects with api

export class ConsolidadoApi {
  constructor(private http: HttpClient) { }
  getInvestiments(search?: any): Observable<any> {
    return this.http.get<any>(`${environment.basePosicaoConsolidada}`);
  }
}

Response this api:

https://demo5095413.mockable.io/consolidado

This one is responsible for the logic before reaching the component

@Injectable({
    providedIn: 'root'
})
export class CoreService {
    public test;
    constructor(private api: ConsolidadoApi, private state: StateService) { }

public createMenu() {
    this.api.getInvestiments()
        .subscribe(response => {
            console.log(response.carteiras[0])
           this.products = response.carteiras[0]
           return this.products;
        })
}

In my component

export class MenuComponent implements OnInit {

  constructor( private coreService : CoreService ) {}

  ngOnInit(): void {
    console.log(this.coreService.createMenu())
  }

}

But when createMenu is called in menu.component.ts it comes undefined.

enter image description here

Guilherme Lucas
  • 497
  • 6
  • 14

3 Answers3

2

The raw response is an object. forEach works only on an array. If you are aiming for forEach in 'categorias', you should try

this.test.categorias.forEach()
vsnikhilvs
  • 456
  • 1
  • 3
  • 10
1

When you return Observable<any>, that means the argument of the lambda you create when you do subscribe (which you named response) is type any. This doesn't necessary have the function forEach defined (unless the API returns an object with that prototype). That's generally why using any is not good practice; you can't have any expectations on what the object can contain. In fact, it's possible that it's not on object (it could be an array since any is not exclusively an object). If you do want to use forEach, you will want to make sure that response is type array. You can inspect the object's type before using it (e.g. using typeof) and make a judgement on what to call or even just check if the function you're trying to use is defined first, e.g. if (response.forEach !== undefined). You don't actually need to compare to undefined though, so if (response.forEach) suffices. In the examples, I used response, but you can use this.test since they are the same object after the first line in the lambda.

uberhaxed
  • 225
  • 1
  • 9
  • Very good, I managed to solve the foreach problem, but I still couldn't get the data to the component, it's still undefined. How can i solve it? – Guilherme Lucas Sep 30 '21 at 16:31
  • The `console.log` in `MenuComponent` can only print something if `createMenu` returns a value, which it doesn't. – uberhaxed Sep 30 '21 at 16:39
  • Updated a question with result createMenu() in component – Guilherme Lucas Sep 30 '21 at 16:47
  • @GuilhermeLucas You need to have a `return` statement in `createMenu` for the `console.log` to print. – uberhaxed Sep 30 '21 at 16:50
  • Oh Sorry, add return this.products, but not working :( – Guilherme Lucas Sep 30 '21 at 16:51
  • @GuilhermeLucas `this.products` is set sometime in the future and you'll have to wait for the request to complete before reading the value. I would suggest either subscribing to the observable in the menu class so you can directly retrieve the value when it's ready or having your service class emit an event when the values are updated and you subscribe to that event. – uberhaxed Sep 30 '21 at 16:54
  • Good idea, could you show an example how I can do this? How can I declare the createMenu response and a BehaviorSubject? – Guilherme Lucas Sep 30 '21 at 16:56
  • @GuilhermeLucas that return statement actually for the lambda and not for the outer function (`createMenu`). – uberhaxed Sep 30 '21 at 16:56
  • @GuilhermeLucas in your service class, make a new class member such as `public menuUpdated: EventEmitter = new EventEmitter`. Then in your `createMenu` function, in the lambda, after you set `this.products`, you can do `this.menuReady.emit()`. The argument is type any, so you can pass anything in there. In your `MenuComponent` you can then `subscribe` to `CoreService.menuReady` and either read from `this.coreService.products` or pass some value through the event emitter (such as `this.products` in the service class) and that will be the argument of the lambda in your `subscribe`. – uberhaxed Sep 30 '21 at 17:06
0

Based on the link you shared, the response is an object. You can log it to the console to confirm.

You can only call for each on an array, so for example, based on the response api, you can call forEach on the property ‘categorias’ and on that array’s children property ‘produtus’

Edit: this answer was based on the op original api and question

https://demo5095413.mockable.io/carteira-investimentos

    public createMenu() {
        return this.api.getInvestiments()
       }

    ngOnit() {
        this.coreService.createMenu().subscribe(x => console.log(x.categorias))};




{
 "codigo":1,
 "categorias":[
    {
       "nome":"Referenciado",
       "valorTotal":23000.0,
       "codigo":"2",
       "produtos":[
          {
           "nome":"CDB Fácil Bradesco",
           "valor":2000.0,
           "codigo":1,
           "quantidade":0.0,
           "porcentagem":0.5500,
           "aplicacaoAdicional":500.0,
           "codigoInvest":1,
           "salaInvestimento":"CDB",
           "permiteAplicar":true,
           "permiteResgatar":true,
           "movimentacaoAutomatica":false,
           "ordemApresentacao":37,
           "horarioAbertura":"08:30",
           "horarioFechamento":"23:59",
           "codigoGrupo":0,
           "codigoMF":"001
Lee
  • 703
  • 6
  • 20