Search code examples
javascriptangularasynchronouspromiseeventemitter

How to get items in asynchronous environment in different components?


I have main component with this code(without imports):

class AppComponent {
    products = null;
    productsUpdated = new EventEmitter();

    constructor(product_service: ProductService) {
        this._product_service = product_service;

        this._product_service.getList()
            .then((products) => {
                this.products = products;
                this.productsUpdated.emit(products)
            });
    }
}

With template: <left-sidenav [productsReceived]="productsUpdated"></left-sidenav>

And component for sorting products:

class LeftSidenavComponent {
    @Input() productsReceived;
    @Output() productsSorted = new EventEmitter();

    categories = []

    constructor(product_list_service: ProductListService) {
        this._product_list_service = product_list_service;
    }            
    ngOnInit() {
        this.productsReceived.subscribe((products) => {
            this.categories = products.map((elem) => {
                return elem.category
            })
        });
    }
}

So when all is drawn, categories array in LeftSidenavComponent is empty. I think that productUpdated event emitter fires earlier than LeftSidenavComponent subscribes to it, but don't know how to handle that.


Solution

  • I would recommend moving the EventEmitter's to the service you have injected like

    @Injectable()
        export class DrinksService {
        drinkSelected = new EventEmitter<any>();
        drinkChanged = new EventEmitter<any>();
        drinksToggle = new EventEmitter<any>();
    }
    

    The above code is an example from one of my projects, but just change the variable names.

    This way rather then relying on the HTML template to modify productsReceived, you simply subscribe to the eventEmitters in ngOnInit.

    Currently, your code is using databinding to an event emitter productsUpdated but you could simply databind [productsReceived]="productsUpdated" where productsUpdated is an empty list. Once productsUpdated is populated with values, it will be reflected in the DOM. You have to populate productsUpdated by subscribing to an event emitter like...

    this.myEmitter
        .subscribe(
            (data)=>this.productsUpdated = data
        );
    

    Does this help? The main thing is to databind to a list, and not an event emitter.