Building a Pizzeria Registration Form

A single phone number isn’t much use on its own. We need context about that number—whose number is it? Why should we send them a text message? In this section , you’ve been hired by your local pizza place to build out an Interactive Online Pizza Experience, that is, some forms, so that locals can order pizza without that awful hassle of talking to someone on the phone. The first full form you’ll create is the registration form where users create their accounts. Practically speaking, we’ll need their name, a password, phone number (to alert them when the pizza’s about to arrive), address, and credit card details. First things first, run ng generate component registration-form and add a route for this new component:

 {
  path: ​'registration'​,
  component: RegistrationFormComponent
 },

When the user has registered, we can store that information and fill in a large portion of the pizza order form you’ll build later in this chapter. The first option that comes to mind is manually building out the registration form by creating a FormControl property for each input element in the form:

 username = ​new​ FormControl(​''​, ​/* validators */​);
 phoneNumber = ​new​ FormControl(​''​, ​/* validators */​);
 streetAddress0 = ​new​ FormControl(​''​, ​/* validators */​);
 streetAddress1 = ​new​ FormControl(​''​, ​/* validators */​);
 city = ​new​ FormControl(​''​, ​/* validators */​);
 /* etc, etc */

If you’re already falling asleep, I don’t blame you. Angular was supposed to save us from all this tedious copy/pasting! FormControl is the basic building block of reactive forms, but there are two abstractions that combine those building blocks into something much easier to work with. These controls can be collected into an object through FormGroup or an array with FormArray. For now, we’ll focus on FormGroup, because it’ll be used in virtually every reactive form you build. A FormGroup takes an object, where the keys are the names of the form elements and the values are FormControl objects.

 myForm = ​new​ FormGroup({
  username: ​new​ FormControl(​''​, ​/* validators */​),
  phoneNumber: ​new​ FormControl(​''​, ​/* validators */​),
 /* etc */
 })

This isn’t much better. There’s still the tedious creation of piles of FormControl objects. Here’s the secret—you should never construct FormControl objects directly like this. Instead, import Angular’s FormBuilder tool and let that do the heavy lifting. FormBuilder is smart enough to know what’s being passed in, allowing you to skip the many redundant new FormControl constructors.

 class​ RegistrationFormComponent ​implements​ OnInit {
  registrationForm: FormGroup;
 constructor​(​private​ fb: FormBuilder) {}
 
  onInit() {
 this​.registrationForm = ​this​.fb.group({
  username: [​''​, ​/* validators */​],
  phoneNumber: [​''​, ​/* validators */​]
  });
  }
 }

Using FormBuilder results in much cleaner and less bloated codebases. Now we can create the form and only focus on the parts we care about (names, values, and validation), while still gaining access to all the tooling we saw in the earlier phone number example. Now that our component has a FormGroup, we need to update the view to connect it to the group as a whole, instead of sewing each individual component on.

 <form ​[​formGroup​]="​registrationForm​"​>
  <label>
  Name:
  <input formControlName=​"username"​/>
  </label>
  <label>
  Phone Number:
  <input formControlName=​"phoneNumber"​/>
  </label>
  <div ​*​ngIf=​"registrationForm.get('phoneNumber').invalid
  && (registrationForm.get('phoneNumber').dirty
  || registrationForm.get('phoneNumber').touched)"​>
  <div ​*​ngIf=​"registrationForm.get('phoneNumber').errors.tooLong"​>
  There are too many digits in your phone number!
  Wanted 10, but you have
  {{ registrationForm.get('phoneNumber').errors.tooLong.numDigits }}
  </div>
  <div ​*​ngIf=​"registrationForm.get('phoneNumber').errors.tooShort"​>
  Your phone number is too short!
  Wanted 10, but you have
  {{ registrationForm.get('phoneNumber').errors.tooShort.numDigits }}
  </div>
  </div>
 </form>

There are a few small changes to note in the phone number snippet above to accomodate the fact that each input element is part of a larger form. First, everything’s enclosed in a <form> tag. We’ve bound registrationForm to this tag using the formGroup directive. This clues in Angular to what this form is specifically looking for. If we introduce an input element that’s not bound to a property on registrationForm, Angular will throw an error, alerting us to this mistake.

Now that we need to pluck the phoneNumber element off the form, rather than having the variable available in the view, the error section has become more verbose. Angular provides a getter here to avoid naming conflicts with properties already on registrationForm. Other than the new getter routine, this section of the form hasn’t changed.

If the extensive getter routine is too cumbersome and clutters up your view, a solution is to add a get property to the component itself:

Getters and Setters

images/aside-icons/note.png

Sometimes, you want the ease of using an object property, but whatever value will be stored there, can’t be easily set. JavaScript provides the get and set keywords for this use case. This means that whenever the username or phoneNumber properties of the class are accessed, the getter function will be called, and the value of the property will be whatever the getter function returns. In this case, it’s merely syntactic sugar, but it can also be useful for computed properties or ensuring a property stays within certain bounds.

 get​ username() { ​return​ ​this​.registrationForm.​get​(​'username'​); }
 get​ phoneNumber() { ​return​ ​this​.registrationForm.​get​(​'phoneNumber'​); }
 <div ​*​ngIf=​"phoneNumber.invalid && (phoneNumber.dirty || phoneNumber.touched)"​>
  <div ​*​ngIf=​"phoneNumber.errors.tooLong"​>
  There's too many digits in your phone number!
  Wanted 10 but you've got {{ phoneNumber.errors.tooLong.numDigits }}
  </div>
  <div ​*​ngIf=​"phoneNumber.errors.tooShort"​>
  Your phone number is too short!
  Wanted 10 but you've got {{ phoneNumber.errors.tooShort.numDigits }}
  </div>
 </div>

So far, so good on creating FormGroups to organize all of the various parts of our form. Now, let’s dig further into the validation rules to see how they can assist us with our form.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.134.151