Because sometimes just one choice isn't enough, you need to allow users to select multiple options. That's when you include a multiselect dropdown on your form.

And Angular Material makes that really easy to do.

In this guide, I'll show you how to include a multiselect in your UI and save the values to a FormGroup object in TypeScript.

You can follow along or just go look at the code. The choice is yours.

Remember: if you're having problems running the Angular app locally, be sure to check the README.

Please note: this guide is a part of an ongoing series of tutorials on how to create a customer relationship management (CRM) application from scratch. The GitHub code for each guide belongs to a specific branch. The master branch holds the entire application up to the current date. If you want to follow the whole series, just view the careydevelopmentcrm tag. Note that the website displays the guides in reverse chronological order so if you want to start from the beginning, go to the last page.

The Business Requirements

Your boss Smithers walks into your office. He quietly sits down in a chair and twiddles his thumbs.

"That CRM you're working on," he says, very slowly. "It allows you to select a line of business for contacts."

He pauses for a moment. And at this point you're pretty sure Smithers smoked a lot of weed last night.

"But you only allow users to select one line of business. In some cases, they may need to select multiple lines of business."

He pauses again.

"Can you make that happen, Hoss?"

Before you can answer, he walks out of your office.

Starting at the End

We're going to do things a little differently today. While you normally start editing TypeScript code and then update the HTML to work with the TS, this time you're going to start with HTML.

Why? Because you won't disrupt anything. Plus, it's nice to get the markup out of the way first.

So edit basic-info-form.component.html and update the line of business input block.

    <div class="vertical-form-field">
      <div class="label">Line of Business</div>
      <div>
        <mat-form-field appearance="fill" class="no-label-field" fxFlex="30" fxFlex.lt-md="100">
          <mat-select multiple formControlName="lineOfBusiness" placeholder="Select a line of business">
            <mat-option *ngFor="let lob of availableLinesOfBusiness" [value]="lob.value">
              {{lob.display}}
            </mat-option>
          </mat-select>
          <mat-error *ngIf="basicInfoFormGroup.controls['lineOfBusiness'].invalid">Please select a line of business</mat-error>
        </mat-form-field>
      </div>
    </div>

The big difference there is the attribute multiple in the <mat-select> element. That tells Angular to allow users to select multiple options from that dropdown.

Welp, that's pretty much it for the HTML.

Componentization

Next, edit basic-info-form.component.ts. Update the FormGroup initialization code to look like this.

    this.basicInfoFormGroup = this.fb.group({
      'firstName': [this.contact.firstName, [Validators.required, Validators.pattern('[A-Za-z \-\_]+')]],
      'lastName': [this.contact.lastName, [Validators.required, Validators.pattern('[A-Za-z \-\_]+')]],
      'email': [this.contact.email, [Validators.pattern("^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$")],
      [this.emailExistsValidator()],
        'blur'
      ],
      'source': [this.contact.source, [Validators.required]],
      'sourceDetails': [this.contact.sourceDetails, [Validators.pattern('[A-Za-z0-9 \-\_]+')]],
      'status': [this.contact.status, [Validators.required]],
      'lineOfBusiness': [this.contact.linesOfBusiness],
      'authority': [authority],
      'title': [this.contact.title, [Validators.pattern('[A-Za-z\-\_]+')]],
      'company': [this.contact.company, [Validators.pattern('[A-Za-z0-9 \-\_]+')]]
    });

Before I get into the line of business part, let me address what's going on with the whole form there.

The code in basic-info-form.component.ts now supports editing contacts as well as creating new ones. So each form field is getting initialized with values from the global Contact object.

That object will be empty if the user is creating a new contact. If the user is editing an existing contact, it will contain the details of that contact.

Now take a look at the linesOfBusiness line. What you can't tell from looking at that line is that this.contact.linesOfBusiness is an array.

And that's the important takeaway here. When you want to support multiselect dropdowns, map your form fields to an array instead of a string or any other single object.

That pretty much takes care of the whole thing. There's not much else to elaborate on here.

Does It Work?

Now let's find out if this thing delivers as advertised.

Fire up your Spring Boot user application. Then, fire up the Spring Boot contact application as well.

Next, launch the Angular CRM application.

Navigate to http://localhost:4200/login and login with the usual credentials (darth/thedarkside).

Go ahead and create a new contact. Be sure to select multiple lines of business.

 

Then, navigate down to the Review & Save section and click Save Info.

You should get that wonderful "Contact Successfully Saved!" message.

But did it work?

Well, one of the easiest ways to check that is to go to your MongoDB client and look at the document in the collection. In my case it looks like this:

 

So it worked.

But, as I alluded to earlier, you also can edit a contact now. Do that by directly encoding a URL.

The URL to edit a contact looks like this: http://localhost:4200/contacts/edit-contact?id=<id>

Just substitute <id> for the contact's ObjectId in Mongo.

Then, take a look at lines of business in the Basic Info form section and you should see the exact same multiple items you selected previously.

Wrapping It Up

Wouldn't it be great if all my articles were this short?

Anyhoo, feel free to use Angular Material selects with the multiple attribute anywhere you need them. They also make great party favors.

As always, you can take a look at the code on GitHub.

Have fun!

Image by Nattanan Kanchanaprat from Pixabay