Hi. It's time for the deep dive into angular
forms and in this video I'm going to show you how you can reuse your form
control or the group of form controls By extracting them into a separate
component and then reuse this component in other angular forms in your angular
Application if you try to do it before probably, you know that it is not as easy
as it seems If you continue watching, you will see in action a couple of
quite rare Angular features like host resolution modifier and view providers. And besides that, we will dive into
a source code of Angular forms to understand a little bit more about
How they were designed and how they work under the hood and there we will
actually find the key to Usable forms. My name is Dmytro Mezhenskyi and on my
youtube channel, you can find already hundreds hundreds of advanced and
unique angular tutorials So subscribe right now, continue watching, and
let's learn more about Angular forms. First of all, I would like to mention
that And everything you will learn in this tutorial, and you will learn quite a lot. This is just a tiny part of my entire in
depth video course about Angular forms. And later in this video, I will show you
exactly what you will learn from there and which really complex form controls you
will be able to build out of the course. But now let's focus on our concrete
use case and let's learn how to make form controls reusable
in your Angular applications. So here I've got a very simple form that
consists of three form controls and two of them, they are grouped within the
nested form group called delivery address. And here you can see
the HTML of this form. You can see I use reactive forms for that. Here's the form group, which
represents the root form group. And here. display name form control, the
delivery address form group and two nested form controls inside. And this is how looks the form
model for this concrete form. So as you can see, very
simple, regular, reactive form. Now imagine that your goal is
to reuse this entire address form group inside Another form. So basically you want to exclude it
into a separate component and include this component In every form where you
need this address form group, right? So what you would do in this case most
probably you would take this whole form group and exclude it from This
template and you would create some another component like I did it right
now and you would place this whole template here, just like that, right? Then you would need to import also
reactive forms module to make it work. And then you would need to go to
the app component and also import these address group component. And instead of the previous. Uh, form group, you would
use this app address group component just like that, right? But let's save, uh, this change and have
a look at the console of our browser. And there we see the following error. So the form group name must be used
within a parent form group directive. You will want to add blah, blah,
blah, blah, blah, and so on. So the general idea of this message
is that the form group directive has to be used within the same view
with the form group name directive. So it means that we can solve this
problem by applying the form group directive within This child component
and provide the root form group as a argument for this form group
directive So it would look like this. So here's my form group directive and
we have to wrap this everything with this form group, right and we have
to provide the root form group as a Input parameters, so I would create
some input here, call it form and say that it is going to be the form Group,
and of course I have to go back and provide this form Just like that, right? And now if I reload the page
You can see the error has disappeared and my form is works. But guys, look, just look at this. Look at this. This is also the terrible part because
we have to always propagate the parent form group down to the child. Um, we need a lot of boilerplate
to make this form just working. And it would be so cool if we
could get rid of all this stuff, remove this and also this input. Why we cannot just make it
work, why do we need to do a lot of these unnecessary actions? And here I will show you the solution,
but for that we have to investigate the source code a little bit and
figure out how it actually works. So welcome to the source code of
the form group named directive. As you can see, it is just a regular form. Angular directive, right? So there is no magic inside
Angular forms actually. And, uh, the problem actually in
this line, what this line is doing. So in order to properly work the
form group name directive, when it is being initialized, it has
to register its own instance. Inside the parent control
container the control container. This is the payments injection provider
token that points to Other directive instances that are responsible for
the, uh, form control grouping. If we're talking about reactive
forms, those are, uh, form group name directive, form group directive,
and form array name directive. If we're talking about
template driven forms. This is ngModelGroupDirective And this
binding of the provider token and concrete directive instance happens by configuring
the providers As you can see here, there is provided control container token that
points to the instance of the form group name directive Alright, and if you have
a look at some other directive that is responsible for controls grouping There
you can find a similar provider where the control container token provided
and it points to this time to the form group directive instance right okay
i hope this part is pretty much clear and now let's very quickly talk how the
control container is being resolved so here you can see a group of resolution
modifiers the skip self resolution modifier instructs angular that it
has to start looking for the control container provider starting from the
parent injector, not from the injector of this directive, because otherwise
you will get the circular dependency, but starting from the parent one. The host resolution modifier is very
tricky and it tells that Angular should look for the provider for the control
container within the same template. Where this form group name
directive is used a bit tricky. Yeah, I know So that's why let's go back
to our project and let me revert back our Working solution with the form group
rubber So what happened why it was working this solution because here's the form
group name directive This is the one which source code we just investigated and then
it tries to inject their control container from the closest parent injector. The closest parent injector will be the
injector of the form group directive. And this injector has the provider
for the control container. And because, uh, this injector
is located within the same. template within the same view, that's
why the form group name properly resolves the parent control container. But when we remove it like that, in this
case the closest injector that contains the provider for control container is
inside the form group directive that is used in the app component view. But the host resolution modifier
says, uh, uh, uh, You are not allowed to inject control container that is
located outside of the view Where the current directive instance has
been created So that's why this form group name directive doesn't see the
control container provider From the app component view and that's why it fails. Phew, I have been recording this
part almost So I really hope that you understood how this everything
works, but yeah, let's move forward. So basically to solve our problem, we
have to provide the control container for address group component that
points to the parent control container. And it has to be done within the
view of the address group component. So, how we can do that? You could think that we could configure
providers property right here. So, let's try. I use providers. Here I provide the object. Where I define the provide here. This is going to be the control. container, right? And, um, and the value of it
has to be that parent container. So for that, I would use the
useFactoryDependencyProvider. And this is the function where I
can actually inject the control container, but I will use also
skipSelfResolutionModifier. But as you can see, it still doesn't work. We still have the same issue. And this is again because of
the host resolution modifier. Because host resolution modifier
doesn't even allow you to look into providers inside that same component. And that's why we have to use a Quite
rare feature in Angular and namely we have to use ViewProviders Because
this is the last place where the HostResolutionModifier can look for
providers All right, and if we save it right now, you can see that the error has
disappeared and Our form remains working. So finally, congratulations. We got read from the
boilerplate here and there. We got read from the input. We just use the view provider that can
provide a control container token for the directives here inside this template. Beautiful, but we still
have a little problem. And currently the issue is that
the functionality is kind of Split between two components inside. Address group component, we have the
view part, but the model that relates to this form, namely this one, it
is located in separate component. It would be great if we could keep
everything in one place and if the address group could register
the proper form control models. Right? So how can we do that? Well, we can again use the control
container that we can inject. So let's inject the control container. And in this control container, I'm
interested in the corresponding instance of the Form group model. So let's create a dedicated getter. Let's name it like parent form group. Doesn't matter. And it will return parent container
and namely the control property and let's cast it as a form group. It is pretty safe to do that because
the control of the control container will be always that form group. And the form group provides you a
set of methods that allow you to add or remove some certain form
control instances from this group. So once the address group component
is being initialized, so let's use the ngOnInit lifecycle hook, and here, after
the initialization, We will use this parent form group in order to add the new
control and which control we are going to add we are going to add exactly this
part so we can completely cut it from here and just go and place it right here and
i have to just uh fix it a little bit so it is going to be the name of the control
right and the second argument it is the values, which exactly, uh, FormControl
or FormControlGroup we have to register. And in my case, it will be
the FormGroup with addresses. And of course, I have to import
the FormControl model right here. And this is it. So if I save everything, you can
see that everything works fine. but also don't forget that this
component can be destroyed so you have to handle also this case and for that
let's use the ngOnDestroy lifecycle hook and the similar way we just
remove control and we say that we will remove exactly This control, right? So here we go. And as you can see, uh,
my form still works. And if I type some stuff here and try
to submit it, you can see that delivery address was hooked up and added. To this form group, even though we
don't declare it right here, it happens automatically when the address group
component is being initialized, but we can go even further and make it
not that hard coded, but make it. really dynamic and for that we can
introduce a couple of inputs the first one can be like ctrl key that is empty string
and we can also make it required in the latest angular version you can configure
input as a required which is really cool and useful and then this ctrl key we use
in Instead of these strings, just like that, it means that we can configure their
control key just like a regular input. This is the, this is the
delivery address, right? And we can also provide
something like label, right? So here we can configure
the string as well. So let's do a new input and
it's going to be a label. It is not required by default. It's just an empty string and we will use
this label where we will use it right here So here we go And now we can do what we
can provide this label as an input as well So in my case, it is a delivery address
right, I save it and it remains working and every time when you have to reuse this
address group you Just have to add it and it will be For example, I could have a use
case when I want to reuse the same group within even the same form, because often
we provide their delivery address, right? And we have something like
a billing address, right? And usually they're identical. And, uh, here I just have to adjust
the label and obviously their control key and change it to billing address. And I save it. And imagine that user fills the form. South Metro, zip code is 111,
street is FFFFF, billing address will be zip code 22222, and street,
I don't know, MMMMM, whatever. And now I submit the form and you
can see that both billing address... Okay, billing address didn't work. Ah, I got it because we hard
coded delivery address here. So I have to use my input control key. I have to use it instead
the hard coded string. Okay, now the metro. 1111, FFFFF, 2222222, MMMMMMM. And... Submit, and now you can see everything
works, billing address works, delivery address works, display name works. Super simple, super flexible, super cool. You can now reuse this address group
everywhere in your application. It is magically hooked up and
adds and registers everything it needs for its work. Really reusable form group. And as I said... This is just a small
part of my entire work. In depth angular form course and take
just one minute to have a look what you will build in the end of this course,
in just a few easy sections, you will be guided through most of the template
driven and reactive forms features, so you can create two advanced and
interactive forms that will impress. everyone and leave you
feel proud of your work. But that's not all. The course strongly focuses on custom form
controls implementation, so you will learn a lot about control value accessor and
how it is used by Angular under the hood. You will get to build custom form
controls like a rating picker and a simple text editor, both of which support
template driven and reactive forms, as well as, you know, validations and
other form control features, of course. In addition, you will master a really
complex component in the third section. Here I'm talking about a drop down
component that supports option filtering, multi selection, and
accessible keyboard navigation. With my Step by step guidance,
you will be able to build this advanced form control very easy. Already impressive, isn't it? But even that is not all. In the remaining course sections, you
will learn how to create Angular forms dynamically from JSON config and which
architecture solution can help make it scalable and maintainable in the future. In the last section, you will learn
how to manage validation errors globally, so you can dynamically
render error messages for invalid controls without generating a ton of
boilerplate in your component templates. So, enroll right now and let's
take your form building skills to a completely new level. The link to the course and discounts
will be in the video description. All right guys, thanks for watching. I hope this video was really useful,
and if so, and if you'd like to help me to grow my YouTube channel, one
of the easiest and best ways to help me with that is to share this video
with your colleagues and friends. Or you can make a little donation by
using this square code that should appear somewhere on the screen. Here and starting from
the next video in the end. I will be showing the nicknames
of those who Supported my youtube channel and maybe in the future. I will even create some private community
from it with some unique content. What do you think about that? Please let me know in the comment section. Otherwise, I wish you
productive week ahead, guys. Stay safe and see you in the
next Advanced Angular tutorial.