description |
---|
In this section we will make a presentational component to add attendees. |
- Add the component with the following command
ng g c event/components/add-attendee
It is encouraged to make many custom interfaces and discouraged to leave code un-typed. It is important to note these interfaces do not get added to the JavaScript bundled and sent to the browser, so adding them to a global folder like this is acceptable in this respect.
- Create a models folder on the root of the app folder.
- Add a Attendee interface file to the models folder with the below code.
{% code-tabs %} {% code-tabs-item title="src/app/models/attendee.ts" %}
export interface Attendee {
name: string;
guests: number;
attending: boolean;
}
{% endcode-tabs-item %} {% endcode-tabs %}
In Angular and NgRx in particular it is very common to make an index.ts file which acts as a public API for a section of code like a models folder or a feature module. Everything that is meant to be shared from this section of code is described here, helping other developers know what by design is to be consumed from each section of an app.
- Create an index.ts file to the models folder to re-export all the interfaces we make as we go, starting with our Attendee interface.
{% code-tabs %} {% code-tabs-item title="src/app/models/index.ts" %}
export * from './attendee';
{% endcode-tabs-item %} {% endcode-tabs %}
- Add the AddAttendeeComponent to the EventComponent.
{% code-tabs %} {% code-tabs-item title="src/app/event/containers/event/event.component.html" %}
<app-add-attendee></app-add-attendee>
{% endcode-tabs-item %} {% endcode-tabs %}
In Angular you have "Template Driven" and "Reactive Forms". Reactive forms are the newer of the two and the recommended approach from the Angular team. Reactive forms are powerful and flexible with the ability to configure in code making it easy to change forms dynamically, listening to field changes as observables and make custom asynchronous validation simple.
- Import the ReactiveFormsModule into EventModule and register it in the imports array of the @NgModule decorator.
{% code-tabs %} {% code-tabs-item title="src/app/event/event.module.ts" %}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { EventComponent } from './containers/event/event.component';
import { AddAttendeeComponent } from './components/add-attendee/add-attendee.component';
@NgModule({
imports: [
CommonModule,
RouterModule.forChild([{ path: '', component: EventComponent }]),
ReactiveFormsModule
],
declarations: [EventComponent, AddAttendeeComponent]
})
export class EventModule {}
{% endcode-tabs-item %} {% endcode-tabs %}
To keep this presentational component simple and avoid injecting in dependencies making it harder to mock we will not use the popular FormBuilder from Angular. We only have a single field orFormControl
in our FormGroup
but it is easy to imagine how we could add more to this addAttendeeForm
.
- Remove the
constructor
andngOnInit
lifecycle hook from the component, further helping other developers know this is a presentational component and should not need a constructor. - Add
addAttendeeForm
reactive form,FormGroup
andFormControl
.
{% code-tabs %} {% code-tabs-item title="src\app\event\components\add-attendee\add-attendee.component.ts" %}
import { Component } from '@angular/core';
import { Attendee } from '../../../models';
import { FormGroup } from '@angular/forms';
import { FormControl } from '@angular/forms';
import { Validators } from '@angular/forms';
@Component({
selector: 'app-add-attendee',
templateUrl: './add-attendee.component.html',
styleUrls: ['./add-attendee.component.scss']
})
export class AddAttendeeComponent {
addAttendeeForm = new FormGroup({
name: new FormControl('', [Validators.required])
});
}
{% endcode-tabs-item %} {% endcode-tabs %}
- Add
submit
method to be executed when someone hits the add button in the HTML template. - In the
submit
method build up a newattendee
constant which we can add on the attending and guests fields we have not yet implemented in our form. - Console log the submitted value until the next section when we emit the submitted form out of this presentational component to be listened to by the parent container component.
{% hint style="info" %} I am using the Turbo Console Visual Studio Extension to make more readable log messages. {% endhint %}
{% code-tabs %} {% code-tabs-item title="src\app\event\components\add-attendee\add-attendee.component.ts" %}
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Attendee } from '../../../models';
@Component({
selector: 'app-add-attendee',
templateUrl: './add-attendee.component.html',
styleUrls: ['./add-attendee.component.scss']
})
export class AddAttendeeComponent {
addAttendeeForm = new FormGroup({
name: new FormControl('', [Validators.required])
});
submit() {
const attendee = {
name: this.addAttendeeForm.value.name,
attending: true,
guests: 0
};
console.log('TCL: AddAttendeeComponent -> submit -> attendee', attendee);
}
}
{% endcode-tabs-item %} {% endcode-tabs %}
- Create a HTML form element and add an angular
[formGroup]
binding to angularize the form. - and
(ngSubmit)
event handler to call our submit method when the form is submitted. We do not need to pass the form value over we can grab in in the template from theaddAttendeeForm
. - Bind the name field of our FormControl to the input element with angular's
formControlName
attribute.
{% code-tabs %} {% code-tabs-item title="src/app/event/components/add-attendee/add-attendee.component.html" %}
<form [formGroup]="addAttendeeForm" (ngSubmit)="submit()">
<input type="text" formControlName="name">
<button type="submit" >submit</button>
</form>
{% endcode-tabs-item %} {% endcode-tabs %}
- Add styles to make the button and input element inline next to each other.
{% code-tabs %} {% code-tabs-item title="src/app/event/components/add-attendee/add-attendee.component.scss" %}
form {
display: flex;
}
{% endcode-tabs-item %} {% endcode-tabs %}
- Start the app and check the correct value is logged to the console when you submit a name.
{% embed data="{"url":"https://stackblitz.com/github/duncanhunter/angular-and-ngrx-demo-app/tree/5-create-add-attendee-component\",\"type\":\"link\",\"title\":\"StackBlitz\",\"icon\":{\"type\":\"icon\",\"url\":\"https://c.staticblitz.com/assets/icon-664493542621427cc8adae5e8f50d632f87aaa6ea1ce5b01e9a3d05b57940a9f.png\",\"aspectRatio\":0},\"thumbnail\":{\"type\":\"thumbnail\",\"url\":\"https://c.staticblitz.com/assets/icon-664493542621427cc8adae5e8f50d632f87aaa6ea1ce5b01e9a3d05b57940a9f.png\",\"aspectRatio\":0},\"caption\":\"Web Link: Link to the demo app running in StackBlitz"}" %}