Custom dropdown/auto-complete with AngularJS

Update (2015-09-17): Check out new Version 2 of this control.

I’ll admit it, I’m a big fan of AngularJS; it’s a great framework. If you consider yourself a serious front-end developer, you should really know about AngularJS. In our day to day work, we frequently find challenging requirements and problems that need to be solved efficiently and, why not, elegantly. And frameworks such as AngularJS help us achieve just that, and even turn our solutions into generic pieces of work that we can put in our tool box and use here and there across different projects. This time I will talk briefly about one such case. Hopefully it can be of use to someone else, too.

The problem

We all need to use an auto-complete box once in a while. There are many good solutions out there that are easy to use. But… they are usually limited to working with strings. On the other hand, regular select elements are great when you want to display names but use Id’s (or some sort of unique value) for your model and your business rules. But… they are pretty inflexible and “boring”. So, I needed and auto-complete box that worked also well with complex objects, and could integrate seamlessly with AngularJS.

The solution

Create an AngularJS directive from scratch. At least that was the only option I saw. And it didn’t turn out too bad after all. So here it is, Custom Select (sorry for the totally uncreative name).

<div custom-select ng-model="fruit" ng-options="f for f in fruits">

You may have noticed that the attributes look very similar to those of a regular AngularJS select directive (except for the additional custom-select attribute). Assuming you setup the appropriate values in your scope, you’ll get something like this.


If you want to use JSON objects and have a display property and another property that gets saved to your model, you could use something like this:

<div custom-select ng-model="state" ng-options=" as for s in states">

The end result would look very similar, but will work slightly different.

As a bonus, you could use a custom template for your dropdown items. Here’s an example:

<div custom-select ng-model="person" ng-options="t as for t in people">

<div class="pull-left" style="width: 40px">
        <img ng-src="{{ t.picture }}" style="width: 30px" />

<div class="pull-left">
        <strong>{{ }}</strong>
        <span>{{ }}</span>

<div class="clearfix"></div>


And the end result:

If you liked it, you can grab the source code and the examples from Github.

96 thoughts on “Custom dropdown/auto-complete with AngularJS

  1. Great job! I use AngularJS in my personal web applications, it’s amazing web framework, I’ll try your component, thanks!

  2. Is it possible to make it two way databinding? If I set the model ($scope.fruit=’orange’ it doesn’t update the selected item in the dropdown

  3. hi
    I want use you pretty control but I have a problem.
    My project has used Bootstrap3 but custom-select work with Bootstrap 2.
    Can you help me?

      • It doesn’t seem to work when the list is inside an object. For example:
        $scope.growable = { options: [‘Item 1’, ‘Item 2’, ‘Item 3’] };

        But when using:
        $scope.growable = [‘Item 1’, ‘Item 2’, ‘Item 3’];

        works fine.
        Any ideas of why?

  4. Hi Buddy ,
    How to Clear the Selected Value when I press Reset ? Can you Help me in this ?
    Is it Possible to set Values Dynamically to the Custom Select ?

    • You can clear the selected value by setting the ng-model property to null or undefined (e.g. $scope.fruit = null). If by the second question you mean making the option list dynamic, yes, you can.

      • Thanks for your early response.Yeah it’s working fine.
        Could you show me any sample example, so that i can understand.

    • I just modified the sample index file and added a Reset button to one of the examples. There’s also one example where you can add items to the dropdown model by using $scope.growable.push. It also works if you do something like $scope.growable = someOtherValue.

      • Hi buddy ,
        I have a problem here .
        $scope.reset=undefined is Working fine with Reset button . But if i click on the Submit Button , after completing all my necessary things with that scope value . its not Resetting any Value ..

    • If you followed the example, $scope.reset is the name of the function that is called when you click on the button. Make sure you’re setting your ng-model property to undefined, not the function. You will need to call $scope.reset (or whatever your function name is) manually after submitting the form.

  5. Axel, Congratulations for this!
    I’m trying to use it here on my app and I found a problem on line 98(dropdownElement.eq(0).dropdown()), “undefined is not a function”. This error does not happen everytime. I’ve noticed that the problem is because of the dropdown function. Is there any library you used that I should import or put on my definitions to make this work 100% all the time?

    • Hi, Fernando.
      The only two dependencies: jQuery and Bootstrap (more importantly, the dropdown plug-in). Make sure you are referencing the jQuery and bootstrap JavaScript files before this control and your own JavaScript code.

      • Axel, I had a long time without this problem but suddenly it happened again this week.
        I changed your line 98:
        anchorElement = dropdownElement.eq(0).dropdown(),
        anchorElement = $(dropdownElement.eq(0)).dropdown(),
        Fortunately when I was debugging this new line the error “behavior” showed up again and with this new line it worked fine. Now it is working 100% all the time.!

      • My first thought is that you are referencing the jQuery script after the AngularJS script. When Angular initializes, since it doesn’t “see” jQuery, it uses its own implementation of jqLite. The DOM elements that Angular sends in the directives are wrapped by this jqLite object, so the jQuery plugins are not available. In the line you changed, you are explicitly wrapping the element in a jQuery object, so you have access to the Bootstrap dropdown plugin. Try moving the jQuery script tag above the AngularJS one and see what happens.

  6. Hi ,
    How to set a Default value to this Custom Select . I tried something Like this $scope.ngModelOfCombo=someValue; But is not setting by default to the Combo. Suggest me some methods .

    • You just need to specify the default ng-model value in your controller. For example, if you setup your Custom Select like so

          <div custom-select ng-model="fruit" ng-options="f for f in fruits"></div>

      You need to initialize your ng-model variable to whatever initial value you would like, for example $scope.fruit= 'orange'.

  7. Hi Axel,

          Congratulations  very good work. I have small problem when i implemented this one. If the user select any item,then select is disappearing how to show the 'select' option in the dropdown after select the item.
    • Hi, usually that’s the desired behavior (once the user selects an item, the box displays the name of the item so the user knows what is selected). You would need to modify the source code to make it work like you want.

  8. Hi Axel,
    Good work on this one.
    I just have a question here, I am having trouble integrating it to my application.
    I’m getting
    Error: dropdownElement.eq(…).dropdown is not a function

  9. Hi Axel,

    I am getting error
    TypeError: undefined is not a function
    at (http://localhost:8080/TargetModel/ui/js/mr/ng-widgets/custom-select/customSelect.js:98:44)
    for line
    anchorElement = dropdownElement.eq(0).dropdown(),

    // Create dropdown element
    var dropdownElement = angular.element(dropdownTemplate),
    anchorElement = dropdownElement.eq(0).dropdown(),
    inputElement = dropdownElement.eq(1).find(‘:text’),
    ulElement = dropdownElement.eq(1).find(‘ul’);

    Could you please suggest what possibly can be wrong ?

  10. Hello,

    It’s a really nice directive.
    I have a question? Can you help me please to add a value in the dropdown to clear the selected option?
    Kind of like having a value with the functionality of the reset button.

    Thank you.

    • Hi, I’m not sure I understand your question. If you need to reset the selected value you only have to set your ng-model variable to whatever value you need (empty, undefined, or any other default value). This should be done on your controller.

      • When there is no value selected, a “Select…” option appears as default(placeholder).
        When I select a value, i need to have a “Select…” option at the beginning to reset the ng-model.

    • I think I get it now. In that case, you would need to manually insert that option at the beginning of your options list. For example:

      $scope.states = [
          { id: null, name: 'Select...' },
          { id: 'AL', name: 'Alabama' },
          { id: 'AK', name: 'Alaska' },
          { id: 'AS', name: 'American Samoa' },
  11. Awesome plugin Man. Just one thing can we do grouping like for example
    . Kolkata
    . Delhi
    United Stated
    . New York
    . Atlanta
    . Melbourne
    . Sydney
    . Parth

  12. After spending a few hours trying to make this work with Angular in a template with what little instructions you’ve given, I’ve given up on it! Going to try Select2 now!

  13. Hi Axel,

    Thanks for writing this wonderful component.

    I am trying to pre-select an option from the drop down. Following is modified version of your complex object selection example which is not working for me as model itself is an complex object.

    $scope.state = { id: ‘AL’, name: ‘Alabama’ };

    Any suggestions how this can be fixed?

    • The problem is that object equality for objects is given by reference, and for “primitives”, by value. In other words, the first example works because it is plain strings, so if you set $scope.fruit = 'mango', the code will find that one of the elements in the array of values equals 'mango' (by value); but your example with objects is not working because you are creating a new object instance, whose reference won’t equal any of the objects in the array. One way to accomplish what you want is doing something like $scope.state = $scope.states[0].
      As a side note, Angular can compare objects by value, but that involves a higher performance cost since the objects are traversed and tested for value equality.

  14. I am having an application which shows suggestions as we enter the text in the textbox. When I am entering ‘!’ i.e exclamation mark in the text box instead of showing error of special characters, it is considering as “NOT” and displaying results except that particular text. For Eg. If I write “!S” in the textbox it is showing me the results except “S” instead it should throw an error of special characters.

    Kindly provide me with a solution.

    • Hi Ishan,
      The custom select delegates the filtering functionality to the filter filter (documentation). This filter handles the leading ! as a negation and as of now there is no way to configure or disable that behavior. You would need to implement your own filtering logic and plug it into the custom select directive.

  15. I can’t make it work… =[

    I’m using angularjs 1.4 (then, cs-options) jquery 2.1.1, bootstrap 3.3.4…

    The error is in customselect.js at line 100

    var dropdownElement = angular.element(dropdownTemplate),
    anchorElement = dropdownElement.eq(0).dropdown(), // — Hi, I’m line 100 !
    inputElement = dropdownElement.eq(1).find(‘:text’),
    ulElement = dropdownElement.eq(1).find(‘ul’);

    The dropdown method does not exist…

    Somebody can help me ?

  16. Pingback: Custom dropdown/auto-complete with AngularJS (Version 2) | Axel Zarate
  17. Hi, I’m using your autocomplete, but I must add new item to the select list and set this item as selected after some async function. Can you help me?

    • Hi, I’m assuming that your function is asynchronous but the items are stored in an array a variable and the filtering is performed locally. If that’s the case, I suggest you download the latest version from the repository (a new option async was added) and do something along the lines of:

      <div custom-select="i for i in items | filter: { name: $searchTerm }" ng-model="selected">
      $scope.items = [/*Initialize your items array*/];
      // Callback executed after your async function is completed
      function myAsyncFunctionCallback(result) {
          $scope.selected = result;

      The important parts here are the items array and the selected property.

      • Hi,
        Thank you for the help. The new version fixed the adding of new item to the list, even without the async option. Now I can see it there but the label doesn’t update unless I click the select again. I am using custom onAdd function.
        My code is as follows :
        $scope.supplyItem.itemId = data.newItem.itemId;


        div custom-select=”item.itemId as for item in itemsList | filter: $searchTerm” ng-model=”supplyItem.itemId”

        The select ng-model is “supplyItem.itemId” and is set to the new value.

  18. Any reason why angular.module(‘ui.filters’, []); is not included in format.js?

    I see that you have included this line in your sample.html. These customizations can be if we have control over source inclusion in html file.

    In our project all the dependencies are added by gulp. EX:

    From your source:

    // This is needed in order to use the format filter
    angular.module(‘ui.filters’, []);


    How do you think we can use your plug-in?

    • Yes, you’re right. I used that little directive just for the formatting of the messages, but for those same reasons I decided to just include the relevant function inside the directive itself (it’s pretty straightforward). That dependency has been removed for recent versions. Please take a look at the link at the top of the article.

  19. Hi Axel,

    Thank you for the custom dropdown, it’s working fine.
    The is it possible to implement a custom filter, i.e. like in your example «Custom Item Template»,
    to search for name but also for phone, or more attributes?
    Thank you for your time!

  20. Thank you for the custom dropdown. I want to know, how to change the default ‘displayText’ value for different dropdowns. Actually I have 3-4 dropdowns. I want to show like “Select Fruits”, “Select Vegetables”. etc.

    • You can pass options to each custom select directive by using the custom-select-options attribute in your HTML:

      <div custom-select="f in fruits | filter: $searchTerm" custom-select-options="fruitsOptions"></div>

      And in your controller:

      $scope.fruitsOptions = {
          displayText: "Select Fruits"
    • You can plug in your own (or someone else’s) custom filter inside the logic. For example, you can take a look at this Stack Overflow answer on how to provide your own comparator to filter by the start of the string. Then, for the custom-select attribute you would need to specify something like f for f in fruits | filter:$searchTerm:startsWith.

  21. Hey,
    It’s a good directive, but I’m noticing – in loading multiple cutom-selects in a modal window, that this hangs..

    so i have 3 sections specifically where 1 custom-select is rendered in a data-ng-repeat.

    so customers, manufacturers, products (this is in an edit/new order partial)…
    it hangs. it renders eventually, but it’s a delay of a few seconds, which seems odd to me, yet when I load the attrs to the console they’re instantly rendered on modal load.

    The scope array objects are pre-loaded on module load (each section is it’s own module and pre-loads all the assets, ie: customers, manufacturers, products based upon user login) so theoretically this shouldn’t hang because the assets are there – no xhr is required. any ideas on this?

      • I will if the option doesn’t function. I realized by reading the documentation that I can load the custom-select with the search functioning as a typeahead – which might solve my problem.

        I didn’t realize the entire ul/li was compiled rather than simply referenced from the scope – yet you also have an xhr call – so I’m going to try that first and hopefully load multiple key/value pairs – if this presents the same problem I’ll fiddle it and we can take a look 🙂

  22. Hi Axelzarate,
    I am using your Autocomplete dropdown. very Nice!….

    I have an issue. I want to populate my searchable dropdown dynamically. I am calling a service through HTTP and it returns a JSON array with some objects like below:


    I am storing it in a $scope.username=[{the above values}] variable.

    In my HTML, I am calling this variable like below:

    It is not displaying the list at all.
    It takes only the key names where {id:1, name:”banesh”}, but if the key name changes then it doesn’t display anything.

    Need your Help………….

      • Sorry, I forgot to update the $searchTerm with desired attribute. However, can I make the searchTerm for 2 or more fields?

      • No, the objects can have any properties you like, but if you’re filtering by a single property, the property name on the filter must match that of the items. In some of the examples that property happens to be name.

    • I cannot see what HTML code you’re using, but you can use an angular filter, to which you can pass an object to filter on a specific properties, all properties, or a function with custom filter logic. You can refer to the sample usages for reference.

    • There is a displayText option that you can set on the options object in the controller, or if you want to do it directly on the view you could use ng-options="{ displayText: 'Your text goes here...' }".
      If you want to change the default value globally, you could modify the customSelectDefaults on the config or run callback for your module:

      angular.module("app").config(["customSelectDefaults", function (customSelectDefaults) {
          customSelectDefaults.displayText = "Your text goes here...";
  23. Thanks for such a great plugin once again.
    I am interested in knowing if we can lazy load the data in the dropdown. What I mean to say is that, lets say, I have a big json to populate the dropdown and its taking considerable amount of time to create the options. is there any way, we can load say 50 data at first and on scrolling, we load more data?
    Thanks in advance

Leave a Reply to axelzarate Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s