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

Commit 1814c12

Browse files
devversionThomasBurleson
authored andcommitted
fix(chips): detect cursor position for selecting previous chip.
* Currently we check the truthyness of the chipBuffer, to confirm that the user is at the beginning of the chip input. Once he is at the beginning, we select and focus the previous chip, so the user can keep deleting the chips. * Checking for truthyness is not working, because Angular is trimming all ngModel values for the autocomplete and default chip input. This caused issues, where users can't delete their spaces in the input anymore. Checking the cursor position is more appropriated here, and works without affecting the autocomplete. This allows the autocomplete to work independently without any changes with the `md-chips` component. Fixes #8750 Closes #8791
1 parent 75a86df commit 1814c12

File tree

3 files changed

+84
-5
lines changed

3 files changed

+84
-5
lines changed

src/components/chips/chips.spec.js

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,15 +355,18 @@ describe('<md-chips>', function() {
355355
expect(scope.items).toEqual(['Apple', 'Banana', 'Orange', 'Test']);
356356
}));
357357

358-
it('should not trim the input text of the input', inject(function($mdConstant) {
358+
it('should properly cancel the backspace event to select the chip before', inject(function($mdConstant) {
359359
var element = buildChips(BASIC_CHIP_TEMPLATE);
360360
var ctrl = element.controller('mdChips');
361361
var input = element.find('input');
362362

363363
input.val(' ');
364364
input.triggerHandler('input');
365365

366-
expect(ctrl.chipBuffer).toBeTruthy();
366+
// Since the `md-chips` component is testing the backspace select previous chip functionality by
367+
// checking the current caret / cursor position, we have to set the cursor to the end of the current
368+
// value.
369+
input[0].selectionStart = input[0].selectionEnd = input[0].value.length;
367370

368371
var enterEvent = {
369372
type: 'keydown',
@@ -379,6 +382,11 @@ describe('<md-chips>', function() {
379382
input.val('');
380383
input.triggerHandler('input');
381384

385+
// Since the `md-chips` component is testing the backspace select previous chip functionality by
386+
// checking the current caret / cursor position, we have to set the cursor to the end of the current
387+
// value.
388+
input[0].selectionStart = input[0].selectionEnd = input[0].value.length;
389+
382390
input.triggerHandler(enterEvent);
383391

384392
expect(enterEvent.preventDefault).toHaveBeenCalledTimes(1);
@@ -690,6 +698,56 @@ describe('<md-chips>', function() {
690698
expect(element.find('input').val()).toBe('');
691699
}));
692700

701+
it('should properly cancel the backspace event to select the chip before', inject(function($mdConstant) {
702+
setupScopeForAutocomplete();
703+
var element = buildChips(AUTOCOMPLETE_CHIPS_TEMPLATE);
704+
705+
// The embedded `md-autocomplete` needs a timeout flush for it's initialization.
706+
$timeout.flush();
707+
$timeout.flush();
708+
scope.$apply();
709+
710+
var input = angular.element(element[0].querySelector('md-autocomplete input'));
711+
712+
713+
input.val(' ');
714+
input.triggerHandler('input');
715+
716+
expect(input.controller('ngModel').$modelValue).toBe('');
717+
// Since the `md-chips` component is testing the backspace select previous chip functionality by
718+
// checking the current caret / cursor position, we have to set the cursor to the end of the current
719+
// value.
720+
input[0].selectionStart = input[0].selectionEnd = input[0].value.length;
721+
722+
var backspaceEvent = {
723+
type: 'keydown',
724+
keyCode: $mdConstant.KEY_CODE.BACKSPACE,
725+
which: $mdConstant.KEY_CODE.BACKSPACE,
726+
preventDefault: jasmine.createSpy('preventDefault')
727+
};
728+
729+
input.triggerHandler(backspaceEvent);
730+
731+
// We have to trigger a digest, because the event listeners for the chips component will be called
732+
// with an async digest evaluation.
733+
scope.$digest();
734+
735+
expect(backspaceEvent.preventDefault).not.toHaveBeenCalled();
736+
737+
input.val('');
738+
input.triggerHandler('input');
739+
740+
// Since the `md-chips` component is testing the backspace select previous chip functionality by
741+
// checking the current caret / cursor position, we have to set the cursor to the end of the current
742+
// value.
743+
input[0].selectionStart = input[0].selectionEnd = input[0].value.length;
744+
745+
input.triggerHandler(backspaceEvent);
746+
scope.$digest();
747+
748+
expect(backspaceEvent.preventDefault).toHaveBeenCalledTimes(1);
749+
}));
750+
693751
it('simultaneously allows selecting an existing chip AND adding a new one', inject(function($mdConstant) {
694752
// Setup our scope and function
695753
setupScopeForAutocomplete();

src/components/chips/js/chipsController.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,19 @@ MdChipsCtrl.prototype.inputKeydown = function(event) {
114114
}
115115

116116
if (event.keyCode === this.$mdConstant.KEY_CODE.BACKSPACE) {
117-
if (chipBuffer) return;
117+
// Only select and focus the previous chip, if the current caret position of the
118+
// input element is at the beginning.
119+
if (getCursorPosition(event.target) !== 0) {
120+
return;
121+
}
122+
118123
event.preventDefault();
119124
event.stopPropagation();
120-
if (this.items.length) this.selectAndFocusChipSafe(this.items.length - 1);
125+
126+
if (this.items.length) {
127+
this.selectAndFocusChipSafe(this.items.length - 1);
128+
}
129+
121130
return;
122131
}
123132

@@ -139,6 +148,19 @@ MdChipsCtrl.prototype.inputKeydown = function(event) {
139148
}
140149
};
141150

151+
/**
152+
* Returns the cursor position of the specified input element.
153+
* If no selection is present it returns -1.
154+
* @param element HTMLInputElement
155+
* @returns {Number} Cursor Position of the input.
156+
*/
157+
function getCursorPosition(element) {
158+
if (element.selectionStart === element.selectionEnd) {
159+
return element.selectionStart;
160+
}
161+
return -1;
162+
}
163+
142164

143165
/**
144166
* Updates the content of the chip at given index

src/components/chips/js/chipsDirective.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@
175175
ng-model="$mdChipsCtrl.chipBuffer"\
176176
ng-focus="$mdChipsCtrl.onInputFocus()"\
177177
ng-blur="$mdChipsCtrl.onInputBlur()"\
178-
ng-trim="false"\
179178
ng-keydown="$mdChipsCtrl.inputKeydown($event)">';
180179

181180
var CHIP_DEFAULT_TEMPLATE = '\

0 commit comments

Comments
 (0)