In the previous chapters, you used Material form fields such as text fields, text area, single select, and multiselect drop-downs. You explored Angular forms, such as template-driven and reactive forms. When building the forms, we need controls in addition to the basic text fields, drop-downs, and so forth. This chapter covers other commonly used Angular Material form fields: the date picker, the slider (for selecting a value in a range), toggle switches, and check boxes. They are a Material Design implementation of Angular components.
This chapter explains importing Angular Material components and discusses common usage with the help of the Superheroes sample application.
Material Design Date Picker Control
Date is a commonly used input field in a form. The Angular Material library provides a date component confined to the Material Design look and feel. The component provides the functionality to easily select a date or switch between previous months and years. For reference, see Figure 10-1, Figure 10-2, and Figure 10-3.
Getting Started
Similar to other Angular Material components, to use Angular Material’s date picker, import the module containing the component (see Listing 10-1). In the Superheroes code sample, all the Material Design components are encompassed in superheroes-material-design.module.ts.
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from '@angular/material/core';
@NgModule({
declarations: [
// Removed code for brevity
],
imports: [
// Removed code for brevity
MatDatepickerModule,
MatNativeDateModule,
],
exports: [
],
providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 10-1
Import Modules for Date Picker
We are importing two modules.
MatDatepickerModule: Contains the Angular Material components and directives for Material Design.
MatNativeDateModule: Contains the date implementation. Components in MatDatepickerModule provide the UI control. It is agnostic of the date implementation underneath. To begin, you may use MatNativeDateModule.
It is imported from @angular/material/core. It uses the JavaScript Date object implementation.
Alternative for MatNativeDateModule
The JavaScript default implementation does not include all locales around the world. Hence it is preferable to use a Moment.js-based implementation named MatMomentDateModule. Moment.js is a popular library for handling the date and time in JavaScript.
To use MatMomentDateModule, install two packages—moment and @angular/material-moment-adapter—with the following command.
npm install --save moment @angular/material/moment-adapter
or
yarn add moment @angular/material-moment-adapter
Next, modify the imports in the Angular module in superheroes-material-design.module.ts. See Listing 10-2.
import { MatDatepickerModule } from '@angular/material/datepicker';
// Leaving the commented import to spot the difference
// import { MatNativeDateModule } from '@angular/material/core';
import { MatMomentDateModule } from '@angular/material-moment-adapter'
@NgModule({
declarations: [
// Removed code for brevity
],
imports: [
// Removed code for brevity
MatDatepickerModule,
// MatNativeDateModule, -- left commented import to sport the difference
MatMomentDateModule,
],
exports: [
],
providers:[HitCounter]
})
export class SuperheroesMaterialDesignModule { }
Listing 10-2
Import MatMomentDateModule Instead of MatNativeDateModule
Date Picker Component
Use Angular Material’s mat-datepicker component for a date picker. Figure 10-2 shows a typical date picker’s look and feel. When using the date picker in a form, we need an input field to show the selected date. The date picker control seen in Figure 10-2 allows you to select a date. The selected date needs a placeholder form field to showcase the date. We use an input field for this purpose.
When creating a new superhero, date of birth is one of the form inputs. mat-datepicker shows the Material Design date control (see Figure 10-2). The input field is used to show the selected date. It also acts as a placeholder to launch the date picker.
The date picker is enclosed in mat-form-field. Similar to a text field in a form, we use a mat-label to show a label for the date-of-birth form field and a matInput (on the input element) to show the selected date.
Note
The “opened” input element on the mat-datepicker component. Since its value is true, date picker is open on page load.
To tie the input field to the date picker, use the template reference variable. Listing 10-3 uses #dateOfBirth in the date picker. Use the matDatePicker input attribute with a value for the dateOfBirth template reference variable to relate the date picker with the input field.
Figure 10-2 showcases three views for the date picker: default, year, and multiyear. To show the date picker in year or multi-year view when it loads, use the input startView on the mat-datepicker component. See Listing 10-4.
When using reactive forms (explained in Chapter 9), formControlName maps date-of-birth to a form control object in a form group. The model object in the Typescript class component shows the selected date of birth.
To initialize with a default value, we may initialize the form control with a date value. See Listing 10-6.
this.superheroFormGroup = new FormGroup( {
name: new FormControl(", Validators.required),
// Removed remaining form group for brevity
dob: new FormControl(new Date('05/20/2019'))
});
Listing 10-6
initialize formControl with a Date Value
Listing 10-7 prints the value of the date-of-birth form control.
console.log("Selected date value ", moment(this.superheroFormGroup.value.dob).toDate());
Listing 10-7
Return Selected Date Value from the Form Group
If we are not using the form control or form group, we use the input value on the directive to provide a value (see Listing 10-8).
Note the input [for]. The template reference variable is now tied to the toggle as well (in addition to the text field).
The mat-datepicker-toggle component shows the calendar icon prefixed or suffixed to the text field. Listing 10-8 uses the matSuffix attribute to show it at the end. We use matPrefix to show it at the start of the text field. See Figure 10-2.
Clicking the calendar icons opens the date picker.
We may use a custom icon instead of the calendar icon. Use matDatepickerToggleIcon directive on the mat-icon component. Listing 10-10 and Figure 10-3 use the child_care icon for date of birth.
Custom Icon for date picker with matDatepickertoggleIcon
Note
Using Angular Material icons need MatIconModule from @angular/material/icon in SuperheroesMaterialDesignModule. We imported it already. Add it to imports on the @NgModule() decorator, if not already done.
Filter Dates
To ensure the correctness of the date fields in a form, consider the following options to filter unwanted dates on the form.
Min and Max Values
Use min and max inputs on MatDatePicker to disable dates before and after the given dates. To provide a real-world example for a min date value, consider the date of birth. We might need to disable all future dates. As another example, when scheduling an appointment, we might have to disable all past dates.
Listing 10-11 shows max set on matDatePicker (see line 4).
Consider scenarios to filter dates based on custom logic. For example, do not allow selecting dates over the weekend or holidays. To achieve this, use MatDatepickerFilter on the MatDatepickerInput directive.
Listing 10-14 filters weekends. It is a method on TypeScript class component. Note that the “date” parameter is each date on the date picker. On a date object, the day()function returns a zero-based index. A value of 0 represents the first day of the week—Sunday, and a value of 6 represents the last day of the week—Saturday.
filterWeekends(date: Date){
// day 0 is Sunday and day 6 is Saturday.
if(date.day() !== 0 && date.day() !== 6){
return true;
}
return false;
}
Listing 10-14
Custom Date Filter Function
Use it in the template with MatDatepickerFilter. See Listing 10-15 and Figure 10-6.
A slider is a Material Design control for selecting numbers or a value within a range; for example, it is on a scale of 1 to 10. Use Angular Material’s matSlider component for the control. Figure 10-7 is a depiction of a slider.
Getting Started
To use Angular Material’s matSlider, import the module containing the component. See Listing 10-16. In the Superheroes code sample, all the Material Design components are encompassed in superheroes-material-design.module.ts.
import { MatSliderModule } from '@angular/material/slider';
@NgModule({
declarations: [
// Removed code for brevity
],
imports: [
// Removed code for brevity
MatSliderModule,
],
exports: [
],
providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 10-16
Import Modules for Slider
Slider in an Input Form
Form fields that need to select a value within a range of numbers, like a feedback rating, may use a slider. In the Create Superhero form, let’s add a ratings field (see Listing 10-17).
The following are the input elements on the slider component.
min: The start value of the slider range.
max: The end value of the slider range.
step: As the user drags the slider, increments whether the rating should increase or decrease.
thumbLabel: Shows a label for the selected value; especially useful on mobile screens when dragging the slider with your fingers. Note the value of 8, which is the thumb label in Figure 10-7.
Note
You may use data binding on all input values. In Listing 10-17, we bind the minRating and maxRating defined in TypeScript class component. We hard-code this step in the HTML template. If required, we may apply input binding on the step as well.
If we use reactive forms, and the rating is a field on a form group, we may use formControlName. A value is initialized and updated as the user changes it on the screen.
Listing 10-18 line 6 shows the TypeScript file component for a form control named “rating”. The form control is mapped in the HTML template with formControlName. See line 4 in Listing 10-19. Note the form group on the form element in line 2.
The variable rating is defined in the TypeScript class component. As the user drags the slider, we may use the event named input to capture the changed value. See Listing 10-21.
We pass the event to the onSliderChange function on the TypeScript class component. Use the value object on the event object to retrieve the user-selected value. For defining the data type for the event or the function parameter, import MatSliderChange from the @angular/material/slider module.
Note
In template-driven forms, we may use data-binding features and ngModel on mat-slider to read chosen value or set a new value.
The slider component can be oriented vertically. It is natural to drag up or down with the thumb and useful on mobiles screens. Consider the volume rocker on mobile devices as an example.
Use the vertical input attribute, true, for vertical orientation.
Toggle Switch and Check Box
We may use toggle switches or check boxes to switch a feature on or off; select from the available options or any similar use case. Both components serve a similar purpose. We may pick one of the two components and use consistently across the application.
Toggle switches provide a relatively modern look and feel, colors, and animation. Figure 10-8 showcases toggle switches.
Use matSlideToggle component in Angular Material for toggle switch implementation.
Check boxes are traditional. We may use the Angular Material component for a Material Design look and feel, including colors and animation (when selecting and unselecting). Figure 10-9 showcases check boxes.
Use the matCheckbox component in Angular Material for check box implementation.
Getting Started with Toggle Switch
To use Angular Material’s matSlideToggle, import the module named MatSlideToggleModule, which contains the component. Consider Listing 10-22. In the Superheroes code sample, all the Material Design components are encompassed in superheroes-material-design.module.ts.
import { MatSlideToggleModule } from '@angular/material/slide-toggle'
@NgModule({
declarations: [
// Removed code for brevity
],
imports: [
// Removed code for brevity
MatSlideToggleModule,
],
exports: [
],
providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 10-22
Import Modules for Toggle Switch
Getting Started with Check Box
To use Angular Material’s matCheckbox, import the module named MatCheckboxModule, which contains the component. See Listing 10-23. In the Superheroes code sample, all the Material Design components are encompassed in superheroes-material-design.module.ts.
import { MatCheckboxModule } from '@angular/material/checkbox';
@NgModule({
declarations: [
// Removed code for brevity
],
imports: [
// Removed code for brevity
MatCheckboxModule,
],
exports: [
],
providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 10-23
Import Modules for Check Box
Toggle Switch in an Input Form
A toggle switch allows the user to select or unselect a value. The value could be part of a group, like a list of cities, or it could be an isolated value.
The following attributes are used on the component.
checked: If true, shows the toggle selected. We may use this attribute to set a default value.
labelPosition: By default, it is set to “after”. We may use “before” to show the label first and the toggle switch later.
disableRipple: If true, disables the ripple animation on a Material Design component.
checked: Emits an event of type MatSlideToggleChange. Listing 10-25 prints the checked property, which indicates if the toggle is selected or not.
onToggleChange(event: MatSlideToggleChange){
console.log(event.checked );
}
Listing 10-25
Change Handler for the Toggle
Note
Import the event MatSlideToggleChange from the @angular/material/slide-toggle module. We used it as a parameter on the onToggleChange function. It helps provide data type for the event object in the TypeScript class.
Listing 10-25 is about toggle switches in a form group. It results in showing a list of cities with toggle switch as in Figure 10-10. In the code sample, the component TypeScript file has an array with list of cities. See Listing 10-26. The HTML template iterates through the array with ∗ngFor to show cities that can be toggled on/off. See Listing 10-27.
cities = [ {
name: "New York",
selectedByDefault: true
},{
name: "Boston",
selectedByDefault: false
},{
name: "Hyderabad",
selectedByDefault: false
}, {
name: "Bengaluru",
selectedByDefault: true
}];
Listing 10-26
List of Cities in the TypeScript Class File Component
<div formArrayName="jurisdiction" *ngFor="let city of superheroFormGroup.controls.jurisdiction.controls; let i=index;" >
<mat-slide-toggle [formControlName]="i" >
{{cities[i].name}}
</mat-slide-toggle>
</div>
Listing 10-27
Show List of Cities with Toggle Switches in a Form
Note formArrayName in Listing 10-27. In this sample, we are using Reactive Forms and a form group. The toggle switch is part of a form group. See Listing 10-28.
1. ngOnInit() {
2. // Create form controls array based on the list of cities
3. let j = this.cities.map( i => new FormControl(i.selectedByDefault));
4. this.superheroFormGroup = new FormGroup( {
5. name: new FormControl(“, Validators.required),
6. // removed other controls for brevity
7. jurisdiction: new FormArray(j)
8. });
9.}
Listing 10-28
Create formArray Based on List of Cities
Note the statements in line 3 and line 7. First, using the list of cities (which we also used to show toggle switches on the HTML template), we create an array of form controls. In the form group, we create a form array named “jurisdiction” that uses the array of form controls.
The form control initializes with selectedByDefault field on the city object. See line 3 in Listing 10-28. The field is defined in each city object in Listing 10-27. The default selected value changes case by case. We arbitrarily set some cities to true and the others to false.
As the user changes the values on the form, including selecting a city as a jurisdiction for the superhero, form controls in the form group are updated. We use this data when we submit the form. Just to demonstrate that the data was updated, Listing 10-29 subscribes to the form group’s valueChanges observable. Read Chapter 9 for more information on the observable.
With subscribe(), we receive data and a model object representing form controls. In the data, we iterate through a jurisdiction array. Since we have four cities, it returns four true or false values, depending on if the city is selected or not. When printing the debug log, we select the city name and the user-selected value. See Figure 10-10 for the result.
Note
In template-driven forms, we may use data-binding features and ngModel on mat-slide-toggle to read if an option is selected or to toggle true/false.
Check Box in an Input Form
Similar to toggle switches, check boxes could also be part of a group or an isolated value. As mentioned earlier, the matCheckbox component is used for a Material Design look and feel functionality on a check box. See Listing 10-30.
The following attributes are used on the component.
checked: If true, the check box is selected. You may use this attribute to set a default value.
labelPosition: By default, it is set to “after”. You may use “before” to show the label first and the check box afterward.
disableRipple: If true, disables the ripple animation in the Material Design component.
change: Emits an event of type MatCheckboxChange. Listing 10-31 prints the checked property, which indicates if the toggle is selected or not.
onToggleCheckboxChange(event: MatCheckboxChange){
console.log(event.checked );
}
Listing 10-31
Change Handler for the Check Box
Note
Import MatCheckboxChange from the @angular/material/checkbox module. We used it as a parameter on the onToggleCheckboxChange function. It helps provide a data type for the event object in the TypeScript class.
Listing 10-31 is about check boxes in a form group. It results in showing a list of cities with check boxes, as shown in Figure 10-10. In the code sample, the TypeScript file component has an array with a list of cities. See Listing 10-32. The HTML template iterates through the array to show the check boxes.
<div formArrayName="jurisdiction" *ngFor="let city of superheroFormGroup.controls.jurisdiction.controls; let i=index;" >
Note formArrayName. In this sample, we are using reactive forms and a form group. The check box is part of a form group. See Listing 10-33.
ngOnInit() {
// Create form controls array based on the list of cities
let j = this.cities.map( i => new FormControl(i.selectedByDefault));
this.superheroFormGroup = new FormGroup( {
name: new FormControl(“, Validators.required),
// removed other controls for brevity
jurisdiction: new FormArray(j)
});
}
Listing 10-33
Create formArray Based on List of Cities
Note the two statements in Listing 10-33. First, using the list of cities (which we also used to show check boxes in the HTML template), we create an array of form controls. We use these form controls and create a form array. It is named jurisdiction. Notice, the form array, jurisdiction is part of the superhero form group.
The form control initializes with selectedByDefault field on the city object. It is one of the fields on city object (defined in Listing 10-32). We arbitrarily set this value true for some cities and false for the other.
As the user changes values on the form, including selecting a city as a jurisdiction for the superhero, form controls on the form group are updated. We use this data when we submit the form. Just to demonstrate data is updated, consider Listing 10-34, which subscribes to the form group’s valueChanges observable. Read Chapter 9 for more information on the observable.
On the subscribe, we receive data, a model object representing the form controls. In the data, we iterate through a jurisdiction array. Since we have four cities, it returns four true or false values, depending whether the city is selected. When printing the debug log, we select the city name and the user-selected value. Figure 10-11 shows the result.
Note
In template-driven forms, we may use data-binding features and ngModel on the mat-checkbox to read if an option is selected or to switch true/false.
Conclusion
This chapter explored the date picker component. We also used the mat-slider component that provides Material Design slider control.
The chapter covered using toggle switches, which are a modern approach to enabling or disabling a feature on a form. Using components with reactive forms was discussed, and traditional ways to select or unselect a feature on a data form using check boxes was covered.
Exercise
In the dinosaurs form, provide options to select the continents that a given dinosaur was found in. Create the form with the following toggle button options. Selecting at least one continent is mandatory.
North America
South America
Greater India
Europe
Arabia
Laurasia
Gondwanaland
Provide a date-of-discovery option. Do not allow the date to be prior to 1900. The date cannot be later than today (the current system date).