17

I've got a pretty large app that has many dropdowns. I don't want to have to modify my data to add a blank option and I don't want the placeholder to be selectable. What's the best approach?

beaudetious
  • 2,354
  • 3
  • 36
  • 60
codevinsky
  • 1,273
  • 1
  • 9
  • 18

2 Answers2

24

We can do this easy by using angular's powerful directive system to extend basic html.

app.directive('select', function($interpolate) {
  return {
    restrict: 'E',
    require: 'ngModel',
    link: function(scope, elem, attrs, ctrl) {
      var defaultOptionTemplate;
      scope.defaultOptionText = attrs.defaultOption || 'Select...';
      defaultOptionTemplate = '<option value="" disabled selected style="display: none;">{{defaultOptionText}}</option>';
      elem.prepend($interpolate(defaultOptionTemplate)(scope));
    }
  };
});

With this, we can now do the following:

<select ng-model="number" 
    ng-options="item.id as item.label for item in values">
</select>

This will create a select box with an unselectable placeholder that says "Select..."

If we want a custom placeholder we can simply do this:

<select ng-model="dog" 
    ng-options="dog.id as dog.label for dog in dogs" 
    default-option="What's your favorite dog?">
</select>

This will create a select box with an unselectable placeholder that says "What's your favorite dog?"

Plunker Example (in coffeescript): http://plnkr.co/edit/zIs0W7AdYnHnuV21UbwK

Plunker Example (in javascript): http://plnkr.co/edit/6VNJ8GUWK50etjUAFfey

codevinsky
  • 1,273
  • 1
  • 9
  • 18
  • This will not work if default-option is dynamic: http://plnkr.co/edit/SNMYtCcjTY5OVYup5TxX?p=preview – Mathew Berg Dec 04 '13 at 13:43
  • No.... it doesn't: http://plnkr.co/edit/q4Kbymxgw3vY6dcXQW1b?p=preview If defaultOption gets set at a later time then the element will not render the updated option. In my example defaultOption gets set to "TEXT SHOULD BE THIS" but you never see it update because you've already created it. – Mathew Berg Dec 17 '13 at 21:42
  • Also, did you look at my plunkr? You'll see that the localize filter is not firing – Mathew Berg Dec 17 '13 at 21:44
  • A few things here: 1. Your directive isn't firing because your directive is wrong. It should be a filter. 2. If you look at the select over-ride directive, you'll notice that the defaultOption is being set based on an attribute, not a scoped value. Because of this, it has to be a string. However, because angular is so awesome, you can use an expression there like so: http://plnkr.co/edit/aWUA2lXEeFqhCmZIdr1d – codevinsky Dec 20 '13 at 01:53
  • As mentioned, look at the latest plunker, if you update the value after the directive is rendered, nothing is changing. Specifically look at the part in the setTimeout. – Mathew Berg Dec 20 '13 at 13:55
  • Here's my suggestion on a good place to start: http://plnkr.co/edit/p5bv4jyEpABgKUtVhqOS?p=preview – Mathew Berg Dec 20 '13 at 14:24
  • This doesn't work anymore since Angular 1.2.16. The first option is selected as default. – adriendenat May 28 '14 at 08:31
23

You can also do it directly in the html.

<select   ng-model="number"
          ng-options="item.id as item.label for item in values">
          <option value="" disabled selected style="display: none;"> Default Number </option>
></select>
Joffrey Outtier
  • 880
  • 10
  • 9