проблема со стрелкой вверх/вниз с управлением typeahead (angular bootstrap UI)

проверить это PLNKR я реализовал typeahead контроль, По умолчанию в типе ahead control они не устанавливают max-height или height в список, но в соответствии с требованием я должен зафиксировать высоту списка до 110px. Итак, когда у нас будет более длинный список за раз, будут показаны только 4 данные, а остальные можно увидеть, прокрутив вниз. Прокрутка работает, когда пользователь нажимает стрелки прокрутки вверх/вниз, но он не работает с клавишами клавиатуры вверх/вниз.

проблема описано в шагах:-

  1. введите что-нибудь i.e " a " для получения данных в typeahead (список будет заполнен)
  2. нажмите клавишу со стрелкой вниз (фокус будет на элемент списка)
  3. нажмите клавишу со стрелкой вниз 4-5 раз, чтобы идти дальше вниз (когда мы траверс вниз к списку, прокрутка не перемещается.)
  4. он всегда показывает верхние 4 элемента в списке. Идеальное поведение-это сдвиг.

пользователь может прокручивать, нажав на прокрутку вручную, но с помощью клавиши со стрелкой это не прокрутка.

Type "a" and traverse down to list with down-arrow key scrolling is not working.

HTML-код

<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
 <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.js"></script>
 <script src="example.js"></script>
 <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
 <link href="style.css" rel="stylesheet">
</head>
<body>
<div class='container-fluid' ng-controller="TypeaheadCtrl">
  <h4>Static arrays</h4>
  <pre>Model: {{selected | json}}</pre>
  <input type="text" ng-model="selected" typeahead="state for state in states | filter:$viewValue | limitTo:8" class="form-control">
 </div>
</body>
</html>

в CSS

.dropdown-menu{
 height:110px;
 overflow:auto;
}

javascript datalist

$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'];

4 ответов


вот рабочий поршень

в этом у меня есть переопределение ui-bootstrap typeahead, как предложено в ответ.

Ниже приведены изменения, которые мне нужно сделать, чтобы он работал:

добавлена следующая строка в typeaheadMatch директива (строка-335 пользовательского интерфейса.загрузчик.машинописный.файл JS в plunker)

element[0].focus();

добавил shouldFocus директива (строка - 314 -350)

.directive('shouldFocus', function(){
  return {
   restrict: 'A',
   link: function(scope,element,attrs){
     scope.$watch(attrs.shouldFocus,function(newVal,oldVal){
       element[0].scrollIntoView(false);
     });
   }
 };
})

и, наконец, добавил директиву li (линия - 372)

should-focus=\"isActive($index)\"

@user1690588 ответ Отлично работает. Проблема только в том, что когда последний элемент в списке активен и вы нажимаете клавишу вниз. первый элемент scrollToView не работает. Я добавил проверку, чтобы убедиться, что newVal верно, что, кажется, исправить это.

  if (newVal) { 
    element[0].scrollIntoView(false);
  }

http://plnkr.co/edit/05yoHSlhvX740tgiRRXm


я использовал другой подход для решения этой проблемы, поскольку ни одно из решений здесь не удовлетворяет. В основном:

  • достижение последнего элемента и нажатие клавиши вниз должно привести первый элемент в поле зрения
  • наведение курсора на элементы не должно сделать всплывающее окно Typeahead прокруткой
  • использование колеса прокрутки мыши не должно вызывать странное поведение во всплывающем окне Typeahead
  • исправить следует избегать изменения начальной загрузки AngularUI источники

расширение директив начальной загрузки AngularUI и прослушивание только определенных ключевых событий, похоже, обеспечивают более чистое обходное решение, как вы можете видеть здесь: http://plnkr.co/edit/QuZw7j?p=preview

angular.module('ui.bootstrap.demo')
    .directive('typeahead', function () {
        return {
            restrict: 'A',
            priority: 1000, // Let's ensure AngularUI Typeahead directive gets initialized first!
            link: function (scope, element, attrs) {
                // Bind keyboard events: arrows up(38) / down(40)
                element.bind('keydown', function (evt) {
                    if (evt.which === 38 || evt.which === 40) {
                        // Broadcast a possible change of the currently active option:
                        // (Note that we could pass the activeIdx value as event data but AngularUI Typeahead directive
                        //  has its own local scope which makes it hard to retrieve, see:
                        //  https://github.com/angular-ui/bootstrap/blob/7b7039b4d94074987fa405ee1174cfe7f561320e/src/typeahead/typeahead.js#L104)
                        scope.$broadcast('TypeaheadActiveChanged');
                    }
                });
            }
        };
    }).directive('typeaheadPopup', function () {
        return {
            restrict: 'EA',
            link: function (scope, element, attrs) {
                var unregisterFn = scope.$on('TypeaheadActiveChanged', function (event, data) {
                    if(scope.activeIdx !== -1) {
                        // Retrieve active Typeahead option:
                        var option = element.find('#' + attrs.id + '-option-' + scope.activeIdx);
                        if(option.length) {
                            // Make sure option is visible:
                            option[0].scrollIntoView(false);
                        }
                    }
                });

                // Ensure listener is unregistered when $destroy event is fired:
                scope.$on('$destroy', unregisterFn);
             }
        };
    });

протестировано с AngularJS 1.4.5 & AngularUI Bootstrap 0.13.4, но это должно работать с другими последними версиями.

[обратите внимание, что мне пришлось вручную включить jQuery, как предварительно загруженный Plunker (jQuery v1.8.3) не удастся получить текущая активная опция.]


принятое решение не будет выполнено, если главное окно уже прокручивается. @user1690588 был на правильном пути.

редактировать ui-bootstrap-tpls-0.13.3.js и поместите это вокруг строки 5205 выше .фильтр('typeaheadHighlight') по крайней мере, пока команда AngularUI не решит исправить это. А также применение другого изменения к шаблону, на который ссылается принятое решение.

.directive('shouldFocus', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            scope.$watch(attrs.shouldFocus, function (newVal, oldVal) {
                if (newVal && element.prop("class").indexOf("active")) {
                    var par = element.parent("ul");
                    var scrollingTo = element.offset().top - par.offset().top + par.scrollTop();
                    // uncomment below section if you want the selected content to be 
                    // viewed at half the box height
                    // scrollingTo = scrollingTo - (par.height() / 2); 
                    par.scrollTop(scrollingTo);
                }
            });
        }
    }
})

также, если вы хотите избавиться от артефакта мыши, где это начинает прокрутку вверх, пока не попадет в первую запись или вниз, пока не попадет в последнюю запись, а затем удалите из шаблона ng-mouseenter