Skip to content

Commit

Permalink
fix(mdChips): Backspace key and custom input focus/blur.
Browse files Browse the repository at this point in the history
 * Fix backspace key in Firefox to not change browser history/url

   In Firefox, the backspace key would also modify the browser's
   history/url.

 * Fix focus/blur on chips with custom input:

   Chips with a custom input did not properly update it's class
   list when the inner input was focused/blurred.

Fixes angular#3562. Fixes angular#3960. Fixes angular#2607. Closes angular#4359.
  • Loading branch information
topherfangio authored and kennethcachia committed Sep 23, 2015
1 parent b5919ae commit 1974b99
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 4 deletions.
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

0 comments on commit 1974b99

Please sign in to comment.