Forms in Angular
Forms on html page and how angular can help you with those forms now on first side might be strange because form is something that you can simply submit server then keep in mind you are creating a single page application so there is no submit to the server instead you have to handle from through angular and if then you want to submit something to server you will need to reach out via angular http service.
How angular works together with forms.
This is html code of form which you might use nothing is angular specific about this code its normal html code placed in html document it will be displayed like this with the input for Name and mail
Now angular job now is to allow you to retrieve values which is entered here and also check some other things like is the form valid did the user entered valid information all that will happen in javascript and in typescript or we can say angular side. So some how we have to pass these values which user enters so some how you need javascript object representation of your form in your typescript code to work with.
This object could look something like this it is more complex in real world these will be key features we need. We need to have value of the form and there could be any key value pair where key is referes to name of input like name in the form or html we mentioned and value is holds user entered. This would make it super simple for you to work with these values in your type script code to do something with the values user entered. It might have also some meta data information like form is valid.
Two types of forms in Angular / Two Approaches.
- Template driven forms (Angular infers the Form Object from the DOM)
- Reactive forms (also known as dynamic forms) [Form is created programmatically and synchronised with the DOM]
Lecture 2:
So here I am on a simple example form just to get started, the code responsible for it is this HTML code in the template of my app component here and you can find this code attached to this lecture here.
Now it's a simple form, we're going to expand it or enhance it with some features throughout this module, to get started, this is just fine.
Now if we have a look at this HTML code,
you will quickly realize that on the form tag here, I don't have the action attribute pointing to some route,
I'm also not specifying the method attribute which typically would be post.
The reason for this is that this form should not get submitted to a server,
I don't want a HTTP request to be the result of me clicking the submit button, instead
as mentioned earlier, Angular should handle this form and therefore, I don't have an action on it.
This of course means that right now if I hit the submit button, nothing happens,
if you have a look at the refresh icon up there, you see it's not spinning, nothing happens because we're
not actually sending a request.
Well we will work on this but first, let's understand what actually happens behind the scenes and how
Angular infers such forms, create such a Javascript object for us as it does when using the template
driven approach.
Lecture 3 :
now let's understand how Angular creates such a Javascript object representing our form in the template
driven approach.
The great thing is you don't have to do anything, well almost anything,
make sure that in your app module, you actually import the forms module, add it here to your imports array
and have the import at the top of this file. As the name implies,
this built-in module shipping with Angular includes a lot of forms related functionalities and it's
actually needed to get this template driven approach to work, to get this form creation by Angular to
work. Now by default in a CLI project, this should already be imported so it should work fine
but again, I'm just highlighting it because it's super important that you have this import, otherwise the following
steps will not work. With this imported, Angular will actually automatically create a form for you,
so a Javascript representations of the form when it detects a form element in HTML code, like it does
here.
<form>
</form>
So you can think of that form element serving as a selector for some Angular directive, which then creates
such a Javascript representation of the form for you.
Of course, you can't see that form representation as of now and it would be very empty because one thing
does not happen automatically, Angular will not automatically detect your inputs in this form
and the simple reason for this is that whilst you could argue that it should be able to scan your HTML
code and detect that you have an input here and here and that you have a select dropdown here, you
still might not want to add all these elements as controls to your form, so with control I'm referring
to what is in the Javascript object
and again not every input in your HTML code might be a control you want to have in your Javascript form.
Maybe you have a dropdown which values only changes something you view on the UI but the input
should not actually be part of what gets submitted,
maybe you use some third-party package which adds some custom form controls which are not labeled input,
which don't use input as a selector and then Angular would have no chance of detecting that this is a
control of your form.
So you still need to register controls manually,
you need to tell Angular hey within that form element, what should be an actual control of my form?
And this is what we're going to do
now, tell Angular how does our form look like,
which controls do we want to have? In the template driven approach,
this is super simple.
You simply pick the input which you want to add as a control, like this input here
and I'm just going to structure it a bit different to split it up over multiple lines to make it easier
to read and then you add ngModel, like this.
Now you might already know ngModel from the two-way binding, two-way data binding and it actually is
the same directive. In two-way data binding though,
you saw that we use that with square brackets and parentheses wrapped in ngModel.
Now we will have a look at this later again
but for now, let's add it without any parentheses, without any square brackets just like this.
This will be enough to tell Angular, hey this input is actually a control of my form, so ngModel in
the end is a directive made available in the forms module, something I mentioned earlier in the course
when we had a look at two-way data binding.
This is key to understand,
you can use it to get two-way data binding but it actually is part of a bigger module with more features
giving you full control over forms.
Now for this to work, for this to be recognized as a control in your form, we need to give Angular one other
piece of information, the name of this control.
Right now, it would see OK this input should be part of the Javascript object representation of this
form,
so whatever the user enters here as a value should be the value of this control, of what's
the name of that control.
We need to give that information to Angular and we do this by adding the normal HTML attribute, name. So
name is nothing Angular 2 specific, name is the default attribute
you can add to any HTML control.
Now here, the name might be username because that is what we can enter in this input
and with this, this control will be registered in this Javascript representation of the form.
Now I'll do the same for the email, restructure it so that it's easier to read, add ngModel and add
a name, like for example email here.
Well and the same is true for the select here which is just another type of HTML input.
Here we can also add ngModel and we can add a name, like secret because I'm asking for a secret question
here and with that, we registered all the controls,
of course we can't see that much though.
Well that is something we're going to have a look at in the next lecture when we see how we can submit
such a form and therefore, how we can see these key-value pairs representing what the user entered into
which input.
Lecture 4: Submitting and Using Form
In the last lecture, we configured our form here, we added some control by placing ngModel on the
inputs,
now let's make this form submittable so that we can actually see what the user entered.
For this, I'll go to my app component,
I already do have a method here which you will use later,
let's ignore it for now and I'll add a new method, onSubmit maybe, this should be triggered whenever this
form is submitted by the user. In onSubmit,
I want to output whatever the user entered,
well first of all we need to call this method,
so back in the template, how can we call onSubmit?
Now you might think that a good place would be on a click listener on this button here at the bottom right, because
this is a button we click when we want to submit the form,
however this is not the best place to do it.
Keep in mind that this button here is type submit,
so if we click it as it is placed inside of an HTML form element, something else will happen,
The default behavior of HTML will be triggered to call it like this.
If you have a button in a form element, this button will submit the form, will send a request normally
but besides that, it will also trigger a Javascript event,
the submit event that's built into Javascript, built into HTML
you could say. Angular takes advantage of this and gives a directive
we can place on this form element as a whole,
it is called ngSubmit and it actually only gives us one event we can listen to,
<form (ngSubmit)="onSubmit()">
</form>
so let's wrap it in parentheses.
This event made available by the ngSubmit directive will be fired whenever this form is submitted,
so whenever this default behavior is triggered
and here, we can call onSubmit like this and to show you that this works,
I will simply go into onSubmit and log submitted here,
just like that.
Now if we save this and let it recompile, let's go back and let's open up the developer tools and if
I now hit the submit button, you see submitted here on the right
because indeed, the form gets submitted.
Now it would be nice to see the actual values of the form though, to see that form object and to see
it, we have to go back to our template because we're in the template driven approach,
so as a rule of thumb, everything you do you do it in the template, everything you want to change about
this form, you want to add as functionality,
you do it in a template. On this form object,
we want to get access to the form created by Angular.
Now you learned about local references you can place on HTML elements to get access to them,
so we could place #f on the form element and now we could access this form element on the f
<form (ngSubmit)="onSubmit()" #f>
reference in our template and we could pass f as an argument to the onSubmit method and print it
there.
<form (ngSubmit)="onSubmit(f)" #f>
</form>
So now we know that we get the form
and actually, this will be of type element ref as we learned.
So if we import element ref and make this of type ElementRef here and we output the form here,
Note: Thats actually not correct it is of Type "HTMLFormElement"
onSubmit(form: HTMLFormElement)
{
console.log(form);
}
so this element, if we now go back to this and hit submit,
yes we did see the form object, we see some strange classes here, I will come back to them but that still is not what
we want,
it's not a Javascript object created by Angular but this object is there, we just need to know how to
get to it and there actually is a trick you could call it but it's no trick, it's the default way to
get access to this automatically created object,
you set this local reference equal to something.
Now we haven't done that yet but we can set it equal to something exposed by this
form here,
keep in mind the form element is kind of a selector for a directive built into Angular which will create
this Javascript object automatically and then it will expose some data we can fetch here on this form element.
We can get access to it by writing ngForm here between the quotation marks.
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
So this might look super strange but what this in the end does is
it tells Angular hey please give me access to this form you created automatically.
That's just something you have to keep in mind,
this is how you get access to the form, to this Javascript object created by Angular automatically.
So therefore here where we get this form, we now still pass it,
now this will no longer be an ElementRef, so let's remove this type here, instead
this will now be of ngForm.
So let's import ngForm from @angular/forms and kind of makes sense that it is of type ngForm
because that is what we're accessing here,
this automatically created form.
Now let's print it to the console one more time and let's actually enter something into these fields to
see that it worked.
If I now type submit here, you see that now we get an ngForm object, an object which we certainly didn't
create
and there, we have a lot of properties,
we'll have a close look at those later.
We also do have a value property
and if we expand this, we indeed see a couple of key-value pairs here where we have the names of the
controls, so the names we set up here and the name attribute like username and email,
we find them here
and then the values the user entered.
And this is how we can submit such a form and how we can also get access to the form object created by
Angular,
Lecture 5: Understanding Form State
In the last lecture, we learned how we can submit a form created by Angular and how we can access to this
object
Angular created for us.
Now we had a look at the value property which stores the input of the user in key-value pairs,
Here value:Object
email:"test@gmail.com"
secret:"pet"
username: "test"
we see that we also have a lot of other properties and that's pretty cool about this Javascript object,
about the form handling by Angular,
it allows us to really understand the state of our form
We can see which controls we registered here on the controls object, e-mail, secret and username and
each control is of type FormControl, of course a type made available by Angular where each control then
has a couple of properties, mostly the same properties we have on the overall form though
and therefore let's go back to that overall form,
for example properties like dirty, disabled, enabled, errors
and most of the properties should be pretty self-explanatory.
Dirty for example is true because we changed something about that form.
If I reload the page and submit it now, you will see that dirty is false because I didn't type into any
input, so therefore of course dirty is false.
Disabled would be true if the form was disabled for some reason,
invalid is false because we haven't added any validators, so it isn't invalid, it is indeed valid.
You do have the valid property down here too, so the form is valid right now,
we will later learn how to add validators to make sure that a valid e-mail address has to be entered
for example.
And we also have
touched for example to see did we click into some of the fields, the difference to dirty
would be that for dirty, we have to change the field, have to change the value of a field, for touch we simply
have to click into it and now it would be touched and you will later learn how these properties can
be helpful in
changing the user experience, for example disabling the submit button if the form is not valid,
I will come back to this later.
It's important to understand that you have all these properties and definitely feel free to dive into
the output we logged here and understand which properties you have, how they change, which properties
the individual controls have and so on.
Lecture 6 : Accessing Form Child With @ViewChild
In the last lectures, we learned how we can register controls and how we can submit the form and also which
properties this form has. Now
right now, we submit the form by passing the form which we get via ngForm here to the onSubmit method,
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
</form>
this is absolutely fine and probably the approach you will use in many use cases.
I just want to bring some other approach to your attention.
You don't have to submit it here.
Like we don't need to pass f in this method onSubmit()
Remember the components section where we learned about @ViewChild which allowed us to access a
local reference, an element controlled or which holds a local reference in our TypeScript code.
Well in the end, we do just have such a local reference here
and whilst that might not point to an element ref but to the ngForm object, it still is a local reference
in our template so we can also use @ViewChild here.
So I will simply comment out this onSubmit method here so that we have it in the code you can find
attached to this module and show you an alternative approach. In this alternative approach,
I will use @ViewChild, this decorator you learned about in the component section, so make sure to import
it from @angular/core
and I want to get access to the element which has the local reference f on it.
So I pass f as a string, as an argument to @ViewChild
and then I could simply store this in a variable named signupForm, any name you like, which will be of
type ngForm of course. Now in onSubmit,
I could output this signupForm, like this
and you should see that if I now submit this again, we still have this form
and I can also enter something so that we can see that this works too if we have a look at the value.
So this gives us access to the very same form without passing it to onSubmit,
this is especially useful if you need to access the form, not just at the point of time when you submit it
but also earlier
and I will show a use case for this in a later lecture.
For now, let's keep in mind that this is another way of getting access to the form in our TypeScript
code, a perfectly valid way of getting access and before diving deeper into why this might be useful
or when we could use that, let's actually understand how we can control the validity of the form.
So to determine whether the form is valid, if we entered a valid e-mail address here or not because right now
I can submit anything, no matter if this is invalid, if this is empty,
it would be nice if we could add such validation and take advantage of the tools Angular
gives us there to possibly also enhance the user experience by placing a red border around invalid elements
or something like this.
We'll have a look at validation in the next lectures.
Lecture 7 : Adding Validation to Check User Input
So as mentioned at the end of the last lecture, it would be nice if we could validate the user input,
something very important in any app you build.
Whilst you should still validate input on the server as the front-end can always be tricked, you can
greatly enhance user experience by also validating the input here,
for example we want to make sure that none of the fields here is empty and that the e-mail address
actually is a valid e-mail address.
So let's go back to our app component, to the HTML file, to the template and see how we can add such validators.
Now since we use the template driven approach, we can only add them in the template
and here we can for example add required to our username input. Now required is a default HTML attribute
<input type="text", id="username" class="form-control" ngModel name="username" required>
you can add to an input, here however Angular will detect it,
so it acts as a selector for a built-in directive shipping with Angular and it will automatically configure
your form you could say, to take this into account, to make sure that now this will be treated as invalid
if
it is empty.
And on the e-mail, we can for example therefore also add required
and there also is an email directive you can add.
<input type="email" id="email" class="form-control" ngModel name="email" required email>
Now e-mail is not a built-in HTML attribute,
it still is a directive
and keep in mind required is only treated as a selector for an Angular directive here.
An email is simply another directive made available by Angular which makes sure that this is actually
a valid e-mail address.
So now if we save this and we have a look at our form here and I submit it, I can still submit it because
we haven't set up anything which would prevent us from doing so
but if we have a look at it and check the valid attributes, you see it is false.
And if I enter something here and I enter something here,
so it's filled but the e-mail address is still not valid,
you see that still valid is false.
Only if I turn this into a valid e-mail address here, only in this case,
now if we submit it,
now you see valid is true.
So now Angular tracks the state of this form and correctly informs us or gives us a chance of querying
it whether this form is valid or not and actually this does not only work on form level, if we dive into
the actual controls, you'll see that on the e-mail control,
we also have a valid attribute which is true.
So it tracks this on a per control level
and then also on a form level, now there also is another place where it tracks this and helps us.
If we inspect this e-mail element here in the HTML code,
you'll see that it adds a couple of classes because the form-control class here is by us, it's
a Bootstrap class to give it some styling but ng-dirty, ng-touched and ng-valid,
these are not classes added by us and the ng at the beginning makes it pretty clear who is responsible
for adding these classes.
Now watch these classes
if I remove the @ sign here,
you saw that ng-invalid was added and ng-valid was removed.
So Angular dynamically add some classes, giving us information, some CSS classes, giving us information
about the state of the individual control here whether it is dirty or not,
so whether we did change the initial value, whether it touched or not
so whether we clicked into it or not and whether it is valid or not.
Now with that information, we can style these inputs conditionally.
So let's in the next lecture take advantage of the fact that Angular tracks the state of the validity and
of the form overall and change the styling and the behavior the user experience with that form.
Lecture 8 : Built- in Validators & Using HTML 5 Validation
Built-in Validators & Using HTML5 Validation
Which Validators do ship with Angular?
Check out the Validators class: https://angular.io/api/forms/Validators - these are all built-in validators, though that are the methods which actually get executed (and which you later can add when using the reactive approach).
For the template-driven approach, you need the directives. You can find out their names, by searching for "validator" in the official docs: https://angular.io/api?type=directive - everything marked with "D" is a directive and can be added to your template.
Additionally, you might also want to enable HTML5 validation (by default, Angular disables it). You can do so by adding the ngNativeValidate to a control in your template.
Lecture 9 Using the Form State
In the last lecture we found out that Angular tracks the state of each control of the form, whether it's valid and so on and conditionally also adds these CSS classes.
Now with that information, we can go back to our form and you take advantage of it. Before diving into the CSS classes,
the easiest way of taking advantage is down here on the submit button,
let's disable the button if the form is not valid.
So I'll just split this over multiple lines and add some property binding, I want to bind to the disabled property
which will add the or which will set the disable state of this button to true or false depending on
some condition
and I will specify the condition here.
Now I could set it true here to always disable it,
that of course is not super useful, instead here I want to check whether the form,
remember we do have access to it on this f local reference here,
so if this form is valid, which would be precise
<button class"btn btn-primary" type="submit" [disabled]="!f.valid">Submit</button>
if it is not valid. So if this form is not valid, the button should be disabled and we can actually see
this once this reloads and
now the button is disabled and only if I enter some valid values here, I can hit the submit button again.
So this is the first improvement in place,
the second improvement is to take advantage of these CSS classes.
We do get these classes added automatically, so we can now go to the stylesheet of this app component
and we could say that on ng-invalid, we want to give it a red border,
.ng-invalid
{
border: 1px solid red;
}
so one pixel solid red.
Sounds like a solid idea, doesn't it?
Well if we do this, you see everything is red
now, the two controls but also the overall form.
The reason for this is that our overall form is also invalid
and that Angular also adds the ng-invalid class, CSS class to the form element.
So a better approach would be to make sure that is not added to the form.
Now there are a couple ways of doing this and it's all just pure CSS logic, one idea would be that
we want to be inside of the form element but then it would still place these red borders around grouping
divs,
we will have a look at what I mean with this later.
So the best way is to simply be explicit that we want to add it on inputs for example
and of course you could also add select here, so input with ng-invalid or select with ng-invalid and which
other elements you have.
Just be creative here,
there are different ways of achieving this goal, in the end you just want to make sure that the border is applied
to the right controls.
Now with this in place, we see that now we only have a red border around the invalid controls but we
do have the border right from the start which is also not great because I at least want to give the
user the chance of changing it before showing a warning, showing that it's wrong.
So a better approach might be to make sure that we only add a red border to an input which has the CSS
class, ng-invalid
and also the CSS class ng-touched, so that the user has to at least click into it. Now by default,
we don't see anything red
even though the form is invalid
but if we click in there and decide yeah I'm done this is my value,
well now you see we have a red border because now we had a chance of changing it,
we didn't change it,
it is invalid
and we want to show this
and with that, we're taking advantage of this form state handled by Angular.
We disable the button and we show a visual feedback to the user.
Now you could of course go much further,
you could also add a warning message below this input here for example and output please enter a valid
value or be more precise than that of course
and add ngIf to conditionally show this if the input value is wrong.
<p *ngIf="">Please enter a valid value</p>
Well this gives us one additional problem though, how do we determine whether this input here or this
control here does hold a wrong value.
Lecture 10: Outputing Validation Error Message:
In the last lecture, we improve the user experience by taking advantage of the form state handled by
Angular.
Now let's improve this even more and let's say we want to output some help text below this input to assist
<input type="email" id="email" class="form-control" ngModel name="email" required email>
<span class="help-block">Please enter a valid email</span>
if there is an invalid value in there.
Now we can use a Bootstrap class here, help-block, to make sure that this has the appropriate styling
and then we could say please enter a valid e-mail.
We only want to show this if an invalid value has been entered into the control
associated with this input though.
Well, a quick and easy way of getting access to the control created by Angular automatically as we added
ngModel to the input is by adding a local reference to this input element here,
for example email, any name you like and associating this now not with ngForm as we did for the overall
form but with ngModel.
So just like the form directive automatically added by Angular when it detects a form element, the
ngModel directive here also kind of exposes some additional information about the control it creates
for us on the overarching form by accessing ngModel.
<input type="email" id="email" class="form-control" ngModel name="email" required email #email="ngModel">
<span class="help-block" *ngIf="!email.valid && email.touched">Please enter a valid email</span>
So with this, we could simply check or say that we want to attach this span here
if e-mail is not valid, so add an exclamation mark at the beginning.
Now with this if this reloads, you'll see that help text
and of course you can improve this by also chaining another condition
that e-mail should have been touched to give the user a chance of changing it.
So now you don't see the warning but if you click in there and click out of there and it is invalid,
you see that warning
and if you now enter a valid data, it disappears.
So this is another way of taking advantage of the state managed by Angular
but this also shows you how you can get a quick and easy access to control added by Angular.
And with that, you should have tools to really provide a pleasant user experience showing the right errors,
the right warnings and styling the form correctly depending on the state of the form.
Lecture 11: Set Default Values with ngModel Property Binding.
How to define some default value should be displayed like in drop down by default nothing is selected so its nice if something is shown by default.
So we can change they way we add ngModel to select
<select id="select" class="form-control" [ngModel]="dedaultQuestion" name="secret">
<option value="pet">Your first Pet</option>
<option value="teacher">Your first teacher ?</option>
</select>
This dedaultQuestion property can be fined in ts file with pet value
like this
dedaultQuestion = 'pet';
Now this first option will show.
Lecture 13: Grouping Form Controls.
Now let's say that on the value object we get when we submit the form, we want to group some things,
for example we want to group the secret and the questionAnswer and the username and e-mail to just have
some structure in our object because for a very big form,
we might want to have such a structure.
This would also be nice if we could then validate the validity, the status of our individual groups of
inputs,
turns out that's easy to do with the template driven approach. Here
on our first group, the username and e-mail, I already have a wrapping div with the ID userData here.
Now you can simply place another directive on it,
the ngModelGroup directive like this and this will now group this into,
well you guessed it, a group of inputs,
however ngModelGroup needs to be set equal to a string.
So for example, the userData,
this will be the key name for this group.
So now if I save this with ngModelGroup added, If I enter value here and here and hit submit and we
have a look at the value of the form, you'll now see that we have a userData field here which holds
another object where we now have e-mail and username.
Now not only did we add this extra field in our value, we also now have a different set up here in controls,
here
we also now have a userData control with all the properties you know on those controls, like valid and
so on.
So if we now simply inspect our HTML code and this div with the ID userData, you'll see that there also
we got the ng-dirty, touched and valid classes added.
So you can now also check the validity of this overall control here for example
which might be a nice feature in your form.
You can also get access to the Javascript representation by again adding a local reference to
the element which holds the ngModelGroup directive,
here for example userData would be a fitting name and then setting this equal to ngModelGroup.
So just like we did before with e-mail which was equal to ngModel, I'm now setting this reference
equal to ngModel group to get access to this Javascript object
and this would allow us to for example output a message if this whole group is not valid.
So we could simply output a paragraph here, userData is invalid which we add if userData, this is the local
reference created here,
if userData is not valid
and let's say it has been touched,
so userData touched is true. With that if this reloads,
you see that we don't see any message
but as soon as I click into one of the fields and then leave it,
you'll see userData is invalid was shown.
So now you really got a very finegrained control over your form with all these tools.
Lecture 14: Handling Radio Buttons
We're nearing the end of the first part of this section, the template driven approach,
there are still some things I want to show you, for example how to work with radio buttons.
We don't have any radio buttons in our form as of now, so let's add some. Let's add a property in the app
component first with some genders.
So this is simply an array where I have male and female and I don't want to insult anyone, I know there
are more genders nowadays, I'm going to go with the classic approach here just to keep it simple.
We have this genders array and now with that array, I want to output genders here,
so let's say below our
your reply paragraph here, I'll add a new div with a class of radio
and this div should be replicated for all the genders.
So I'm going to loop through my genders, maybe bind it to a gender variable and this is just a setup
of Bootstrap uses to give this some nice styling, of course
use any other setup to style your radio buttons here. I'm looping through all the genders
and now again in the bootstrap world, to create a nice looking radio button,
I'm going to wrap it in a label, this input here which is of type radio
and I'm going to wrap this over multiple lines too, just to make it all super simple to read and to understand
and here I will give it a name of gender because in a radio button, I can only select one of them in a group,
so
the name should be gender for whichever button is selected and I will place ngModel on it to make
it a control
and I will prepopulate or I set the value of this button equal to gender,
so this variable of my ngFor loop.
Now with that if we save this, we should see that we have some gender buttons, to output a text,
I need to add it here after my input.
So again, gender here
like that
and now we have male and female here
and if I just enter something so that I can submit the form and I pick male here, you will see that on
the value object here,
we got gender which is male and of course if I pick female, this will, you guessed it. be set to female.
So this is how you can easily incorporate radio buttons by binding or by placing ngModel on the
input as always, setting the value, of course you could also hardcode the value and that well makes
it usable just like any other input.
And if you want to set it to a default gender of course, you can use one-way binding again to make sure
that one of the two buttons is selected by default at the start
when you load the form. You can also of course add the required directive or attribute to that input
here to make sure that now the form will not be valid until one of the two has been selected,
so that works just like on any other input.
So I just want to highlight this because radio buttons can look like a very special case,
they aren't, they are used like any other input when using the template driven approach in your Angular
app.
Angular framework support for Forms
- Two data Binding
- Change Tracking
- Validations
- Error Handling
- Unit Testing
Template Driven Forms : Introduction
- Easy to use
- Template driven forms are simple and straight forward
- All the validations, forms elements are all defined in the template file
- Forms are tracked automatically
- Tracked form data traverses via various states (pristine etc)
- Uses Two-Way data binding techniques to bind data.
- Most of the code resides in template file.
- Validations are mostly the default HTML5 validations
- Minimal component code as most of the code is in template file.
- Unit testing will be a challenge.
- We will need to import FormsModule in app module to work with template driven forms.
How to use Template Driven Forms
We will need to import FormsModule in app module to work with Template driven forms.
Step #1 - Import and add in the FormsModule in the app.module.ts
- For template driven forms - FormsModule need to be imported.
- If we do NOT import this - We will get error when doing two way data binding.
- Add the module into the array list of imports.
Step #2 - Create the form in app.component.html
- ngForm
- Form name as template variable using "#" for e.g #loginForm
- ngModel
- Every form field should have a "name" attribute and ngModel attached to it.
Reference Image
Here in example.component.ts file we will define that method and we can get value by getting that template reference variable and on template reference variable we have value.fieldname which we defined in input or select or radio with name="that field".
Adding different form fields in template form.
- Input type = "text"
- Input type = "radio"
- Input type = "checkbox"
- Input type = "email"
- textarea
- Select drop down.
Validations in Template Driven Forms
- Validations are extremely important and integral part of any Forms in apps.
- In order to prevent unwanted data or junk data we must validate the form fields and it's data entered by the users.
- Angular provides common validators like minLength, maxLength, required etc.
Angular maintains state information of the Forms at all times.
- ng-touched
- ng-untouched
- ng-dirty
- ng-pristine
- ng-valid
- ng-invalid
First, Let's see the form object that is always maintained in console log
Ways to Handle Validations in Template Driven Forms.
input.ng-invalid.ng-touched{
background-color:red
}
we can add this property to css and once we enter mouse in input field and step out then it will show as red color but for that we have to define required as attribute to input field.
- Disabling the Submit button
- By adding attribute [disabled]="!formNameTemplateReferenceVariable.valid"
- Custom Field Level Validation - Show hide Errors Messages
- <span *ngIf="fieldName.touched && !fieldName.valid">Define custom error message </span>
But to do this we have to do 2 ways data binding means we have also define (template reference variable with ngModel) #fieldName="ngModel". We have to define in each field.
Reactive Forms in Angular
Reactive Forms / Dynamic Forms: Introduction
- Experience is similar to Template Driven Forms
- Whats different is how we implement, design and handle the form and the data.
- All the form elements, user interactions and validations are handled in the component class
- We will make use of Angular's built in formGroup and formControl
- Using reactive forms we can control better data binding.
- Exclusive define custom regular expression patterns for error handling
- We will need to import ReactiveFormsModule in our app module.
- Very flexible and allows users to define, develop complex requirements for forms.
- More logic in the component class and less in HTML mark up itself.
Angular maintains state information of the Forms at all times.
- ng-touched
- ng-untouched
- ng-dirty
- ng-pristine
- ng-valid
- ng-invalid
Reactive Forms in Easy Steps
How to use Reactive Forms
- Step #1 - Import and Add in the ReactiveFormsModule in the app.module.ts
- For template driven forms - ReactiveFormsModule needs to be imported.
- If we do NOT import this - we will get error.
- Add the module into the array list of imports
- Step #2 - Create the form in app.component.html
- FormGroup
- We need to use the directive FormGroup for the entire form and give it a name.
- Example: <form [formGroup]="checkoutForm">
- formControlName
- Every form field should have a "formControlName" attribute.
- Step #3 - In the component class - import the required modules.
- Step #4 - Inject the FormBuilder in the constructor
constructor(private formBuilder: FormBuilder){}
- Step #5- Create the form instance
this.registerForm = formBuilder.group({
fname: new FormControl(),
lname: new FormControl()
});
Validations in Reactive Forms
- Validations are extremely important and integral part of any Forms in apps
- In order to prevent unwanted data or junk data we must validate the form fields and its data entered by the users
- Angular provides common validators like minLength, maxLength, required etc.
Three Approaches to handle Validations in Reactive Forms
- Approach #1 - Highlighting the errors
input.ng-invalid.ng-touched{ background-color:red
}
- Approach #2 - Disabling the Submit button
By adding attribute [disabled]="!formName.valid"
this.registerForm = formBuilder.group({
fname: ['', Validators.required],
lname: ['',
[
Validators.minLength(5),
Validators.maxLength(10),
Validators.required,
Validators.pattern('^[a-zA-Z]+$')
]
],
email:['', [Validators.required, Validators.email]]
})
- Approach #3 - Custom Field Level Validation - Show Hide Errors Message.
Note: In case of checkbox required doesn't work it need Validators.requiredTrue in ts file while validating.
Form Group - GET Values:-
- We can get the values of a form fields/ controls from the form.
- Syntax to read the value of "entire" form
- this.formName.value
- // this will give values for all the form fields or Formcontrols of the form.
- Syntax to read the value of an individual form control
- this.formName.get('fieldname').value
- this.formName.value.fieldName
- // this field name can be anything from the form name attribute
- Let's learn it with some hands on examples.
Form Group - SET Values:-
- Setting values in the Form - setValue
- We can SET the values of the entire form using setValue()
- We need to set values for each and every field of the form
- We cannot omit any field in the form.
- Syntax
- this.registerForm.setValue({
- fname: 'ARC',
- lname: 'Tutorials',
- email: 'boolment@gmail.com'
- });
Note: We set values in ngOnInit(){} method
- Setting Individual Form Field Controls - patchValue
- We can SET individual fields using patchValue()
- Syntax:
- this.registerForm.patchValue({
- fname: 'ARC',
- email: 'sridhar@gmail.com'
- });
Form Group - Reset Forms
Its important that we reset our form to avoid any duplicate values getting added.
Reset Form - reset()
We can reset the entire form using reset() method.
Syntax
this.registerForm.reset()
//We will use reset method to reset the entire form in one shot.
Angular maintains state information of the Forms at all the times.
- ng-touched
- ng-untouched
- ng-dirty
- ng-pristine
- ng-valid
- ng-invalid
Which is better - Template driven Forms or Reactive Forms ?
- Template Driven Forms
- If your application forms are simple straight forward
- Fixed static form fields and elements.
- No complex validations or pattern matching.
- Reactive Forms
- If your application forms are complex
- Uses multiple dynamic components
- Advanced validations requirements
- Dependent form elements
- Dynamic form generation based on user preferences.
Comments
Post a Comment