In this article i am going to show how we can build nested angular template drived form.
I am assuming you have already known what
ngModelGroup directives are for.
So let’s start with simple form:
There is nothing new here for those how do it every day. We’ve written form containing
lastName fields and we’re expecting the result like:
Now let’s imagine our client has changed requirements and we have to add address fields to our form:
and the value will look as follows:
As the app grows inevitably you will face the situation when you need to reuse address fields from the preceding template.
That’s time to refactor our code. For that we can create
and use it in parent component:
Unfortunately, as soon as we do it, we’ll get the error:
Template parse errors: No provider for ControlContainer (“[ERROR ->]<fieldset ngModelGroup=”address”>
Hmm… Angular complains about
ControlContainer provider for
Let’s try to find solution
— Where does
If we take a look at source code we can notice that
NgModelGroup directives provide it within their
Here is excerpt from
This way angular can’t find
ControlContainer provider that is declared on
NgForm directive lives there).
Now let’s open source code to see where angular requires it.
As we can see angular blocks search for
ControlContainer provider by using Host decorator.
The documentation states that Host decorator:
Specifies that an injector should retrieve a dependency from any injector until reaching the host element of the current component.
Let’s get back to our
AddressComponentand take look at its template:
In order to find provider angular will walk up from
fieldset until it reaches
address host element.
But our parent
ngForm is located within parent template while
NgModelGroup directive requires parent element within current template something like:
<some-element ngForm> <some-element ngModelGroup>
The most straightforward solution would be passing parent
FormGroup to child component. Such approach is typical for model driven form but we can’t pass
Let’s get back to the error:
No provider… No provider… No provider…
Seems angular wants us to declare
ControlContainerprovider. So let’s do it!
For those who know how angular DI works it should be easy. Host decorator gives us the opportunity to get a provider from
viewProviders declared for host element:
Working example could be found on Stackblitz