
Using the FormBuilder API
The FormBuilder API is the foundation for reactive forms. You can think of it as a factory for turning out the forms we are constructing in our code. Go ahead and add the ngOnInit lifecycle hook to your class, as follows:
ngOnInit() {
this.sub = this.route.data
.subscribe(
(data: { exercise: Exercise }) => {
this.exercise = data.exercise;
}
);
this.buildExerciseForm();
}
When ngOnInit fires, it will extract the data for an existing or new exercise from the route data that has been retrieved and returned by ExerciseResolver. This is the same pattern we followed with initializing the Workout component.
Now, let's implement the buildExerciseForm method by adding the following code:
buildExerciseForm(){ this.exerciseForm = this.formBuilder.group({ 'name': [this.exercise.name, [Validators.required, AlphaNumericValidator.invalidAlphaNumeric]], 'title': [this.exercise.title, Validators.required], 'description': [this.exercise.description, Validators.required], 'image': [this.exercise.image, Validators.required], 'nameSound': [this.exercise.nameSound], 'procedure': [this.exercise.procedure], 'videos': this.addVideoArray() }) }
Let's examine this code. To start with, we are using the injected instance of FormBuilder to construct the form and assign it to a local variable, exerciseForm. Using formBuilder.group, we add several form controls to our form. We add each of them by a simple key/value mapping:
'name': [this.exercise.name, Validators.required],
The left side of the mapping is the name of the FormControl, and the right is an array containing as its first element the value of the control (in our case, the corresponding element on our exercise model) and the second a validator (in this case, the out-of-the-box required validator). Nice and neat! It's definitely easier to see and reason about our form controls by setting them up outside the template.
We can not only build up FormControls in our form this way but also add FormControlGroups and FormControlArray, which contain FormControls within them. This means we can create complex forms that contain nested input controls. In our case, as we have mentioned, we are going to need to accommodate the possibility of our users adding multiple videos to an exercise. We can do this by adding the following code:
'videos': this.addVideoArray()
What we are doing here is assigning a FormArray to videos, which means we can assign multiple controls in this mapping. To construct this new FormArray, we add the following addVideoArray method to our class:
addVideoArray(){ if(this.exercise.videos){ this.exercise.videos.forEach((video : any) => { this.videoArray.push(new FormControl(video, Validators.required)); }); } return this.videoArray; }
This method constructs a FormControl for each video; each is then added each to a FormArray that is assigned to the videos control in our form.