Submitting & Resetting

Learning Objectives

  • How to call a function on our component when the user clicks submit.

  • How to reset the form back to it’s original state.

Submitting

To submit a form in Angular we need a button with a type of submit in our form markup in between the <form> …​ </form> tags, like so:

<form>
  .
  .
  .
  <button type="submit" class="btn btn-primary" >Submit</button>
</form>

When we press this submit button this triggers the normal HTML5 form submission mechanism, so it tries to POST the form to the current URL.

However instead of issuing a standard POST we want to call a function on our component instead, to do that we use the ngSubmit directive and add it to the form element, like so:

<form (ngSubmit)="onSubmit()">
  .
  .
  .
  <button type="submit" class="btn btn-primary" >Submit</button>
</form>

This hijacks the normal form submission mechanism and instead calls the function onSubmit() on our component. Let’s implement onSubmit() with a simple console.log line like so:

Listing 1. script.ts
onSubmit() {
  if (this.myform.valid) {
    console.log("Form Submitted!");
  }
}

Now when we press the Submit button Form Submitted! gets printed to the console.

Tip

We can do anything we want in this function.

To get the current value of the form model we can call myform.value.

In a later section we cover how to make HTTP requests, after learning that we will be able to make an API request passing in values from our form model.

Resetting

In a model driven form to reset the form we just need to call the function reset() on our myform model.

For our sample form lets reset the form in the onSubmit() function, like so:

Listing 2. script.ts
onSubmit() {
  if (this.myform.valid) {
    console.log("Form Submitted!");
    this.myform.reset();
  }
}

The form now resets, all the input fields go back to their initial state and any valid, touched or dirty properties are also reset to their starting values.

Summary

We can bind to the ngSubmit directives output event to call a function on our component when the user submits a form.

Calling the reset function on a form model resets the form back to it’s original pristine state.

We can call functions on our component to process a form. However Angular gives us another way to process a forms values, by using reactive programming and RxJS, we’ll cover that in the next lecture.

Listing

Listing 3. script.ts
import {
    NgModule,
    Component,
    Pipe,
    OnInit
} from '@angular/core';
import {
    ReactiveFormsModule,
    FormsModule,
    FormGroup,
    FormControl,
    Validators,
    FormBuilder
} from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';


@Component({
  selector: 'model-form',
  template: `<form novalidate
      [formGroup]="myform"
      (ngSubmit)="onSubmit()">

  <fieldset formGroupName="name">
    <div class="form-group"
         [ngClass]="{
        'has-danger': firstName.invalid && (firstName.dirty || firstName.touched),
        'has-success': firstName.valid && (firstName.dirty || firstName.touched)
      }">
      <label>First Name</label>
      <input type="text"
             class="form-control"
             formControlName="firstName"
             required>
      <div class="form-control-feedback"
           *ngIf="firstName.errors && (firstName.dirty || firstName.touched)">
        <p *ngIf="firstName.errors.required">Last Name is required</p>
      </div>

      <!--
        <pre>Valid? {{ myform.controls.name.controls.firstName.valid }}</pre>
        <pre>Dirty? {{ myform.controls.name.controls.firstName.dirty }}</pre>
      -->
    </div>

    <div class="form-group"
         [ngClass]="{
        'has-danger': lastName.invalid && (lastName.dirty || lastName.touched),
        'has-success': lastName.valid && (lastName.dirty || lastName.touched)
      }">
      <label>Last Name</label>
      <input type="text"
             class="form-control"
             formControlName="lastName"
             required>
      <div class="form-control-feedback"
           *ngIf="lastName.errors && (lastName.dirty || lastName.touched)">
        <p *ngIf="lastName.errors.required">Last Name is required</p>
      </div>
    </div>
  </fieldset>


  <div class="form-group"
       [ngClass]="{
        'has-danger': email.invalid && (email.dirty || email.touched),
        'has-success': email.valid && (email.dirty || email.touched)
   }">
    <label>Email</label>
    <input type="email"
           class="form-control"
           formControlName="email"
           required>
    <div class="form-control-feedback"
         *ngIf="email.errors && (email.dirty || email.touched)">
      <p *ngIf="email.errors.required">Email is required</p>
      <p *ngIf="password.errors.pattern">The email address must contain at least the @ character</p>
    </div>

    <!--
      <pre>Valid? {{ myform.controls.email.valid }}</pre>
      <pre>Dirty? {{ myform.controls.email.dirty }}</pre>
    -->

  </div>

  <div class="form-group"
       [ngClass]="{
        'has-danger': password.invalid && (password.dirty || password.touched),
        'has-success': password.valid && (password.dirty || password.touched)
   }">
    <label>Password</label>
    <input type="password"
           class="form-control"
           formControlName="password"
           required>
    <div class="form-control-feedback"
         *ngIf="password.errors && (password.dirty || password.touched)">
      <p *ngIf="password.errors.required">Password is required</p>
      <p *ngIf="password.errors.minlength">Password must be 8 characters long, we need another {{password.errors.minlength.requiredLength - password.errors.minlength.actualLength}} characters </p>
    </div>
  </div>

  <!--
    <pre>{{ language.errors | json }}</pre>
  -->

  <div class="form-group"
       [ngClass]="{
        'has-danger': language.invalid && (language.dirty || language.touched),
        'has-success': language.valid && (language.dirty || language.touched)
      }">
    <label>Language</label>
    <select class="form-control"
            formControlName="language">
      <option value="">Please select a language</option>
      <option *ngFor="let lang of langs"
              [value]="lang">{{lang}}
      </option>
    </select>
  </div>

  <button type="submit"
          class="btn btn-primary">Submit
  </button>

  <pre>{{myform.value | json}}</pre>
</form>`
})
class ModelFormComponent implements OnInit {
  langs: string[] = [
    'English',
    'French',
    'German',
  ];
  myform: FormGroup;
  firstName: FormControl;
  lastName: FormControl;
  email: FormControl;
  password: FormControl;
  language: FormControl;


  ngOnInit() {
    this.createFormControls();
    this.createForm();
  }

  createFormControls() {
    this.firstName = new FormControl('', Validators.required);
    this.lastName = new FormControl('', Validators.required);
    this.email = new FormControl('', [
      Validators.required,
      Validators.pattern("[^ @]*@[^ @]*")
    ]);
    this.password = new FormControl('', [
      Validators.required,
      Validators.minLength(8)
    ]);
    this.language = new FormControl('');
  }

  createForm() {
    this.myform = new FormGroup({
      name: new FormGroup({
        firstName: this.firstName,
        lastName: this.lastName,
      }),
      email: this.email,
      password: this.password,
      language: this.language
    });
  }

  onSubmit() {
    if (this.myform.valid) {
      console.log("Form Submitted!");
      this.myform.reset();
    }
  }
}


@Component({
  selector: 'app',
  template: `<model-form></model-form>`
})
class AppComponent {
}


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

platformBrowserDynamic().bootstrapModule(AppModule);

Learn Angular 5 For FREE

I've released my 700 page Kick Starter funded Angular 5 book for FREE