Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

typeahead pull request #57

Closed
wants to merge 12 commits into from
5 changes: 5 additions & 0 deletions src/typeahead/docs/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class='container-fluid' ng-controller="typeaheadCtrl">

<input ng-model="query" typeahead-source="states" typeahead-items="10" typeahead-min-length="1">

</div>
10 changes: 10 additions & 0 deletions src/typeahead/docs/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function typeaheadCtrl($scope) {
$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'];

// Try to override updater method to provide your own functionality
// $scope.updater = function(item) {
// var test = $filter('filter')($scope.states, item);
// if (!test.length) { $scope.states.push(item); }
// return item;
// };
}
29 changes: 29 additions & 0 deletions src/typeahead/docs/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Typeahead Directive

typeahead is a AngularJS version of [Twitter Bootstrap typeahead plugin](http://twitter.github.com/bootstrap/javascript.html#typeahead)

this directive can be used to quickly creating elegant typeheads with any form text input.

## Usage

add class typeahead to your input to provide typeahead functionality.

### Options

Options can be passed via attributes in the input tag

items : number of items display in the dropdown
min-length : minimum character length needed before triggering suggestions

You can also modify some methods if default ones don't fit with your usage

scope.matcher : method which determines if the query matches an item. Return an array of items that match.
scope.updater : method which return the selected item. If you want to do more. (keep from the original bootstrap jquery component because it was a simple solution to let developers extend the component and keep it simple)

### Features

an AngularJS filter have been add to highlight the results.

## TODO

Order the results
9 changes: 9 additions & 0 deletions src/typeahead/test/typeaheadSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
describe('typeahead', function () {

var $element, $scope;

beforeEach(module('ui.bootstrap.typeahead'));

beforeEach(module('template/typeahead/typeahead.html'));

});
80 changes: 80 additions & 0 deletions src/typeahead/typeahead.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
angular
.module('ui.bootstrap.typeahead', [])
.directive('typeaheadSource', [ '$filter', '$http', '$templateCache', '$compile', function($filter, $http, $templateCache, $compile) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
var dScope = scope.$new(true),
items = attrs.typeaheadItems || 4,
minLength = attrs.typeaheadMinLength || 1,
source = scope.$eval(attrs.typeaheadSource);

dScope.updater = scope.updater || function(item) {
return item;
};

dScope.matcher = scope.matcher || function(item) {
return (item && item.length >= minLength) ? $filter('limitTo')($filter('filter')(source, item), items) : [];
};

dScope.setActive = function(index) {
dScope.active = index;
};

dScope.select = function(index) {
var value = (!index) ? dScope.query : dScope.matches[index];
dScope.query = dScope.selected = dScope.updater(value);
ctrl.$setViewValue(dScope.query);
ctrl.$render();
};

dScope.handleKeypress = function(key) {
switch(key) {
case 40 : dScope.active = (dScope.active + 1) % dScope.matches.length;
break;
case 38 :
dScope.active = (dScope.active ? dScope.active : dScope.matches.length) - 1;
break;
case 13 :
case 9 :
dScope.select(dScope.active);
break;
case 27 :
dScope.open = false;
break;
default :
break;
}
};

scope.$watch(attrs.ngModel, function (value){
dScope.query = value;
dScope.matches = dScope.matcher(value);
});

dScope.$watch('matches', function(current, previous) {
dScope.open = (dScope.matches && dScope.matches.length > 0 && dScope.selected!=dScope.query) ? true : false;
});

$http.get('template/typeahead/typeahead.html', {
cache: $templateCache
}).success(function(tplContent){
element.after($compile(tplContent)(dScope));

element.bind('keyup', function(evt) {
scope.$apply(function() {
evt.preventDefault();
dScope.active = dScope.active || 0;
dScope.handleKeypress.call(scope, evt.which);
});
});
});
}
};
}])
.filter('highlighter', function() {
return function(text, expression) {
return (expression) ? text.replace(new RegExp(expression, 'gi'), '<strong>$&</strong>') : text;
};
});
7 changes: 7 additions & 0 deletions template/typeahead/typeahead.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div class="dropdown" ng-class="{open: open}">
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
<li ng-repeat="item in matches" ng-class="{active: active == $index}" ng-mouseenter="setActive($index)">
<a href ng-click="select($index)" ng-bind-html-unsafe="item | highlighter:query" ng-click="select($index)"></a>
</li>
</ul>
</div>