Explosion Pills
Explosion Pills

Reputation: 191779

Call ViewChild methods with updated nested value in Angular2

I am using the angular2-progressbar library to display some circular progress bars in my app. I have a list of inventory items and a service that updates the inventory list. Each inventory item component gets the updated inventory value from a key in the inventory list like so:

export class InventoryComponent implements OnInit {
  @ViewChild(CircleProgressComponent): circleComp: CircleProgressComponent;
  @Input() deviceKey: string;
  private circleOptions: ShapeOptions { /* from angular2-progressbar example */ }
  constructor(private inventoryService: InventoryService) { }
  ngOnInit(): void {
    this.deviceList = this.inventoryService.deviceList;
    setInterval(() => {
      // this value will be 0 or 1
      this.circleComp.animate(this.deviceList[this.deviceKey]);
    }, 2000);
  }
}

While this does work, it seems very hacky to me to have the interval check only after every 2 seconds when the actual value in the template itself gets updated immediately whenever inventoryService updates its device list.

I tried implementing OnChange, but there are two problems:

  1. The initial change fires before the view init lifecycle, i.e. before circleComp is available. This breaks things.
  2. Because this.deviceList is an object and its properties get updated internally, OnChange does not get fired anyway. Instead I can do an additional check using ngDoCheck -- this does work, but it is a lot more verbose and #1 still causes a problem.

Is there any way to start performing checks after the view has loaded?

Upvotes: 0

Views: 620

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 209052

Is there any way to start performing checks after the view has loaded?

Use the AfterViewInit lifecycle hook (override ngAfterViewInit). This is when the @ViewChild is available

I think there may be a better solution than polling deviceList. You could use a Subject in the service. This will act like an observer and observable, so you can subscribe to it on one end, and publish on the other. For example

import { BehaviorSubject } from 'rxjs/BehaviorSubject'

class InventoryService {
  private _inventoryList = new BahaviorSubject<any>({ initialize with data })

  inventoryList$ = this._inventoryList.asObservable();

  set inventoryList(list: any) {
    this._inventoryList.next(list);
  }
}

Now you can just subscribe to the list. And whenever you want to update it, just use the setter, and all the subscribers will get the updated list. No need to poll.

Subscriber

service.inventoryList$.subscribe(list => {})

Publisher

service.inventoryList = newList

See also:

Upvotes: 2

Related Questions