Angular JS: enfoca automáticamente la entrada y muestra el menú desplegable typeahead – ui.bootstrap.typeahead

Estoy usando Angular JS – ui.bootstrap.typeahead:

Me gustaría hacer clic en un botón y enfocar un campo de entrada y mostrar automáticamente el menú desplegable de sugerencia de tipeo. Tengo una directiva que enfoca automáticamente el campo de entrada cuando se hace clic en el botón. ¿Cómo puedo mostrar el menú desplegable automáticamente para que el usuario pueda usar la flecha hacia abajo o hacer clic para seleccionar rápidamente un usuario?

He creado un Plunker con el archivo ui-bootstrap JS editable para retoques:

http://plnkr.co/edit/Z79LY0OYlwFc3wirjxol?p=preview

Este es mi guion completo:

         angular.module('plunker', ['ui.bootstrap']) .directive('focusMe', function($timeout, $parse) { return { //scope: true, // optionally create a child scope link: function(scope, element, attrs) { var model = $parse(attrs.focusMe); scope.$watch(model, function(value) { if(value === true) { $timeout(function() { element[0].focus(); }); } }); } }; }); function TypeaheadCtrl($scope, $http) { $scope.selected = undefined; $scope.states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming']; $scope.opened = false; $scope.open = function() { $scope.opened = true; } $scope.close = function() { $scope.opened = false; } }  

How can I open the typeahead dropdown automatically when button is pressed?

I have a directive that automatically focuses on the field but I can't seem to automatically show the typeahead. Even adding down arrow key click support would be great.




Model: {{selected | json}}

Como HarishR mencionó en un comentario, todavía no hay soporte integrado para esta función.

Pero solo quiero intentar piratear y aquí está el resultado: http://plnkr.co/edit/Qrnat8yTvISuM1qHHDlA?p=preview

Contiene muchos hacks para que funcione:

  1. Incluya jQuery para usar .trigger (), podría reemplazarse con JS nativo pero soy flojo.
  2. use ng-focus para llamar a .trigger (‘input’) para activar la ventana emergente typehead
  3. use ng-trim = “false” para deshabilitar el recorte automático de valores de la entrada
  4. una directiva personalizada de tipo vacío que interactúa con el controlador ngModel para aplicar la lógica secretEmptyKey para eludir la comprobación typeahead-min-length:

     .directive('emptyTypeahead', function () { return { require: 'ngModel', link: function (scope, element, attrs, modelCtrl) { // this parser run before typeahead's parser modelCtrl.$parsers.unshift(function (inputValue) { var value = (inputValue ? inputValue : secretEmptyKey); // replace empty string with secretEmptyKey to bypass typeahead-min-length check modelCtrl.$viewValue = value; // this $viewValue must match the inputValue pass to typehead directive return value; }); // this parser run after typeahead's parser modelCtrl.$parsers.push(function (inputValue) { return inputValue === secretEmptyKey ? '' : inputValue; // set the secretEmptyKey back to empty string }); } } }) 
  5. una función de comparador de filtro personalizado que siempre devuelve verdadero (mostrar todos los resultados) cuando un argumento es el secretoEmptyKey:

     $scope.stateComparator = function (state, viewValue) { return viewValue === secretEmptyKey || (''+state).toLowerCase().indexOf((''+viewValue).toLowerCase()) > -1; }; 
  6. eliminar el filtro de límite para mostrar todos los resultados

  7. establecer las propiedades max-height y css overflow para mostrar la barra de desplazamiento si el contenido es demasiado largo

¡Hecho!

Actualizado:

Agregué la directiva a github para facilitar las actualizaciones y el acceso. Ahora puede instalarlo como una dependencia a través de bower.

Publicación original:

Se me ocurrió un truco bastante limpio que no requiere ningún cambio en ui-bootstrap-tpls . La idea es usar $ setViewValue () para activar el menú emergente con una combinación de una función de filtro de comparación especial.

Para omitir el control minLength , $ setViewValue () tiene que establecerse en un valor mayor que 1, así que estoy usando una cadena de espacio. El rol de la función de comparación es tratar un espacio como una coincidencia con todos los elementos para que se muestren al hacer clic en una entrada vacía.

Creé una directiva simple:

 angular.module('app') .directive('typeaheadFocus', function () { return { require: 'ngModel', link: function (scope, element, attr, ngModel) { //trigger the popup on 'click' because 'focus' //is also triggered after the item selection element.bind('click', function () { var viewValue = ngModel.$viewValue; //restre to null value so that the typeahead can detect a change if (ngModel.$viewValue == ' ') { ngModel.$setViewValue(null); } //force trigger the popup ngModel.$setViewValue(' '); //set the actual value in case there was already a value in the input ngModel.$setViewValue(viewValue || ' '); }); //compare function that treats the empty space as a match scope.emptyOrMatch = function (actual, expected) { if (expected == ' ') { return true; } return actual.indexOf(expected) > -1; }; } }; }); 

Uso:

  

Obtuve una solución de trabajo cambiando algún código en ui-bootstrap-tpls-0.10.0.js. Por lo tanto, no hay diferencias en el marcado HTML de typeahead.

Puedes echar un vistazo aquí en http://plnkr.co/edit/LXHDpL?p=preview .

Para usar esta corrección, use ui-bootstrap-tpls-0.10.0.js desde Plunk. Para ver mis cambios, abra ui-bootstrap-tpls-0.10.0.js desde Plunk y busque ‘ahneo’.

  1. //minimal no of characters that needs to be entered before typeahead kicks-in // ahneo :: before //var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1; // ahneo :: after (changed minimal no of characters to 0 by default) var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 0; 2. // ahneo :: new (set input value to empty string if it contains " " string value) if (inputValue === ' ') { inputValue = ''; modelCtrl.$setViewValue(''); } 3. // ahneo :: before //if (inputValue && inputValue.length >= minSearch) { // ahneo :: after (add new condition to get matches for min search = 0) if (minSearch === 0 || inputValue && inputValue.length >= minSearch) { 4. // ahneo :: new (bind element to focus event to trigger modelCtrl.$parsers.unshift method) element.bind('focus', function (evt) { if (modelCtrl.$viewValue === '') { modelCtrl.$setViewValue(' '); } }); 

Espero que esto ayude

Ahora, como no tengo suficiente reputación para comentar, debo escribir una nueva respuesta para advertir a las personas sobre la respuesta de runTarm anterior. Esta es una solución viable, pero corre el riesgo de encontrarse con el siguiente error:

 Error: [$rootScope:inprog] $apply already in progress 

Esto parece deberse a que ng-focus es un evento sincronizado ( ver discusión aquí ). En cambio, uno puede usar el atributo ng-click-y este error no ocurre.

Además, he verificado que

 $element.triggerHandler('input'); 

funciona tan bien como el jQuery-trigger en la respuesta de RunTarm.

Parece que el soporte integrado para esta función viene en una próxima versión en forma de valor de soporte de atributo typeahead-min-length de 0.

Se implementa en este compromiso en la twig principal https://github.com/angular-ui/bootstrap/commit/d859f42cc022a5d8779f1c7b358486bbdd04ed57 , pero todavía no hay una versión y no está en la twig 0.14.x.

Con suerte, una nueva versión llegará rápidamente para que ya no haya necesidad de estas soluciones.

Quería algo así como la descripción del OP y la única solución que encontré fue crear una plantilla que combine las directivas desplegables y de escritura anticipada; tal vez el OP o alguien más lo encuentre útil:

 angular.module('app', ['ui.bootstrap']) .controller('AppCtrl', function($scope) { $scope.model; $scope.options = [{label:'Option 1'}, {label:'Option 2'}, {label:'Option 3'}]; $scope.onSelect = function($item, $model, $label) { $scope.model = angular.copy($item); } }); 
     

Me solucionaron este problema a través de una directiva. Cuando usa esta directiva, muestra la lista sin algún filtro, escribe su búsqueda para encontrar un elemento.

 angular.module('myapp') .directive('typeaheadLikeSelect', ['$parse',function($parse) { return { require: 'ngModel', link: function (scope, element, attr, ngModel){ var aux_modelValue, aux_viewValue, modelGetter = $parse(attr.ngModel), modelSetter = modelGetter.assign; var noViewValue = function(){ return ngModel.$$lastCommittedViewValue === undefined || !ngModel.$$lastCommittedViewValue.trim(); }; var forceEvent = function(){ ngModel.$setViewValue(); ngModel.$viewValue = ' '; ngModel.$setViewValue(' '); ngModel.$render(); scope.$apply(); element.val(element.val().trim()); }; element.on('mousedown', function(e){ e.stopPropagation(); forceEvent(); }); element.on('blur', function(e){ e.stopPropagation(); if(aux_modelValue){ modelSetter(scope, aux_modelValue); scope.$apply(); } }); scope.$watch(function () { return ngModel.$modelValue; }, function(newValue, oldValue){ if(newValue || (!newValue && !oldValue)) aux_modelValue = newValue; }); } }; }]); 

Dejo un código de vista para probar el código anterior.

  
No Results Found

typeahead-min-length = “0” hace el truco (estoy usando v0.4.0)

Quería que el tipo de entrada se abriera cada vez que mi elemento de entrada tuviera el foco. La solución de @yohairosen no funcionó para mí en la última versión de Angular Bootstrap (Versión: 1.0.3). Aquí está la solución que funcionó para mí. Implicaba invocar manualmente el analizador adjunto por ui-bootstrap-typeahead, que rellena las sugerencias:

 angular.module('app') .directive('typeaheadFocus', function () { return { require: 'ngModel', link: function (scope, element, attr, ngModel) { element.bind('click', function () { ngModel.$parsers[0](ngModel.$viewValue); }); } }; }; }); 

Lo que queremos es activar (‘entrada’) en el elemento de entrada cuando está enfocado.

La forma correcta de hacerlo en Angular es hacerlo en una directiva.

 angular.module('app') .directive('showList', function() { return { restrict: 'A', link: function(scope, iEle) { iEle.focus(function() { iEle.trigger('input'); }); } }; }); 

Utilice esta directiva en el elemento de entrada typeahead –

  

puedes lograr con este código

  $scope.change = function() { var e = document.getElementById("test"); var $e = angular.element(e); $e.triggerHandler('focus'); $e.triggerHandler('input'); } 

cambie la prueba a su ID de cabezal de tipo