Angular Template Driven Form

Template-driven forms

Forms are the most common UI in business applications. We use forms to sign in/out, submit a request, place an order, book a flight, schedule a meeting, and other data-entry tasks. Smart UI for Angular provides native experience of building Forms with Angular.

Introduction to Template-driven forms with Smart UI for Angular

The Smart Forms components for Angular have support for two-way data binding, change tracking, validation, and error handling, which you'll learn about on this page. Such components are:
  • Smart.Input
  • Smart.TextBox
  • Smart.MultilineTextBox
  • Smart.NumericTextBox
  • Smart.MaskedTextBox
  • Smart.PasswordTextBox
  • Smart.Calendar
  • Smart.DateTimePicker
  • Smart.ColorPicker
  • Smart.ColorPanel
  • Smart.ListBox
  • Smart.DropDownList
  • Smart.ComboBox
  • Smart.FileUpload
  • Smart.Slider
  • Smart.Tank
  • Smart.Gauge
  • Smart.SwitchButton
  • Smart.CheckBox
  • Smart.RadioButton
  • Smart.Rating
This page shows you how to build a simple form from scratch. It is based on https://angular.io/guide/forms. Along the way you'll learn how to:
  • Build an Angular form with a component and template.
  • Use ngModel to create two-way data bindings for reading and writing input-control values.
  • Validate user input and show validation errors to users and enable/disable form controls.
  • Use template refeence variables.
.

You'll learn to build a template-driven form that looks like this:
angular form

Let's start

  1. ng new my-project
  2. cd my-project.
  3. ng add smart-webcomponents-angular.
  4. ng-serve and in your browser enter localhost:4200.
  5. Navigate to the \src\app folder.
  6. Open app.module.ts and put the following content:
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { FormsModule } from '@angular/forms';
    
    import { DropDownListModule } from 'smart-webcomponents-angular/dropdownlist';
    import { ButtonModule } from 'smart-webcomponents-angular/button';
    import { InputModule } from 'smart-webcomponents-angular/input';
    
    import { AppComponent } from './app.component';
    
    @NgModule({
        declarations: [AppComponent],
        imports: [BrowserModule, FormsModule, DropDownListModule, ButtonModule, InputModule],
        bootstrap: [AppComponent],
        entryComponents: [AppComponent]
    })
    
    export class AppModule { }
    
    
  7. Create a new Hero class
    export class Hero {
    
        constructor(
            public id: number,
            public name: string,
            public power: string,
            public alterEgo?: string
        ) { }
    }
    
  8. Open app.component.ts and put the following content:
    import { Component, ViewChild, OnInit, AfterViewInit } from '@angular/core';
    import { DropDownListComponent } from 'smart-webcomponents-angular/dropdownlist';
    import { Hero } from './hero';
    
    @Component({
    	selector: 'app-root',
    	templateUrl: './app.component.html',
    	styleUrls: ['./app.component.css']
    })
    
    export class AppComponent implements AfterViewInit, OnInit {
    	@ViewChild('power', { read: DropDownListComponent, static: false }) power: DropDownListComponent;
    
    	powers = ['Really Smart', 'Super Flexible',
    		'Super Hot', 'Weather Changer'];
    
    	model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');
    
    	submitted = false;
    
    	onSubmit() { this.submitted = true; }
    
    	ngOnInit(): void {
    		// onInit code.
    	}
    
    	ngAfterViewInit(): void {
    		// afterViewInit code.
    		this.init();
    	}
    
    	init(): void {
    		// init code.
    	}
    
    	newHero() {
    		this.model = new Hero(42, '', '');
    	}
    
    	get diagnostic() { return JSON.stringify(this.model); }
    }
    
  9. Open app.component.html and put the following content:
     
    <div [hidden]="submitted" class="container">
        <h1>Hero Form</h1>
        <form (ngSubmit)="onSubmit()" #heroForm="ngForm">
            <div class="form-row">
                <label for="name">Name</label>
                <smart-input required class="form-component" [(ngModel)]="model.name" name="name" id="name" #name="ngModel">
                </smart-input>
                <div [hidden]="name.valid || name.pristine" class="alert alert-danger">
                    Name is required
                </div>
            </div>
    
            <div class="form-row">
                <label for="alterEgo">Alter Ego</label>
                <smart-input class="form-component" [(ngModel)]="model.alterEgo" name="alterEgo" id="alterEgo">
                </smart-input>
            </div>
            <div class="form-row">
                <label for="power">Hero Power</label>
                <smart-drop-down-list required #power="ngModel" class="form-component" [(ngModel)]="model.power"
                    name="power" id="power" required>
                    <smart-list-item *ngFor="let pow of powers" [value]="pow">{{pow}}</smart-list-item>
                </smart-drop-down-list>
                <div [hidden]="power.valid || power.pristine" class="alert alert-danger">
                    Power is required
                </div>
            </div>
            <div class="smart-stack-layout">
                <smart-button [disabled]="!heroForm.form.valid" type="submit" class="success item">Submit</smart-button>
                <smart-button type="submit" (click)="newHero(); heroForm.reset()" class="primary item">New Hero
                </smart-button>
            </div>
        </form>
    </div>
    
    <div [hidden]="!submitted">
        <h2>You submitted the following:</h2>
        <div class="row">
            <div class="col-xs-3">Name</div>
            <div class="col-xs-9">{{ model.name }}</div>
        </div>
        <div class="row">
            <div class="col-xs-3">Alter Ego</div>
            <div class="col-xs-9">{{ model.alterEgo }}</div>
        </div>
        <div class="row">
            <div class="col-xs-3">Power</div>
            <div class="col-xs-9">{{ model.power }}</div>
        </div>
        <br>
        <smart-button class="primary" (click)="submitted=false">Edit</smart-button>
    </div>
    <br /><br />
    <h2>Changes Log:</h2>
    {{diagnostic}}
    

ngFor

Note this code:
<div class="form-row">
	<label for="power">Hero Power</label>
	<smart-drop-down-list required #power="ngModel" class="form-component" [(ngModel)]="model.power"
		name="power" id="power" required>
		<smart-list-item *ngFor="let pow of powers" [value]="pow">{{pow}}</smart-list-item>
	</smart-drop-down-list>
	<div [hidden]="power.valid || power.pristine" class="alert alert-danger">
		Power is required
	</div>
</div>
It generates a DropDownlist and adds powers with *ngFor. This code repeats the <smart-list-item> tag for each power in the list of powers. The pow template input variable is a different power in each iteration; you display its name using the interpolation syntax.
angular form dropdownlist

ngModel

The Two-way data binding is achieved with ngModel. Note the [(ngModel)]="model.name", [(ngModel)]="model.alterEgo", [(ngModel)]="model.power" in the template above.
You also need a template reference variable to access the input box's Angular control from within the template.
<smart-input required class="form-component" [(ngModel)]="model.name" name="name" id="name" #name="ngModel"></smart-input>
Here you created a variable called name and gave it the value "ngModel".
Note the Form tag declaration. It includes NgForm directive, which supplements the form element with additional features. It keeps information about the components with ngModel and name attribute. It watches their properties and validation. NgForm also has a valid property which is true only if every contained component is valid.

One of the additional benefits of using ngModel in a form is that it gives you more than just two-way data binding. It also keeps track of the components state - whether the component is touched or the value is changed.

State Class if true Class if false
The control has been visited. ng-touched ng-untouched
The control's value has changed. ng-dirty ng-pristine
The control's value is valid. ng-valid ng-invalid


  • Form Validation

    Form validation is used to improve the data quality by validating user input for accuracy and completeness. Every time the value of a form control changes, Angular runs its built-in validation and generates either a list of validation errors, which results in an INVALID status, or null, which results in a VALID status. The "Name" and "Power" fields on this form are marked as required. Required fields have a green bar on the left to make them easy to spot. If you delete the hero name, the form displays a validation error in an attention-grabbing style:

    angular form validation
    The Submit button is disabled, and the "required" bar to the left of the input control changes from green to red.

    Validation-related attributes

    The following attributes are used to describe validation constraints:

    Attribute Form controls supporting the attribute Possible values Constraint description Associated violation
    pattern smart-input, smart-text-box, smart-password-text-box, smart-mulitiline-text-box, smart-textarea A JavaScript regular expression, ignoreCase, and multiline flags disabled) The value must match the pattern. patternMismatch constraint violation
    min smart-slider, smart-tank, smart-gauge, smart-numeric-text-box A valid number The value must be greater than or equal to the value. rangeUnderflow constraint violation
    smart-date-time-picker, smart-calendar A valid date
    datetime, datetime-local, time A valid date and time
    max smart-slider, smart-tank, smart-gauge, smart-numeric-text-box A valid number The value must be less than or equal to the value rangeOverflow constraint violation
    date, month, week A valid date
    datetime, datetime-local, time A valid date and time
    required All Form controls none as it is a Boolean attribute: its presence means true, its absence means false There must be a value (if set). valueMissing constraint violation
    minlength smart-input, smart-text-box, smart-password-text-box, smart-mulitiline-text-box, smart-textarea An integer length The number of characters (code points) must not be less than the value of the attribute, if non-empty. All newlines are normalized to a single character (as opposed to CRLF pairs) for <textarea>. tooShort constraint violation
    maxlength smart-input, smart-text-box, smart-password-text-box, smart-mulitiline-text-box, smart-textarea An integer length The number of characters (code points) must not exceed the value of the attribute. tooLong constraint violation

    Let's look at the Template below:
    <smart-input id="name" name="name" class="form-control"
          required minlength="4" 
          [(ngModel)]="hero.name" #name="ngModel" ></smart-input>
    
    <div *ngIf="name.invalid && (name.dirty || name.touched)"
        class="alert alert-danger">
    
      <div *ngIf="name.errors.required">
        Name is required.
      </div>
      <div *ngIf="name.errors.minlength">
        Name must be at least 4 characters long.
      </div>
    </div>
    
    1. The <smart-input> element carries the HTML validation attributes: required and minlength.
    2. #name="ngModel" exports NgModel into a local variable called name. NgModel mirrors many of the properties of its underlying FormControlvalid and dirty. For a full list of control properties, see the AbstractControl API reference.
    3. The *ngIf on the <div> element reveals a set of nested message divs but only if the name is invalid and the control is either dirty or touched.
    4. Each nested <div> can present a custom message for one of the possible validation errors. There are messages for required, minlength.

    Submit the Form with ngSubmit

    The user should be able to submit this form after filling it in. The Submit button in the Form triggers a form submit on click. That is because of its type (type="submit").
    On submit, the onSubmit function is called and it changes the submitted flag to true. You can now note the View changes after the form submission. Our main Form is visible, when the form is not submitted. After submitting the Form, the Form's submit information is displayed. This is achieved by using the [hidden] attribute and binding it to the submitted variable.
    <div [hidden]="!submitted">
        <h2>You submitted the following:</h2>
        <div class="row">
            <div class="col-xs-3">Name</div>
            <div class="col-xs-9">{{ model.name }}</div>
        </div>
        <div class="row">
            <div class="col-xs-3">Alter Ego</div>
            <div class="col-xs-9">{{ model.alterEgo }}</div>
        </div>
        <div class="row">
            <div class="col-xs-3">Power</div>
            <div class="col-xs-9">{{ model.power }}</div>
        </div>
        <br>
        <smart-button class="primary" (click)="submitted=false">Edit</smart-button>
    </div>
    


    Example