Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

feat(autocomplete): adds a new attribute option md-select-on-match #3825

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 53 additions & 23 deletions src/components/autocomplete/autocomplete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('<md-autocomplete>', function () {
}

describe('basic functionality', function () {
it('should update selected item and search text', inject(function ($timeout, $mdConstant, $rootElement) {
it('should update selected item and search text', inject(function ($timeout, $mdConstant) {
var scope = createScope();
var template = '\
<md-autocomplete\
Expand All @@ -47,8 +47,6 @@ describe('<md-autocomplete>', function () {
expect(scope.selectedItem).toBe(null);

element.scope().searchText = 'fo';
ctrl.keydown({});
element.scope().$apply();
$timeout.flush();

expect(scope.searchText).toBe('fo');
Expand All @@ -65,7 +63,6 @@ describe('<md-autocomplete>', function () {
preventDefault: angular.noop,
stopPropagation: angular.noop
});
scope.$apply();
$timeout.flush();

expect(scope.searchText).toBe('foo');
Expand Down Expand Up @@ -95,8 +92,6 @@ describe('<md-autocomplete>', function () {
expect(scope.selectedItem).toBe(null);

element.scope().searchText = 'fo';
ctrl.keydown({});
element.scope().$apply();
$timeout.flush();

expect(scope.searchText).toBe('fo');
Expand All @@ -113,7 +108,6 @@ describe('<md-autocomplete>', function () {
preventDefault: angular.noop,
stopPropagation: angular.noop
});
scope.$apply();
$timeout.flush();

expect(scope.searchText).toBe('foo');
Expand All @@ -136,7 +130,6 @@ describe('<md-autocomplete>', function () {
<span md-highlight-text="searchText">{{item.display}}</span>\
</md-autocomplete>';
var element = compile(template, scope);
var ctrl = element.controller('mdAutocomplete');
var ul = element.find('ul');

expect(scope.searchText).toBe('');
Expand All @@ -152,7 +145,7 @@ describe('<md-autocomplete>', function () {
});

describe('API access', function () {
it('should clear the selected item', inject(function ($timeout, $mdConstant) {
it('should clear the selected item', inject(function ($timeout) {
var scope = createScope();
var template = '\
<md-autocomplete\
Expand All @@ -167,12 +160,9 @@ describe('<md-autocomplete>', function () {
var ctrl = element.controller('mdAutocomplete');

element.scope().searchText = 'fo';
ctrl.keydown({});
element.scope().$apply();
$timeout.flush();

ctrl.select(0);
element.scope().$apply();
$timeout.flush();

expect(scope.searchText).toBe('foo');
Expand All @@ -187,10 +177,9 @@ describe('<md-autocomplete>', function () {
expect(scope.selectedItem).toBe(null);
}));

it('should notify selected item watchers', inject(function ($timeout, $mdConstant) {
var scope = createScope();
var scopeItemChanged = 1;
scope.itemChanged = jasmine.createSpy('itemChanged');
it('should notify selected item watchers', inject(function ($timeout) {
var scope = createScope();
scope.itemChanged = jasmine.createSpy('itemChanged');

var registeredWatcher = jasmine.createSpy('registeredWatcher');

Expand All @@ -210,12 +199,9 @@ describe('<md-autocomplete>', function () {
ctrl.registerSelectedItemWatcher(registeredWatcher);

element.scope().searchText = 'fo';
ctrl.keydown({});
element.scope().$apply();
$timeout.flush();

ctrl.select(0);
element.scope().$apply();
$timeout.flush();

expect(scope.itemChanged).toHaveBeenCalled();
Expand All @@ -237,7 +223,7 @@ describe('<md-autocomplete>', function () {
expect(scope.itemChanged.calls.mostRecent().args[ 0 ]).toBeNull();
expect(scope.selectedItem).toBeNull();
}));
it('should pass value to item watcher', inject(function ($timeout, $mdConstant) {
it('should pass value to item watcher', inject(function ($timeout) {
var scope = createScope();
var itemValue = null;
var template = '\
Expand All @@ -257,12 +243,9 @@ describe('<md-autocomplete>', function () {
var ctrl = element.controller('mdAutocomplete');

element.scope().searchText = 'fo';
ctrl.keydown({});
element.scope().$apply();
$timeout.flush();

ctrl.select(0);
element.scope().$apply();
$timeout.flush();

expect(itemValue).not.toBeNull();
Expand All @@ -272,4 +255,51 @@ describe('<md-autocomplete>', function () {
element.scope().$apply();
}));
});

describe('md-select-on-match', function () {
it('should select matching item on exact match when `md-select-on-match` is toggled', inject(function ($timeout) {
var scope = createScope();
var template = '\
<md-autocomplete\
md-select-on-match\
md-selected-item="selectedItem"\
md-search-text="searchText"\
md-items="item in match(searchText)"\
md-item-text="item.display"\
placeholder="placeholder">\
<span md-highlight-text="searchText">{{item.display}}</span>\
</md-autocomplete>';
var element = compile(template, scope);

expect(scope.searchText).toBe('');
expect(scope.selectedItem).toBe(null);

element.scope().searchText = 'foo';
$timeout.flush();

expect(scope.selectedItem).not.toBe(null);
expect(scope.selectedItem.display).toBe('foo');
}));
it('should not select matching item on exact match when `md-select-on-match` is NOT toggled', inject(function ($timeout) {
var scope = createScope();
var template = '\
<md-autocomplete\
md-selected-item="selectedItem"\
md-search-text="searchText"\
md-items="item in match(searchText)"\
md-item-text="item.display"\
placeholder="placeholder">\
<span md-highlight-text="searchText">{{item.display}}</span>\
</md-autocomplete>';
var element = compile(template, scope);

expect(scope.searchText).toBe('');
expect(scope.selectedItem).toBe(null);

element.scope().searchText = 'foo';
$timeout.flush();

expect(scope.selectedItem).toBe(null);
}));
});
});
15 changes: 15 additions & 0 deletions src/components/autocomplete/js/autocompleteController.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
if (searchText !== $scope.searchText) return; //-- just cache the results if old request
ctrl.matches = matches;
ctrl.hidden = shouldHide();
if ($scope.selectOnMatch) selectItemOnMatch();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should angular.noop this by default

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user only provides a flag, not the function itself. No need for angular.noop, unless I am misunderstanding your suggestion.

updateMessages();
positionDropdown();
}
Expand Down Expand Up @@ -593,4 +594,18 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
if (hasFocus) ctrl.hidden = shouldHide();
}

/**
* If there is only one matching item and the search text matches its display value exactly,
* automatically select that item. Note: This function is only called if the user uses the
* `md-select-on-match` flag.
*/
function selectItemOnMatch () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need function docs

var searchText = $scope.searchText,
matches = ctrl.matches,
item = matches[ 0 ];
if (matches.length === 1) getDisplayValue(item).then(function (displayValue) {
if (searchText == displayValue) select(0);
});
}

}
3 changes: 3 additions & 0 deletions src/components/autocomplete/js/autocompleteDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ angular
* FormController
* @param {number=} md-input-minlength The minimum length for the input's value for validation
* @param {number=} md-input-maxlength The maximum length for the input's value for validation
* @param {boolean=} md-select-on-match When set, autocomplete will automatically select exact
* the item if the search text is an exact match
*
* @usage
* ###Basic Example
Expand Down Expand Up @@ -128,6 +130,7 @@ function MdAutocomplete () {
itemText: '&mdItemText',
placeholder: '@placeholder',
noCache: '=?mdNoCache',
selectOnMatch: '=?mdSelectOnMatch',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the name

itemChange: '&?mdSelectedItemChange',
textChange: '&?mdSearchTextChange',
minLength: '=?mdMinLength',
Expand Down