1

So, I was attempting to use the following example: https://github.com/agiratech/angular4-reactive-form-exercise2/

However, when I implement it, and submit my form, no errors show anywhere on the screen. Below you will find all associated code that I can think of that relates. I'm looking for how to get the errors to show on the screen. I'm fairly new to Angular 4, so any help would be appreciated.

pages.module.ts

import ...
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import ...

import { RegisterComponent } from './register/register.component';
import ...
import { ErrorsComponent } from '../errors.component';

@NgModule({
    imports: [
        CommonModule,
        RouterModule.forChild(PagesRoutes),
        FormsModule,
        ReactiveFormsModule
    ],
    declarations: [
        LoginComponent,
        RegisterComponent,
        LockComponent,
        ErrorsComponent
    ]
})

export class PagesModule {}

register.component.ts

import ...
import {FormGroup, FormBuilder, Validators, FormControl, NgForm} from '@angular/forms';
import ...
import { CustomValidators } from "../../validators/custom-validator.directive";

declare var $:any;

@Component({
    moduleId:module.id,
    selector: 'register-cmp',
    templateUrl: './register.component.html'
})

export class RegisterComponent implements OnInit{
    registerForm: FormGroup;
    test : Date = new Date();
    loading = false;
    error = '';

    constructor(
        private form: FormBuilder,
        private router: Router,
        private authenticationService: AuthenticationService)
    {
        this.registerForm = new FormGroup ({
            'username':new FormControl('', Validators.required),
            'email': new FormControl('', [Validators.required, CustomValidators.validEmail]),
            'first_name': new FormControl('', Validators.required),
            'last_name': new FormControl('', Validators.required),
            'password': new FormControl('', Validators.required),
            'confirmPassword': new FormControl('', Validators.required)
        });
    }


    checkFullPageBackgroundImage(){
        var $page = $('.full-page');
        var image_src = $page.data('image');

        if(image_src !== undefined){
            var image_container = '<div class="full-page-background" style="background-image: url(' + image_src + ') "/>'
            $page.append(image_container);
        }
    };

    ngOnInit() {


        this.checkFullPageBackgroundImage();

        setTimeout(function(){
            // after 1000 ms we add the class animated to the login/register card
            $('.card').removeClass('card-hidden');
        }, 700)
    }

    register(registerForm: NgForm) {
        console.log(this.registerForm.value);
    }


}

register.component.html

<form [formGroup]="registerForm" (ngSubmit)="register(registerForm)">
        <div class="card card-plain">
        <div class="content">
         <div class="form-group">
              <input type="text" placeholder="Your First Name" class="form-control" formControlName="first_name">
              <errors [control]="registerForm.controls.first_name"></errors>
         </div>
         <div class="form-group">
              <input type="text" placeholder="Your Last Name" class="form-control" formControlName="last_name">
              <errors [control]="registerForm.controls.last_name"></errors>
         </div>
         <div class="form-group">
              <input type="text" placeholder="Username" class="form-control" formControlName="username">
              <errors [control]="registerForm.controls.username"></errors>
         </div>
         <div class="form-group">
              <input type="email" placeholder="Enter email" class="form-control" formControlName="email">
              <errors [control]="registerForm.controls.email"></errors>
         </div>

         <div class="form-group">
             <input type="password" placeholder="Password" class="form-control" formControlName="password">
             <errors [control]="registerForm.controls.password"></errors>
         </div>
         <div class="form-group">
             <input type="password" placeholder="Password Confirmation" class="form-control" formControlName="confirmPassword">
             <errors [control]="registerForm.controls.confirmPassword"></errors>
         </div>
             </div>
             <div class="footer text-center">
                 <button [disabled]="loading" type="submit" class="btn btn-fill btn-neutral btn-wd">Create Account</button>
                <i *ngIf="loading" class="fa fa-spinner fa-spin fa-fw"></i>
             </div>
             <errors [control]="registerForm"></errors>
         </div>
    </form>

errors.component.ts

import { Component, Input } from '@angular/core';
import { AbstractControlDirective, AbstractControl } from '@angular/forms';

@Component({
  selector: 'errors',
  template: `
    <ul *ngIf="showErrors()">
      <li class="help-box text-warning" *ngFor="let error of errors()">{{error}}</li>
    </ul>
  `,
})
export class ErrorsComponent {

  private static readonly errorMessages = {
    'required': () => 'This field is required',
    'minlength': (params) => 'The min number of characters is ' + params.requiredLength,
    'maxlength': (params) => 'The max allowed number of characters is ' + params.requiredLength,
    'pattern': (params) => 'The required pattern is: ' + params.requiredPattern,
    'age': (params) => params.message,
    'validEmail': (params) => params.message
  };

  @Input()
  private control: AbstractControlDirective | AbstractControl;

  showErrors(): boolean {
    return this.control &&
      this.control.errors &&
      (this.control.dirty || this.control.touched);
  }

  errors(): string[] {
    return Object.keys(this.control.errors)
      .map(field => this.getMessage(field, this.control.errors[field]));
  }

  private getMessage(type: string, params: any) {
    return ErrorsComponent.errorMessages[type](params);
  }

}
1
  • have you filled in all fields and submit or leave some as blank? Commented Nov 28, 2017 at 22:23

2 Answers 2

1

Your example seems to work based on an example I made from it in StackBlitz, but if you look at errors.component.ts you'll see that it says this.control.dirty || this.control.touched, which means you need to focus and then blur the input using your cursor, or enter a value and then backspace removing it to make the required validation display.

This is a list of FormControl properties from the docs and if you click them you can read up on their meaning. So for example dirty:

Touched

get touched: boolean

A control is marked touched once the user has triggered a blur event on it.

Dirty

get dirty: boolean

A control is dirty if the user has changed the value in the UI.

Note that programmatic changes to a control's value will not mark it dirty.

Also, from looking at your code I'd suggest reading the Angular Style Guide, as well as reading up on the FormBuilder. In the StackBlitz example I made I switched your FormGroup example to use FormBuilder, which is more succinct. Finally, it looks like you're using jQuery to add/remove classes, but instead, have a look at ngClass. You don't need jQuery in Angular, you can do everything you need without it.

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, I see that yours works for you. For some reason, mine still does not work for me. I get a TypeError when I don't fill out the email, and then focus and blur. I'm going to publish the app, and upload it for you to review. It will be at member.newworldfantasysports.com, and it's the "register" link, obviously. Thanks for your help.
Have you tried it using FormBuilder change? Maybe compare my example to yours to find out what is otherwise different. Might be easier if you just drop the differences into the stackblitz I made so I can play with it.
I'm not sure how to do what you're asking. It's currently using a FormBuilder...
So, I changed my form to use FormBuilder, and that fixed the validation issue. It seems to work now. I'll mark your answer as accepted.
1

You can try something like this-

Inside component(.ts) file -

public loginForm: FormGroup = this.builder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.minLength(8), Validators.required]]

});

Inside component(.html) file -

<div class="l-form-row l-login-form__field-row">
      <label
        class="o-label l-form-label"
        for="email"
      >Enter your email</label>
      <div class="o-input-container">
        <input
          class="o-input"
          type="text"
          name="email"
          id="email"
          formControlName="email"
          placeholder="Email"
        ><div class="o-input-icon"></div>
      </div>
      <div
        class="o-input-error l-form-error"
        eValidationError="required"
        control="email"
      >Email is required</div>
      <div
        class="o-input-error l-form-error"
        eValidationError="email"
        control="email"
      >Email is invalid</div>
    </div>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.