2

I am creating a new directive for the select element. As a best practice, I would like to receive some of the options from the server and one option I want to create in the client code e.g. "Search all cars".

This is an example of how I want it to look:

<select>
  <option value="">Search all cars</option>
  <option value="aud">Audi</option>
  <option value="bmw">BMW</option>
  <option value="maz">Mazda</option>
</select>

It is important that the value of "Search all cars" is empty.

But even though I have added an empty element in the select (ref other SO posts) it still gives me an unwanted option:

<option value="?" selected="selected"></option>

Here is an plunker example of the issue/bug using an Angular directive with transclude and replace.

Anyone got a suggestion of how to solve this?

I have also added an issue to the angular team here.

EDIT:

The reason why I would like to have this as an directive is that I want to decide if I should have the "Search all cars" option or not depending on where it is implemented in my application.

EDIT2: Angular team confirms that this is a bug. "It looks like the root reason is that if an unknown option is added after the initial setup, then it will not replace the generated unknown option" - lgalfaso.

Community
  • 1
  • 1
Jan-Terje Sørensen
  • 14,468
  • 8
  • 37
  • 37
  • 2
    I think this is because you *transclude* the default (empty) option into the select. From how transclude works, I'd guess that the final select-directive simply does not recognize the injected default option, and thus creates it's own, because the model does not fit any value in given options. – Yoshi Apr 16 '14 at 09:16
  • @Yoshi - I concur! Do you know if this is a angular bug or feature? – Jan-Terje Sørensen Apr 16 '14 at 09:27
  • I'd say it's just how it works (especially how the directives are compiled). Because of that, I think you'll have to write your own compile method to inject the default option into the select without using transclusion. – Yoshi Apr 16 '14 at 09:31

2 Answers2

1

@Yoshi is right, it's to do with ngTransclude. As soon as you move the default option into the directive itself, the problem goes away. To work around this issue, since you don't care about the default value so much, you can modify the directive slightly and just import the text for the default option:

app.directive('mySelect', [function () {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      default: '@'
    },
    template: '<select ng-options="key as value for (key, value) in myMap"><option value="">{{ default }}</option></select>',
    link: function postLink(scope, element) {
      scope.myMap = {"bmw":"BMW","maz":"Mazda","aud":"Audi"}; // e.g. hashmap from server
    }
};

And then your HTML becomes:

<my-select ng-model="myModel" ng-change="doSomething(myModel)" default="Search all cars">
</my-select>
morloch
  • 1,781
  • 1
  • 16
  • 23
  • @morlock yes, that would solve the transclude issue. It's just that I am making this directive so that I can choose if i need the default empty option or not. I'll update my question. – Jan-Terje Sørensen Apr 16 '14 at 10:04
0

I just had the same issue as you and unfortunately @morloch's answer did not help me. In my case, the transclusion is dynamic.

I started with your plunker and figured out that, if we use the transclusion during the prelink, it solves the issue.

   link: {
      pre:function preLink(scope, element, attrs, controllers, transcludeFn) {
        scope.myMap = {"bmw":"BMW","maz":"Mazda","aud":"Audi"}; // e.g. hashmap from server
        transcludeFn(scope, function(clone) {
          element.append(clone);
        });
      }
    } 

Here is my plunker : http://plnkr.co/edit/4V8r6iW2aKCLLbpIZc5e?p=preview

Ash
  • 1
  • 2