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

feat(autocomplete): option to toggle the clear button #9892

Merged
merged 1 commit into from
Oct 27, 2016
Merged
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
32 changes: 22 additions & 10 deletions src/components/autocomplete/autocomplete.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// The default item height is also specified in the JavaScript.
$md-autocomplete-item-height: 48px !default;
$md-autocomplete-clear-size: 30px !default;
$md-autocomplete-input-offset: 20px !default;

@keyframes md-autocomplete-list-out {
0% {
Expand Down Expand Up @@ -55,14 +57,24 @@ md-autocomplete {
md-autocomplete-wrap {
height: auto;
}
button {
position: absolute;
top: auto;
bottom: 0;
right: 0;
width: 30px;
height: 30px;

.md-show-clear-button {

button {
display: block;
position: absolute;
right: 0;
top: $md-autocomplete-input-offset;
width: $md-autocomplete-clear-size;
height: $md-autocomplete-clear-size;
}

input {
// Add padding to the end of the input to avoid overlapping with the clear button.
@include rtl-prop(padding-right, padding-left, $md-autocomplete-clear-size, 0);
}
}

}
md-autocomplete-wrap {

Expand Down Expand Up @@ -130,12 +142,12 @@ md-autocomplete {
line-height: 40px;
height: 40px;
}
button {
.md-show-clear-button button {
position: relative;
line-height: 20px;
text-align: center;
width: 30px;
height: 30px;
width: $md-autocomplete-clear-size;
height: $md-autocomplete-clear-size;
cursor: pointer;
border: none;
border-radius: 50%;
Expand Down
74 changes: 74 additions & 0 deletions src/components/autocomplete/autocomplete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,80 @@ describe('<md-autocomplete>', function() {

});

describe('clear button', function() {

it('should show the clear button for inset autocomplete', function() {
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);
var ctrl = element.controller('mdAutocomplete');
var wrapEl = element.find('md-autocomplete-wrap');

expect(ctrl.scope.clearButton).toBe(true);
expect(wrapEl).toHaveClass('md-show-clear-button');
});

it('should not show the clear button for floating label autocomplete', function() {
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" ' +
'md-floating-label="Label"> ' +
'<span md-highlight-text="searchText">{{item.display}}</span>' +
'</md-autocomplete>';

var element = compile(template, scope);
var ctrl = element.controller('mdAutocomplete');
var wrapEl = element.find('md-autocomplete-wrap');

expect(ctrl.scope.clearButton).toBe(false);
expect(wrapEl).not.toHaveClass('md-show-clear-button');
});

it('should allow developers to toggle the clear button', function() {

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" ' +
'md-floating-label="Label" ' +
'md-clear-button="showButton">' +
'<span md-highlight-text="searchText">{{item.display}}</span>' +
'</md-autocomplete>';

var element = compile(template, scope);
var ctrl = element.controller('mdAutocomplete');
var wrapEl = element.find('md-autocomplete-wrap');

expect(ctrl.scope.clearButton).toBeFalsy();
expect(wrapEl).not.toHaveClass('md-show-clear-button');

scope.$apply('showButton = true');

expect(ctrl.scope.clearButton).toBe(true);
expect(wrapEl).toHaveClass('md-show-clear-button');
});

});

describe('xss prevention', function() {

it('should not allow html to slip through', inject(function($timeout, $material) {
Expand Down
8 changes: 7 additions & 1 deletion src/components/autocomplete/js/autocompleteController.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,13 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
* Initialize the controller, setup watchers, gather elements
*/
function init () {
$mdUtil.initOptionalProperties($scope, $attrs, { searchText: '', selectedItem: null });

$mdUtil.initOptionalProperties($scope, $attrs, {
searchText: '',
selectedItem: null,
clearButton: false
});

$mdTheming($element);
configureWatchers();
$mdUtil.nextTick(function () {
Expand Down
48 changes: 36 additions & 12 deletions src/components/autocomplete/js/autocompleteDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ angular
* make suggestions
* @param {number=} md-delay Specifies the amount of time (in milliseconds) to wait before looking
* for results
* @param {boolean=} md-clear-button Whether the clear button for the autocomplete input should show up or not.
* @param {boolean=} md-autofocus If true, the autocomplete will be automatically focused when a `$mdDialog`,
* `$mdBottomsheet` or `$mdSidenav`, which contains the autocomplete, is opening. <br/><br/>
* Also the autocomplete will immediately focus the input element.
Expand Down Expand Up @@ -151,6 +152,17 @@ angular
* In this example, our code utilizes `md-item-template` and `md-not-found` to specify the
* different parts that make up our component.
*
* ### Clear button for the input
* By default, for floating label autocomplete's the clear button is not showing up
* ([See specs](https://material.google.com/components/text-fields.html#text-fields-auto-complete-text-field))
*
* Nevertheless, developers are able to explicitly toggle the clear button for all types of autocomplete's.
*
* <hljs lang="html">
* <md-autocomplete ... md-clear-button="true"></md-autocomplete>
* <md-autocomplete ... md-clear-button="false"></md-autocomplete>
* </hljs>
*
* ### Example with validation
* <hljs lang="html">
* <form name="autocompleteForm">
Expand Down Expand Up @@ -232,7 +244,8 @@ function MdAutocomplete ($$mdSvgRegistry) {
inputId: '@?mdInputId',
escapeOptions: '@?mdEscapeOptions',
dropdownItems: '=?mdDropdownItems',
dropdownPosition: '@?mdDropdownPosition'
dropdownPosition: '@?mdDropdownPosition',
clearButton: '=?mdClearButton'
},
compile: function(tElement, tAttrs) {
var attributes = ['md-select-on-focus', 'md-no-asterisk', 'ng-trim', 'ng-pattern'];
Expand All @@ -250,6 +263,11 @@ function MdAutocomplete ($$mdSvgRegistry) {
// Retrieve the state of using a md-not-found template by using our attribute, which will
// be added to the element in the template function.
ctrl.hasNotFound = !!element.attr('md-has-not-found');

// By default the inset autocomplete should show the clear button when not explicitly overwritten.
if (!angular.isDefined(attrs.mdClearButton) && !scope.floatingLabel) {
scope.clearButton = true;
}
}
},
template: function (element, attr) {
Expand All @@ -269,8 +287,11 @@ function MdAutocomplete ($$mdSvgRegistry) {

return '\
<md-autocomplete-wrap\
ng-class="{ \'md-whiteframe-z1\': !floatingLabel, \'md-menu-showing\': !$mdAutocompleteCtrl.hidden }">\
ng-class="{ \'md-whiteframe-z1\': !floatingLabel, \
\'md-menu-showing\': !$mdAutocompleteCtrl.hidden, \
\'md-show-clear-button\': !!clearButton }">\
' + getInputElement() + '\
' + getClearButton() + '\
<md-progress-linear\
class="' + (attr.mdFloatingLabel ? 'md-inline' : '') + '"\
ng-if="$mdAutocompleteCtrl.loadingIsVisible()"\
Expand Down Expand Up @@ -366,18 +387,21 @@ function MdAutocomplete ($$mdSvgRegistry) {
role="combobox"\
aria-haspopup="true"\
aria-activedescendant=""\
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>\
<button\
type="button"\
tabindex="-1"\
ng-if="$mdAutocompleteCtrl.scope.searchText && !$mdAutocompleteCtrl.isDisabled"\
ng-click="$mdAutocompleteCtrl.clear($event)">\
<md-icon md-svg-src="' + $$mdSvgRegistry.mdClose + '"></md-icon>\
<span class="md-visually-hidden">Clear</span>\
</button>\
';
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>';
}
}

function getClearButton() {
return '' +
'<button ' +
'type="button" ' +
'aria-label="Clear Input" ' +
'tabindex="-1" ' +
'ng-if="clearButton && $mdAutocompleteCtrl.scope.searchText && !$mdAutocompleteCtrl.isDisabled" ' +
'ng-click="$mdAutocompleteCtrl.clear($event)">' +
'<md-icon md-svg-src="' + $$mdSvgRegistry.mdClose + '"></md-icon>' +
'</button>';
}
}
};
}