AngularJS Live Example
by JakobJingleheimer
HTML
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.js"></script>
<div ng-controller="listController">
<form name="myForm" ng-submit="submit()">
<ul class="list-inline">
<li show-list="foos" input-id="foo" data-ng-model="data.foo" placeholder="foo…"></li>
<li show-list="bars" input-id="bar" data-ng-model="data.bar" placeholder="bar…"></li>
<li show-list="bazes" input-id="baz" data-ng-model="data.baz" placeholder="baz…"></li>
</ul>
<button type="submit">Send</button>
</form>
</div>
<script type="text/ng-template" id="directiveTmpl">
<input
autocomplete="off"
id="{{ inputId }}"
placeholder="{{ placeholder }}"
type="text"
ng-model="query" /><!--
--><button
class="btn-metal suggest-toggle"
type="button"
ng-click="showSuggestions = !showSuggestions"><!--
--><i class="link icon-chevron-down"></i><!--
--></button>
<ul class="suggestions" data-ng-show="showSuggestions">
<li
class="suggestion"
index="{{ $index }}"
value="{{ suggestion }}"
ng-class="{ 'active': suggestion === query || $index === selectedSuggestionIndex }"
ng-click="query = suggestion; selectedSuggestionIndex = $index"
ng-repeat="suggestion in suggestions | filter:query">{{ suggestion }}</li>
</ul>
</script>
CSS
.list-inline {
width: 100%;
}
.list-inline li {
display: inline-block;
}
.suggestions {
cursor: pointer;
display: block;
max-height: 10em;
overflow: scroll;
padding: 0.25em 0;
position: absolute;
width: 100%;
}
.suggestion {
padding: 0.25em 0.5em;
}
.suggestion:hover {
color: red;
}
.suggestion.active {
background: red;
}
JavaScript
angular.module('ShowList', [])
.directive('showList',function ShowListDirective() {
return {
priority: 10000,
templateUrl: 'directiveTmpl',
restrict: 'A',
scope: {
suggestions: '=showList',
inputId: '@',
query: '=ngModel'
},
link: function postLink(scope, element, attrs) {
scope.showSuggestions = false;
element.addClass('show-list');
var controlKeys = {
down: 40,
enter: 13,
esc: 27,
up: 38
},
formElm = element.closest('form');
if ( 'placeholder' in attrs ) {
scope.placeholder = attrs.placeholder;
}
function selectUpDown(direction) {
scope.selectedSuggestionIndex = angular.isDefined( scope.selectedSuggestionIndex ) ? scope.selectedSuggestionIndex : -1;
var adjustBy = direction === 'up' ? -1 : 1,
newIndex = scope.selectedSuggestionIndex + adjustBy;
scope.$apply(function selectUpDownApply() {
scope.selectedSuggestionIndex = newIndex > 0 ? newIndex : 0;
scope.showSuggestions = true;
});
}
formElm.on('submit', function(event) {
if ( scope.showSuggestions ) { // <- this value is WRONG
event.stopImmediatePropagation();
}
});
element.on('keyup', function showListKeyup(event) {
var key = event.keyCode || event.which;
switch( key ) {
case controlKeys.down:
selectUpDown('down');
break;
case controlKeys.enter:
if ( scope.showSuggestions ) {
scope.selectedSuggestion = scope.selectedSuggestion || element.find('.active').val();
if ( scope.selectedSuggestion ) {
event.stopPropagation();
scope.$apply(function acceptSuggestion() {
scope.query = scope.selectedSuggestion;
scope.showSuggestions = false;
});
}
}
break;
case controlKeys.esc:
event.preventDefault(); // so modals don't inadvertently close
scope.$apply(function hideList(){
scope.showSuggestions = false;
});
break;
case...