4

I have a form and has a bunch of md-selects, text fields and so on. It is a large form and the users expect to press tab and navigate through different form fields. When md-select receives focus via tab key press, it doesnt show the dropdown. An additional down arrow press is required in this case. Is there any way to get the select to display the dropdown without a mouseclick or a down key press ?

I tried adding link functions to mdSelect directive to register a click or a down key press event and it seemed to not work as well. Also, md-autocomplete has a different look and feel altogether, so it doesnt go along with the other input containers.

Additionally is there anyway to get the select dropdown to appear below the input area.

I like the code to be clean and prefer not to use any jquery functions on it. Thanks in advance.

jose
  • 143
  • 2
  • 13

3 Answers3

4

Here's a screen shot of the results:

angular material md-select to show the dropdown on focus

Here's the key HTML:

<md-input-container md-no-float flex="30">
  <md-select name="favoriteColor" ng-model="color" placeholder="Pick a Color" 
             ng-init="showOptions=true" 
             my-on-focus="showOptions" 
             md-on-close="showOptions=false">
    <md-option value="red">Red</md-option>
    <md-option value="blue">Blue</md-option>
    <md-option value="green">Green</md-option>
  </md-select>
</md-input-container>

Note the ng-init, my-on-focus, and md-on-close attributes.

Here's the AngularJS directive:

app.directive('myOnFocus', function() {
  return {
    scope: true,
    restrict: 'A',
    link: function(scope, elem, attr, ctrl) {
      elem.bind('focus', function() {
        if (scope[attr.myOnFocus]) {
          elem.triggerHandler('click');
        }
      });
      elem.bind('blur', function() {
        scope[attr.myOnFocus] = true;
      });
    }
  };
});

The trick is to set the showOptions variable to false when the select is closed so it doesn't open again until blur is run in the directive.

Here's the CSS to get the select dropdown to appear below the input area:

md-select-menu {
  margin-top: 50px;
}

Finally, here's a working Plunker, http://plnkr.co/edit/FD5u78pC3HbO9UwUOKXR?p=preview.

Hope it helps. Let me know if you have any questions.

Tim Harker
  • 2,367
  • 1
  • 15
  • 28
  • 2
    Thanks for the plunkr. The drop down on focus part is working. I have modified the directive a bit to hide the exposed scope variables and the mdOnClose so that the developer can achieve it in one additional attribute. http://plnkr.co/edit/m6LGjVronWR2dMQrwGFn?p=preview. Please let me know if that is a right approach. However the css change just adds a margin on top, so when i select some other option the dropdown still goes over it. – jose Mar 08 '17 at 12:47
2

Thanks to Tim Harker for the guidance.

I have modified the directive a bit to hide the exposed scope variables and the mdOnClose so that the developer can achieve it in one additional attribute.

plnkr.co/edit/m6LGjVronWR2dMQrwGFn?p=preview.

var app = angular.module('app', ['ngMaterial']);
    app.directive('myOnFocus', function() {
        return {
            scope: true,
            restrict: 'A',
            link: function(scope, elem, attr, ctrl) {
                scope.showOptions = true;
                if ((attr['mdOnClose'])) {
                    attr['mdOnClose'] = "showOptions=false;" + (attr['mdOnClose']);
                } else {
                    (attr['mdOnClose']) = "showOptions=false;"
                }

                elem.bind('focus', function() {
                    if (scope.showOptions) {
                        console.log(scope, elem, attr, ctrl)
                        elem.triggerHandler('click');
                    }
                });

                elem.bind('blur', function() {
                    scope.showOptions = true;
                });
            }
        };
    });
jose
  • 143
  • 2
  • 13
1

Although already answered, I prefered to use another approach with decorators, and wanted to share it, since I don´t like too much to declare multiple directives to control behavior of a single element.

.config(function($provide) {
    $provide.decorator('mdSelectDirective', function($delegate) {
        var directive = $delegate[0];
        var originalController = directive.controller;

        var decoratedController = function($scope, $element){
            $element.bind("keyup", function(ev){
                if ( ev.keyCode == 9 ){ //Tab key code
                    $element.triggerHandler('click');
                }
            });

            originalController($scope, $element);
        }

        directive.controller = decoratedController;

        return $delegate;
    });
})
sergio0983
  • 1,232
  • 8
  • 15