0

I have a method with an observable and the data retrieved from it is processed after in another method. The clasificacionController.listCatalogo returns an observable. This is my code:

getCatalogs(node: CatalogBean): CatalogBean[] {
let children;
    const filterBean = {
      inicio: 0,
      maximo: 0,
      direccion: '',
      sort: undefined,
      id: node.idcatalogo,
    } as FilterBean;
    this.clasificacionController.listCatalogo(filterBean).subscribe(catalogs => {
      console.log('getChildren Catalogs', catalogs);
      children = catalogs;
    });
    return children;
}

Then I use this method to do something else:

toggleNode(node: FlatNode, expand: boolean) {
    const children = this.database.getChildren(node.catalogo); //THIS IS WERE I USE THE METHOD ABOVE
    const index = this.data.indexOf(node);
    if (!node.catalogo.hijos || index < 0) { // If no children, or cannot find the node, no op
      return;
    }


    if (expand) {
      node.isLoading = true;
      //THEN I PROCESS THE DATA HERE
      const nodes = children.map(catalogo =>
        new FlatNode(catalogo, node.level + 1, this.database.isExpandable(catalogo)));
      console.log('Data antes del corte', this.data);
      this.data.splice(index, 0, ...nodes);
      console.log('Data despues del corte', this.data);
      // notify the change
      this.dataChange.next(this.data);
      node.isLoading = false;
    } else {
      this.data.splice(index + 1, children.length);
      this.dataChange.next(this.data);
    }
  }

But the map method trows an error (undefined) because the children variable has no data. There is way to wait for the getChildren method to finish and then use the map. Thanks in advance

Kevin
  • 45
  • 1
  • 1
  • 7
  • your code doesn't work because `this.clasificacionController.listCatalogo` is **asynchrnous**, so `children` will always be unedefined – Olivier Boissé Mar 13 '20 at 21:51

1 Answers1

1

The problem with your code is that you subscribe to the result of an Observable, but your function returns before the Observable fires so the result of your function is undefined. You will have to return the Observable from the function instead, and subscribe to its result where you need it and continue your code there.

You can see this problem in action by adding console.log('Hello') above return children. You will see that 'Hello' is printed before 'getChildren Catalogs': Your function continued and the result of your Observable fires later, asynchronously.

The solution is to return the Observable instead, and subscribe to its result in the context where you need it.

Example based on your code

getCatalogs(node: CatalogBean): CatalogBean[] {
let children;
    const filterBean = {
      inicio: 0,
      maximo: 0,
      direccion: '',
      sort: undefined,
      id: node.idcatalogo,
    } as FilterBean;
    return this.clasificacionController.listCatalogo(filterBean)
}

Your function now returns the Observable and we can subscribe to its result in our current context.

toggleNode(node: FlatNode, expand: boolean) {
    this.database.getChildren(node.catalogo).subscribe(
      children => {
        console.log(children);
        ...
        # The rest of your code here, where you have access to children
        ...
      }
    )
  }
Robin De Schepper
  • 4,942
  • 4
  • 35
  • 56
  • No problem :) I hope this puts you on your way with asynchronous programming. Be sure to look through the [RxJS documentation](https://www.learnrxjs.io/) before your next question – Robin De Schepper Mar 13 '20 at 22:22