Skip to main content

Handling Input Bindings

In this section, we will remove this._refreshInterval that defines how frequently our product list should be refreshed and save its data inside the component's state (see input-bindings.start.component.ts.)


Set up @Input bindings

Since parts of our state are passed as input bindings, we need to insert these changes into the component's state. It requires setting values imperatively. The problem with this approach is that it's not composable. That's why in this case we will have to hook into the imperative callback of the refreshInterval component's input binding.

Thus, we have to perform a partial update to our state by providing an object containing the new state slice {refreshInterval: number}. This can be done by using either a reduce function (oldState) => ({refreshInterval: oldState.refreshInterval + 2}) or the state slice itself {refreshInterval: 2}. As no previous state is needed to calculate the new value, we will opt for the latter and provide the slice itself to partially update our state.

Please note that {refreshInterval} is a short form of {refreshInterval: refreshInterval}.

@Input()
set refreshInterval(refreshInterval: number) {
if (refreshInterval > 100) {
+ this.set({refreshInterval});
- this._refreshInterval = refreshInterval;
this.resetRefreshInterval();
}
}

After removing the _refreshInterval, we also have to adopt the related method resetRefreshTick where _refreshInterval is used. As refreshInterval is already part of the component's state, we can easily access the value with this.get('refreshInterval'), using the interval operator to create a new interval.

resetRefreshTick() {
this.intervalSubscription.unsubscribe();
+ this.intervalSubscription = interval(this.get('refreshInterval'))
- this.intervalSubscription = interval(this._refreshInterval)
.pipe(tap((_) => this.listService.refetchList()))
.subscribe();
}

If we edit the input field, we should see the changes in the component's logged state in the template.

Bind the state to the view

In this example, we will use a very simple method and directly bind the complete state of our component to the view. Further performance improvements can be introduced later on.

To bind the state, we can use a simple trick with the structural directive *ngIf, the as syntax, and the async pipe.

<ng-container *ngIf="model$ | async as vm"> </ng-container>

Please note that vm is an abbreviation for view model.

The implementation in our expansion panel will look as follows:

<mat-expansion-panel *ngIf="model$ | async as vm"> </mat-expansion-panel>

Now we can replace the _refreshInterval component in the template with vm.refreshInterval.

<span>
(storeList$ | async)?.length }} Repositories Updated every: {{
vm.refreshInterval }} ms
</span>