In this step, you will add a floating action button (FAB) that will open a dialog to add a new astronaut
8a) Add a fab to the bottom right of the page
app.component.html
<mat-sidenav-content>
...
</mat-sidenav-content>
<button mat-fab aria-label="Add an astronaut"><mat-icon>add</mat-icon></button>
app.component.css
[mat-fab] {
position: fixed;
bottom: 50px;
right: 50px;
z-index: 10;
}
8b) Generate a new component called AddAstronautComponent
and add the MatDialogModule
to the app
import { MatDialogModule } from '@angular/material/dialog';
@NgModule({
...
imports: [
...
MatDialogModule
],
...
})
8b) Add the AddAstronautComponent
to the entryComponents
property of the module. This is needed because this component is added programmatically rather than being part of another component's template.
@NgModule({
...
entryComponents: [AddAstronautComponent]
...
})
8b) Add a click event to the FAB and call a method on the component to open the dialog
app.component.html
<button mat-fab (click)="addAstronaut()"><mat-icon>add</mat-icon></button>
app.component.ts
import { MatDialog } from '@angular/material/dialog';
import { AddAstronautComponent } from './add-astronaut/add-astronaut.component';
constructor(astronautService: AstronautService, private dialog: MatDialog) {
addAstronaut() {
this.dialog.open(AddAstronautComponent, {
width: '500px',
ariaLabel: 'Add an astronaut'
});
}
8b) Inject MatDialogRef<AddAstronautComponent>
into AddAstronautComponent
and the following method to allow the dialog to close when the user clicks away
constructor(private dialogRef: MatDialogRef<AddAstronautComponent>) { }
close(): void {
this.dialogRef.close();
}
8c) Add a form that includes a few different Angular Material components. This is open-ended, but you can see the code that I wrote below.
app.module.ts
import { MatRadioModule } from '@angular/material/radio';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from '@angular/material';
import { MatSelectModule } from '@angular/material/select';
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
...
imports: [
...
MatRadioModule,
MatDatepickerModule,
MatNativeDateModule,
MatSelectModule,
ReactiveFormsModule,
],
...
})
add-astronaut.component.ts
import { Validators, FormGroup, FormBuilder } from '@angular/forms';
import { AstronautService } from '../astronaut.service';
import { Observable } from 'rxjs';
import { Option } from '../types';
import { map } from 'rxjs/operators';
export class AddAstronautComponent {
astronaut: FormGroup;
undergraduateMajors: Observable<Option[]>;
constructor(
private dialogRef: MatDialogRef<AddAstronautComponent>,
fb: FormBuilder,
astronautService: AstronautService
) {
this.astronaut = fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
middleInitial: ['', Validators.maxLength(1)],
active: [true],
birthdate: ['', Validators.required],
undergraduateMajor: ['', Validators.required]
});
this.undergraduateMajors = astronautService.filters.pipe(
map(filters => filters.find(f => f.category === 'undergraduateMajor')),
map(filter => filter.options),
);
}
saveAstronaut() {
// Save to backend
// Display new astronaut
console.log(this.astronaut.value);
this.close();
}
}
add-astronaut.component.html
<h2>Add astronaut</h2>
<form [formGroup]="astronaut" (ngSubmit)="saveAstronaut()">
<mat-form-field>
<input matInput required placeholder="First name" type="text" formControlName="firstName">
</mat-form-field>
<mat-form-field>
<input matInput required placeholder="Last name" type="text" formControlName="lastName">
</mat-form-field>
<mat-form-field>
<input maxLength="1" matInput placeholder="Middle initial" type="text" formControlName="middleInitial">
</mat-form-field>
<mat-radio-group formControlName="active">
<mat-radio-button [value]="true" name="active">
Active
</mat-radio-button>
<mat-radio-button [value]="false" name="active">
Inactive
</mat-radio-button>
</mat-radio-group>
<mat-form-field>
<input matInput required [matDatepicker]="picker" placeholder="Birthdate" formControlName="birthdate">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>Undergraduate major</mat-label>
<select matNativeControl required formControlName="undergraduateMajor">
<option *ngFor="let major of (undergraduateMajors | async)" [value]="major">
{{ major }}
</option>
</select>
</mat-form-field>
<button mat-raised-button [disabled]="!astronaut.valid" [class.disabled]="!astronaut.valid">Save</button>
<button mat-button type="button" (click)="close()">Cancel</button>
</form>
add-astronaut.component.css
mat-form-field {
width: 100%;
}
mat-radio-button {
margin-right: 1.25em;
}
mat-radio-button {
padding-bottom: .75em;
}
mat-select {
padding-bottom: 1.25em;
}