Telerik blogs

Today we will look at how to create forms in Angular with reactive forms and template-driven forms and get values from both.

Forms are basic parts of any web app, and Angular provides us with ways to create forms with validation without adding any new library.

In this article, we will look at how to create forms in Angular and get form values.

Types of Angular Forms

There are two types of Angular forms. 

One type is reactive forms. Reactive forms lets us create forms with a way to access the form values directly from the form object. They’re more scalable and reusable, so this is the preferred way to create forms. Data flow is synchronous and the form data model is immutable.

Another kind of form is template-driven forms. Template-driven forms bind form values to variables we can access with directives. We access the forms values by using the variables that the form controls are bound to. The form data model is mutable with template-driven forms.

Getting Form Values with Reactive Forms

To create reactive forms in our Angular app, we use the ReactiveFormsModule. To do this, we write the following in app.module.ts:

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { ReactiveFormsModule } from "@angular/forms";

import { AppComponent } from "./app.component";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, ReactiveFormsModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

We add the ReactiveFormsModule into imports so we can use it with components in AppModule to create reactive forms.

Now we can create our first reactive form. To do this, we write the following in app.component.ts:

import { Component } from "@angular/core";
import { FormControl } from "@angular/forms";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  name = new FormControl("bob");

  updateName() {
    this.name.setValue("jane");
    console.log(this.name.getRawValue());
  }
}

We add the name form control with the FormControl class. The argument of the constructor is the initial value of the name field.

In the updateName method, we call setValue to set the input value of name. And we get the input value after it’s set with getRawValue.

Then in app.component.html, we write:

<form>
  <label for="name">Name: </label>
  <input id="name" type="text" [formControl]="name" />
</form>

<button type="button" (click)="updateName()">Update Name</button>

to add a form with an input. We set [formControl] to name so that the name FormControl instance is bound to the input.

Then when we type in something, the name FormControl instance will have the input value we typed in. And we can also get and set the input value from our component.

We also add a button that calls updateName when we click it. Now when we click the button, updateName is called. setValue updates the form’s value to 'jane'. And we call getRawValue to return the input’s latest input value, which is 'jane'.

Usually, a form has more than one form control. We can group them together with FormGroup. To do this, we use the FormGroup class:

app.component.html

import { Component } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  personForm = new FormGroup({
    name: new FormControl("bob"),
    age: new FormControl(100)
  });

  onSubmit() {
    console.log(this.personForm.value);
  }
}

to add a FormGroup instance.

We call FormGroup with an object with the form fields which we create with the FormControl class.

Next, we create a form and bind it to the FormGroup by writing:

<form [formGroup]="personForm" (ngSubmit)="onSubmit()">
  <label for="name">Name: </label>
  <input id="name" type="text" formControlName="name" />

  <br />

  <label for="age">Age: </label>
  <input id="age" type="number" formControlName="age" />

  <br />

  <button type="submit">Submit</button>
</form>

We set [formGroup] to personForm to bind the form to the form group we just created.

And we set the formControlName attribute instead of formControl to bind the inputs to the form controls in the form group.

Next, we add a submit button and set (ngSubmit) to onSubmit so onSubmit is called when we submit the form. In onSubmit, we get the form’s input values with this.personForm.value.

As a result, we should see an object with the name and age properties with the input value for each when we submit the form.

Form groups can be nested, we just set the form field to a form group.

For instance, we write:

import { Component } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  personForm = new FormGroup({
    name: new FormControl("bob"),
    age: new FormControl(100),
    address: new FormGroup({
      street: new FormControl(""),
      city: new FormControl(""),
      region: new FormControl("")
    })
  });

  onSubmit() {
    console.log(this.personForm.value);
  }
}

to add the address form group to the personForm form group.

Then we write:

app.component.html

<form [formGroup]="personForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="name">Name: </label>
    <input id="name" type="text" formControlName="name" />
  </div>

  <div>
    <label for="age">Age: </label>
    <input id="age" type="number" formControlName="age" />
  </div>

  <div formGroupName="address">
    <h2>Address</h2>
    <div>
      <label for="street">Street: </label>
      <input id="street" type="text" formControlName="street" />
    </div>

    <div>
      <label for="city">City: </label>
      <input id="city" type="text" formControlName="city" />
    </div>

    <div>
      <label for="region">Region: </label>
      <input id="region" type="text" formControlName="region" />
    </div>
  </div>

  <button type="submit">Submit</button>
</form>

to use the address form group by setting formGroupName to address. And we set formControlName to the form control name as usual.

The rest of the form is the same as the previous one.

As a result, when we submit the form after entering some values, we get something like:

{
  "name": "bob",
  "age": 100,
  "address": {
    "street": "abc",
    "city": "abc",
    "region": "abc"
  }
}

logged from onSubmit.

Template-Driven Forms

An alternative way to create forms is template-driven forms.

We use the NgModel, NgForm and NgModelGroup directives to bind forms and input values to component variables.

To add template-driven forms, we add the FormsModule to AppModule so we can add them in AppModule.

To do this, we write:

app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";

import { AppComponent } from "./app.component";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, FormsModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Next, we can create our form.

To do this, in app.component.ts, we write:

import { Component } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  person = {
    name: "bob",
    age: 100,
    address: {
      street: "",
      city: "",
      region: ""
    }
  };

  onSubmit() {
    console.log(JSON.stringify(this.person, undefined, 2));
  }
}

to add the person variable to AppComponent. Our form will bind to the properties in person so that we can get input values by referencing person.

Next, in app.component.html, we write:

<form #personForm="ngForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="name">Name: </label>
    <input name="name" type="text" [(ngModel)]="person.name" />
  </div>

  <div>
    <label for="age">Age: </label>
    <input name="age" type="number" [(ngModel)]="person.age" />
  </div>

  <div>
    <h2>Address</h2>
    <div>
      <label for="street">Street: </label>
      <input name="street" type="text" [(ngModel)]="person.address.street" />
    </div>

    <div>
      <label for="city">City: </label>
      <input name="city" type="text" [(ngModel)]="person.address.city" />
    </div>

    <div>
      <label for="region">Region: </label>
      <input name="region" type="text" [(ngModel)]="person.address.region" />
    </div>
  </div>

  <button type="submit">Submit</button>
</form>

We add #personForm="ngForm" to set the form’s name to personForm and designate it as a template-driven form.

(ngSubmit) is still used to listen for form submit events with template-driven forms.

Next, to bind the form controls’ input values to variables in the component, we set the name attribute of each input to a value. name must be set so that Angular can bind the input value to the model variable.

Then we set [(ngModel)] to the property of person that we want to bind to. person is the person variable in app.component.ts.

Now when we type in something and click Submit, we get something like:

{
  "name": "bob",
  "age": 100,
  "address": {
    "street": "abc",
    "city": "abc",
    "region": "abc"
  }
}

being logged by console.log.

We just get the input values from the person module object directly.

Conclusion

Forms are basic parts of any web app. And Angular provides us with ways to create forms with validation without adding any new library.

We can create forms with reactive forms or template-driven forms. It’s easy to get form input values with either kind of form.

With reactive forms, we use the classes provided by the @angular/forms module to create the form control and form group objects and get the form values with the methods provided by the instances of those classes.

With template-driven forms, we use [(ngModel)] to bind the input to a model variable so we can get the input value from the model variable that it’s bound to.


About the Author

John Au-Yeung

John Au-Yeung is a frontend developer with 6+ years of experience. He is an avid blogger (visit his site at https://thewebdev.info/) and the author of Vue.js 3 By Example.

Related Posts

Comments

Comments are disabled in preview mode.