This is a nice and simple way to access your query params with Angular’s router, however it doesn’t give us any reactive benefits. This means we cannot subscribe to the query params, meaning if they were to change then we couldn’t get notified of the new value!
That’s where subscribing to the query params comes into play! So now depending on your scenario you can make the right choice for you.
Subscribing to Query Params
It’s time to get reactive! Instead of using the snapshot on the activated route, we’ll instead be using the this.route.queryParamMap Observable.
We can then .pipe() off the Observable and use the map operator to return a params.get() method call, passing in the name of the param we’d like to get:
We’d then bind this.filter$ to the Async Pipe via NgIf Async or NgFor Async. Alternatively, we can .subscribe() directly inside the component class:
import{Component,OnInit}from'@angular/core';import{ActivatedRoute,ParamMap}from'@angular/router';import{Observable}from'rxjs';import{map}from'rxjs/operators';@Component({...})exportclassFilterComponentimplementsOnInit{filter$:Observable<string>;constructor(privateroute:ActivatedRoute){}ngOnInit(){this.filter$=this.route.queryParamMap.pipe(map((params:ParamMap)=>params.get('filter')),);// subscribe and log the params when they change// you could set to an internal variable or// bind the filter$ directly to the async pipe// ultimatecourses.com/blog/angular-ngfor-async-pipethis.filter$.subscribe(param=>console.log(param));}}
And that’s it! The benefit to this approach is we could then use something like combineLatest() with some data, and go and grab the item we are looking for from the data based on the query param.
This is enough to get you started though!
Managing subscriptions
Should you unsubscribe from the queryParamMap Observable? Nope! There’s no need. Angular’s router will manage the subscriptions for you, so this makes it a little bit easier and cleaner for us on the component class.
If you are serious about your Angular skills, your next step is to take a look at my Angular courses where you’ll learn Angular, TypeScript, RxJS and state management principles from beginning to expert level.
This makes it nice when dealing with your data in components as we can .pipe() directly off our queryParamMap and have the subscriptions handled for us!
If you’re working on a complex project inevitably you will face the situation when you have to create a custom form control. The essential component of this task will be implementing ControlValueAccessor. There are some articles on the web that explain how to implement it but none provides an insight into what role this component plays in the Angular forms architecture. If you want to know not only how to implement it but also why this article is for you.
Here I’ll first explain why we need ControlValueAccessor and how it’s used inside Angular. Then I’ll demonstrate how to wrap a 3rd party widget into an Angular component and setup communication with a parent component using the standard input/output mechanism. And finally I’ll show how to implement ControlValueAccessor that introduces a new communication mechanism specifically for Angular forms.
FormControl and ControlValueAccessor
If you’ve worked with forms in Angular before you are probably familiar with FormControl. The Angular docs describe it as an entity that tracks the value and validation status of an individual form control. It’s important to understand that when you work with forms, a FormControl is always created regardless of whether you use template driven or reactive forms. With the reactive approach, you create a control yourself explicitly and use the formControl or the formControlName directive to bind it to a native control. If you use template driven approach, the FormControl is created implicitly by the NgModel directive:
<>
@Directive({
selector:'[ngModel]...',...})exportclassNgModel...{
_control =newFormControl();<---------------- here
A formControl created implicitly or explicitly has to interact with a native form control like input or textarea. And instead of a native form control it’s also possible to have a custom form control created as an Angular component. A custom form control usually wraps a control that is written using pure JavaScript like jQueryUI’s slider. Throughout this article I’ll be using “native form control” phrase to distinguish between the Angular specific formControl and a form control you use in HTML. But you should understand that instead of a native form control like input, any custom form control can interact with a formControl.
The number of native form controls is limited, but the variety of custom form controls can be potentially infinite. So, Angular needs a generic mechanism to stand between Angular’s formControl and a native/custom form control. This is where the ControlValueAccessor object comes into play. This is the object that stands between the Angular formControl and a native form control and synchronizes values between the two. Here is what the docs say about it:
A ControlValueAccessor acts as a bridge between the Angular forms API and a native element in the DOM.
Any component or directive can be turned into ControlValueAccessor by implementing the ControlValueAccessor interface and registering itself as an NG_VALUE_ACCESSORprovider. We will see in a minute how this can be done. Among others the interface defines two important methods — writeValue and registerOnChange:
The writeValue method is used by formControl to set the value to the native form control. The registerOnChange method is used by formControl to register a callback that is expected to be triggered every time the native form control is updated. It is your responsibility to pass the updated value to this callback so that the value of respective Angular form control is updated. The registerOnTouched method is used to indicate that a user interacted with a control.
Here is the diagram that demonstrates an interaction:
Again, it’s important to understand that controlValueAccessoralways interacts with a form control created explicitly (reactive forms) or implicitly (template driven).
Angular implements default value accessors for all standard native form elements:
All form directives, including the formControl directive used above, call the setUpControl function to setup interaction between a formControl and a ControlValueAccessor. Here is the code snippet demonstrating that for the formControl directive:
And here is the gist of the setUpControl function that shows how the native and Angular’s form controls are synchronized:
<>
exportfunctionsetUpControl(control:FormControl, dir:NgControl){// initialize a form control
dir.valueAccessor.writeValue(control.value);// setup a listener for changes on the native control// and set this value to form control
dir.valueAccessor.registerOnChange((newValue:any)=>{
control.setValue(newValue,{emitModelToViewChange:false});});// setup a listener for changes on the Angular formControl// and set this value to the native control
control.registerOnChange((newValue:any,...)=>{
dir.valueAccessor.writeValue(newValue);});
Once we understand the mechanics, we can continue implementing our own accessor for a custom form control.
Implementing widget wrapper
Since Angular provides control value accessors for all default native controls a new value accessor is most often implemented to wrap 3rd party plugins/widgets. I mentioned a slider widget from jQueryUI library earlier and this is the plugin we will use for our custom form control.
Simple wrapper
Let’s start with the most basic implementation which just wraps the widget and shows it on the screen. To do that we implement a new NgxJquerySliderComponent and use a DOM element from its template to render the slider:
Here we create a slider widget on the native DOM element using standard jQuery approach. Then we save the reference to the widget into the widget property.
Once we have our wrapper component ready we can use it in the parent App component like this:
With the above implementation our custom slider control doesn’t have any way to interact with the parent component. So let’s use standard input/output mechanisms as communication channels:
Once the slider widget is created we subscribe to its value changes using slidestop event. Once the event is triggered we notify the parent using valueChanges output event emitter. And we also track changes to the input value binding using ngOnChanges lifecycle hook and once the value is updated we set it into the slider widget.
And here is how we use the component now in parent App component:
However, if we want to use our slider as part of a form and communicate with it using template driven or reactive form directives we need to implement a value accessor. And we don’t need standard input/output communication mechanism so we will remove it when implementing the value accessor.
Implementing custom value accessor
Implementing a custom value accessor is not difficult. It requires 2 simple steps:
NG_VALUE_ACCESSOR provider specifies a class that implements ControlValueAccessor interface and is used by Angular to setup synchronization with formControl. It’s usually the class of the component or directive that registers the provider. All form directives inject value accessors using the token NG_VALUE_ACCESSOR and then select a suitable accessor. If there is an accessor which is not built-in or DefaultValueAccessor it is selected. Otherwise Angular picks the default accessor if it’s provided. And there can be no more than one custom accessor defined for an element.
We specified the class directly in component decorator descriptor. However, all default accessors implemented by Angular define a provide outside the class metadata like this:
and so they need to use forwardRef. To learn more about forwardRef read What is `forwardRef` in Angular and why we need it. When implementing a custom controlValueAccessor I recommend specifying a class directly in the decorator descriptor.
Once we defined a provider let’s implement ControlValueAccessor interface:
We are not interested in learning whether user interacted with a control or not so we leave registerOnTouched empty. Inside registerOnChange we simply save the reference to the callback fn function passed by formControl. We will trigger it every time the change in the slider value occurs. And inside the writeValue method we set the value to the slider widget.
So now if we depict the above functionality to the interaction picture it looks something like this:
If you compare two implementations as a simple wrapper and as a controlValueAccessor you should see the interaction with a parent component is different, while the interaction with the underlining slider widget is the same. You may also notice that formControl actually simplifies the interaction with the parent component. We use writeValue where we used ngOnChanges in the simple wrapper and call this.onChange where we emitted value before with this.valueChange.emit(ui.value).
The custom slider control implemented as ControlValueAccessor can now be used like this: