If you’ve worked with AngularJS, you probably remember the ng-model-options directive.

The two most useful options in this directive were the updateOn and the debounce options.

For example, if we wanted to update the model only on blur or add a debounce functionality we could write the following code:

Unfortunately, Angular has not implemented this feature in the new version. Let’s try to create our own version of ng-model-options in Angular using RxJS and custom form control. We will focus on the two options mentioned above.

ngControlOptions Directive

Let’s start with the basic template of custom form control. If you are not familiar with creating custom form controls in Angular, you can read my article — Angular Custom Form Controls Made Easy.

We are targeting every element with the formControlName/formControl and the ngControlOptions attributes. (if you are working with ngModel ,make sure to add those too).

Our goal is to gain control over the view->model updates, so we need to focus on the onChange method which is responsible for this.

We eventually want to achieve the following result:

Let’s start with the ngControlOptions Input.

We have a simple Input that accepts the options and extends the default ones.

Next, we need to listen to all the events listed in the updateOn key and execute the same piece of code when one of them fired. For this task, we will use two handy Rx observables.

fromEvent — creates an observable sequence by adding an event listener to the matching DOMElement.

merge — merges all the observable sequences into a single observable sequence.

Now we just need to take care of the debouncing functionality. We can’t use the debounceTime operator because we require more control on the timeout duration argument.

Luckily Rx provides the debounce operator that can also take a durationSelector function —

Selector function to retrieve a sequence indicating the throttle duration for each given element.

We are returning a timer observable that indicates the throttle duration (i.e., the debounce time) based on the debounce parameter.

🤓 A little improvement

In the above implementation, we always create the timer , even if we don’t need the debounce functionality. It’s not the end of the world, but we can do better.

We can use the let operator to get the whole observable and decide if we need to add the debounce functionality to our stream or not.

Much better 💪. You can find the full source code here.

Follow me on Medium or Twitter to read more about Angular, Vue and JS!