An Autocomplete looks like a normal text box but provides a menu of suggested options when the user interacts with it. Filters are used to reduce the number of options as the user types.
We can use one property for the Autocomplete search and another for the value that saved in the text box. For example, if I’m searching a list of users I want to search by name, but I really want the user’s ID number stored as the value.
For required fields, we can highlight the first element when the user interacts with the Autocomplete. We can group our options together, but we want to be careful how many options we actually load on a page at once.
You’ve probably seen actions embedded in an Autocomplete. Be careful though, it can confuse your users if you don’t distinguish which selections are options and which are actions. The material specification doesn’t recommend mixing these two things, but if you really need to do it, I’d recommend making it very clear to the user which selections are actions and which are options. Okay, it’s time to add Autocomplete to our application. In fact, let’s add two. Let’s add one that selects a string from an array of string. And let’s make another Autocomplete that selects an object from an object list, so we can see how to work with both of those.
So to get started I’m going to command + P, and we’re going to go to our message-new.component.ts. And I’m going to scroll to line 11, and start a new line here. We’re going to add some properties here. I’m going to add a priorities array, which is going to be a string array. And I’m going to put three priorities in there, High, Medium, and Low. And then I’m going to add a departments object array. And I’ll go ahead and put three departments as objects in there as well.
So the first one will be Complaints. And I’m going to go ahead and copy this and make two more. So I’ll paste this on line 18 and line 22. And we’ll make Complaints, Loyalty, and then I’ll change the id on 23, and make this one Promotions. So now I’ve got those three different data sets that I can work with. Normally I’d pull these from a service, but you’ll be able to do it here like this. I’m going to open up message-new.component.html.
And let’s go to our form and on the first section, just below our email, and above the div with the forward, I’m going to go ahead and start adding our autocompletes. So the first one we’re going to do is going to be priorities. So I’m going to use a mat-form-field elements. Inside that I’m going to create an input type of text. And on this is all on line 10, and then the formControlName is going to be priorityCtrl. And a placeholder is going to be Priority which is the label that shows above the control and material.
And we use the matInput directive, and then I’m going to use a new directive here called matAutocomplete. So, after matInput, I will use matAutocomplete equals auto, and then I’m going to go ahead, and use the required attribute here ’cause that’ll make the little star show up. That doesn’t actually make it required, but we will do that with the validator. Now, inside that mat-form-field I can go ahead and put my matAutocomplete just below this input. So that’s a mat-autocomplete element. And I could say autoActiveFirstOption.
Since this is required, we’ll go ahead and highlight the first option in the autocomplete. We don’t have to do that, but I think it’s a nice thing to do. And auto equals matAutocomplete. Close that out. Now let’s put some options in here. That’s the mat-option element and we’ll just loop. We’re going to loop through let priority of priorities, which is our string array. And our value is going to be priority. And inside the option as well, I want to go ahead and display some things, so we’ll just display the priority here.
Now let’s save this and run it, and see what we have so far. While that’s starting, I’m actually going to go up to line one, and I want to go ahead and set linear back to true, ’cause I want to see whether or not these fields are actually required or not. Okay, the app’s loaded, let’s go back to my browser. Again, we’re going to the messages/new path. And let’s see what we have. Well, it’s probably going to fail because I haven’t actually imported those components yet. I need that module in here. So let’s go ahead and go back to Visual Studio.
Let’s command + P, and let’s go to the messages module. And I need to actually import the Autocomplete component. So I’ll just go ahead and do that above here, ’cause I like to keep these alphabetized on line 10. And we’ll add the MatAutocompleteModule from @angular/material/autocomplete. And now I’ll copy that MatAutocompleteModule name, and I’ll scroll down here to line 25. We’ll put this above MatButtonModule with a comma. Now let’s save that and refresh the page, and see if we get our Autocomplete now.
And my path has changed, so I need to go back to messages/new. And there, I’ve got an Autocomplete. So I’ve got a Priority, and I can pick a Priority here if I want to. And then I can clear it out. And I’ve got a little star here, it’s kind of vague, but you can see it. If I hit next, you see Email lights up, but Priority does not. Well, let’s fix that so that the Priority itself is required. So to do that I’m going to go back to Visual Studio code, command + P. Let’s go to the message-new-component.ts. And if we scroll down here to line 32, where we have our validation logic, let’s just copy this line, put a comma, paste another one on line 33.
And we’re going to set that Ctrl to priorityCtrl with the same rule that priority control is required. Say this, let’s go back, let’s see what we have now. Now that I have my selector, if I hit this, notice both light up now, they’re both required. So that’s how that works. Now let’s go ahead and add an object selector. Returning to our message-new.component, let’s copy our existing Autocomplete from lines nine to 16, paste the new one right below it, with a little space, and our new control is going to be called the departmentCtrl. And my placeholder or my label that’s going to show up, is going to be Department.
Now when I slide down here I have an Autocomplete, and I need to name it. I’m going to call this one auto2. And then, on line 20, make sure you update that reference here to auto2. And let’s go ahead and let department of departments. I’m going to copy the word department so I don’t type it incorrectly. And our value will be the department object that’s selected. And on line 22 our label is going to be department. Let’s see what this does when we use it. Now before I can actually load it, I need to go back to my TS file, and I need to add the control here in the form group.
So I’m going to copy line 33 with a comma on the end, and let’s add our departmentCtrl here. Save that. Go back to the application. And I have my drop downs. So let’s see I have a Priority drop down, and I have a, well that looks weird. That doesn’t look good at all. Well, let’s clean this up. First thing we’ll do is we’re going to change the way that we display an option. So on line 22 you see we’re actually displaying a department object. We actually want to display a property called name. So let’s save that and let’s see what happens now.
Well, that seemed to fix that problem. Now if I select, no, there’s still an issue here. What’s the issue? Well, even though we’re displaying the name, we’re actually selecting the entire object so when it shows the value, the value is the full object. Well, what do we do? What we want to do here is actually use a new attribute on the elements which is going to let me put a function to display the value. So what I’m going to do here on line 20 is I’m going to add a new directive here called displayWith, and I’m going to put getDepartmentName as the name of the function that we’re going to use to display the value.
So this is really handy so you can actually concatenate multiple values, you can do some formatting, whatever you want to do to actually make that display value look nicer. Returning to our behind the scenes TS file, I’m going to go ahead and create that function now. And that function is called getDepartmentName. And this is very important, you’re going to need to take an object. So in this case, we’re getting a department. And we’re going to return a department, and we don’t want to return department.name because what happens if department is null, well, bad things happen. So let’s check, if department is null, or is present, I should say, return department.name, otherwise return undefined.
Saves us from nasty null errors, in fact, this is an untyped object. I will use the array version, say department name. You’ll want to strongly type these objects as you get going, but for simplicity right now I’m just keeping them as straight objects. Let’s return our application, and see if we resolved our issue. Here I am, I’ve got my Priority selected, I’ve got my Department and… Now I see the pretty Complaints instead of seeing the object, but if you were to actually look at this selection event, I actually selected the Complaint object. So this is good when you want to create relationships of objects if you’re working with a NoSQL database, and you want to create a document that shows the structure of everything, this is what you would use to display function.