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

fix(mdChips): Backspace key and custom input focus/blur. #4359

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
70 changes: 70 additions & 0 deletions src/components/chips/chips.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,58 @@ describe('<md-chips>', function() {
expect(scope.appendChip).toHaveBeenCalled();
expect(scope.appendChip.calls.mostRecent().args[0]).toBe('Apple');
});

it('should prevent the default when backspace is pressed', inject(function($mdConstant) {
var element = buildChips(BASIC_CHIP_TEMPLATE);
var ctrl = element.controller('mdChips');

var backspaceEvent = {
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.BACKSPACE,
which: $mdConstant.KEY_CODE.BACKSPACE,
preventDefault: jasmine.createSpy('preventDefault')
};

element.find('input').triggerHandler(backspaceEvent);

expect(backspaceEvent.preventDefault).toHaveBeenCalled();
}));

describe('with input text', function() {

it('should prevent the default when enter is pressed', inject(function($mdConstant) {
var element = buildChips(BASIC_CHIP_TEMPLATE);
var ctrl = element.controller('mdChips');

var enterEvent = {
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.ENTER,
which: $mdConstant.KEY_CODE.ENTER,
preventDefault: jasmine.createSpy('preventDefault')
};

ctrl.chipBuffer = 'Test';
element.find('input').triggerHandler(enterEvent);

expect(enterEvent.preventDefault).toHaveBeenCalled();
}));
});

it('focuses/blurs the component when focusing/blurring the input', inject(function() {
var element = buildChips(BASIC_CHIP_TEMPLATE);
var ctrl = element.controller('mdChips');

// Focus the input and check
element.find('input').triggerHandler('focus');
expect(ctrl.inputHasFocus).toBe(true);
expect(element.find('md-chips-wrap').hasClass('md-focused')).toBe(true);

// Blur the input and check
element.find('input').triggerHandler('blur');
expect(ctrl.inputHasFocus).toBe(false);
expect(element.find('md-chips-wrap').hasClass('md-focused')).toBe(false);
}));

});

describe('custom inputs', function() {
Expand Down Expand Up @@ -264,6 +316,24 @@ describe('<md-chips>', function() {
<input type="text">\
</md-chips>';

it('focuses/blurs the component when focusing/blurring the input', inject(function($timeout) {
var element = buildChips(INPUT_TEMPLATE);
var ctrl = element.controller('mdChips');
$timeout.flush();

// Focus the input and check
element.find('input').triggerHandler('focus');
$timeout.flush();
expect(ctrl.inputHasFocus).toBe(true);
expect(element.find('md-chips-wrap').hasClass('md-focused')).toBe(true);

// Blur the input and check
element.find('input').triggerHandler('blur');
$timeout.flush();
expect(ctrl.inputHasFocus).toBe(false);
expect(element.find('md-chips-wrap').hasClass('md-focused')).toBe(false);
}));

describe('using ngModel', function() {
it('should add the ngModelCtrl.$viewValue when <enter> is pressed',
inject(function($timeout) {
Expand Down
16 changes: 12 additions & 4 deletions src/components/chips/js/chipsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ function MdChipsCtrl ($scope, $mdConstant, $log, $element, $timeout) {
*/
MdChipsCtrl.prototype.inputKeydown = function(event) {
var chipBuffer = this.getChipBuffer();

switch (event.keyCode) {
case this.$mdConstant.KEY_CODE.ENTER:
if ((this.hasAutocomplete && this.requireMatch) || !chipBuffer) break;
Expand All @@ -101,6 +102,7 @@ MdChipsCtrl.prototype.inputKeydown = function(event) {
break;
case this.$mdConstant.KEY_CODE.BACKSPACE:
if (chipBuffer) break;
event.preventDefault();
event.stopPropagation();
if (this.items.length) this.selectAndFocusChipSafe(this.items.length - 1);
break;
Expand Down Expand Up @@ -373,14 +375,20 @@ MdChipsCtrl.prototype.configureUserInput = function(inputElement) {
this.userInputNgModelCtrl = ngModelCtrl;
}

// Bind to keydown and focus events of input
var scope = this.$scope;
var ctrl = this;

// Run all of the events using evalAsync because a focus may fire a blur in the same digest loop
var scopeApplyFn = function(event, fn) {
scope.$evalAsync(angular.bind(ctrl, fn, event));
};

// Bind to keydown and focus events of input
inputElement
.attr({ tabindex: 0 })
.on('keydown', function(event) { scope.$apply( angular.bind(ctrl, function() { ctrl.inputKeydown(event); })) })
.on('focus', angular.bind(ctrl, ctrl.onInputFocus))
.on('blur', angular.bind(ctrl, ctrl.onInputBlur));
.on('keydown', function(event) { scopeApplyFn(event, ctrl.inputKeydown) })
.on('focus', function(event) { scopeApplyFn(event, ctrl.onInputFocus) })
.on('blur', function(event) { scopeApplyFn(event, ctrl.onInputBlur) })
};

MdChipsCtrl.prototype.configureAutocomplete = function(ctrl) {
Expand Down