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

Commit bbc6c07

Browse files
devversionjelbourn
authored andcommitted
feat(chips): md-add-on-blur functionality (#9095)
* Allows developers to convert the remaining input text into a new chip on input blur. This is useful for example, when having chips for email addresses. Closes #3364.
1 parent 57f2afd commit bbc6c07

File tree

3 files changed

+139
-7
lines changed

3 files changed

+139
-7
lines changed

src/components/chips/chips.spec.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,112 @@ describe('<md-chips>', function() {
202202
expect(scope.selectChip).toHaveBeenCalled();
203203
expect(scope.selectChip.calls.mostRecent().args[0]).toBe('Grape');
204204
});
205+
206+
describe('when adding chips on blur', function() {
207+
208+
it('should append a new chip for the remaining text', function() {
209+
var element = buildChips(
210+
'<md-chips ng-model="items" md-add-on-blur="true">' +
211+
'</md-chips>'
212+
);
213+
214+
var input = element.find('input');
215+
216+
expect(scope.items.length).toBe(3);
217+
218+
input.val('Remaining');
219+
input.triggerHandler('change');
220+
221+
// Trigger a blur event, to check if the text was converted properly.
222+
input.triggerHandler('blur');
223+
224+
expect(scope.items.length).toBe(4);
225+
});
226+
227+
it('should not append a new chip if the limit has reached', function() {
228+
var element = buildChips(
229+
'<md-chips ng-model="items" md-add-on-blur="true" md-max-chips="3">' +
230+
'</md-chips>'
231+
);
232+
233+
var input = element.find('input');
234+
235+
expect(scope.items.length).toBe(3);
236+
237+
input.val('Remaining');
238+
input.triggerHandler('change');
239+
240+
// Trigger a blur event, to check if the text was converted properly.
241+
input.triggerHandler('blur');
242+
243+
expect(scope.items.length).toBe(3);
244+
});
245+
246+
it('should not append a new chip when the chips model is invalid', function() {
247+
var element = buildChips(
248+
'<md-chips ng-model="items" md-add-on-blur="true">'
249+
);
250+
251+
var input = element.find('input');
252+
var ngModelCtrl = element.controller('ngModel');
253+
254+
expect(scope.items.length).toBe(3);
255+
256+
input.val('Remaining');
257+
258+
input.triggerHandler('change');
259+
input.triggerHandler('blur');
260+
$timeout.flush();
261+
262+
expect(scope.items.length).toBe(4);
263+
264+
input.val('Second');
265+
266+
ngModelCtrl.$setValidity('is-valid', false);
267+
268+
input.triggerHandler('change');
269+
input.triggerHandler('blur');
270+
271+
expect(scope.items.length).toBe(4);
272+
});
273+
274+
it('should not append a new chip when the custom input model is invalid', function() {
275+
var element = buildChips(
276+
'<md-chips ng-model="items" md-add-on-blur="true">' +
277+
'<input ng-model="subModel" ng-maxlength="2">' +
278+
'</md-chips>'
279+
);
280+
281+
$timeout.flush();
282+
283+
var input = element.find('input');
284+
285+
expect(scope.items.length).toBe(3);
286+
287+
input.val('EN');
288+
289+
input.triggerHandler('change');
290+
input.triggerHandler('blur');
291+
292+
// Flush the timeout after each blur, because custom inputs have listeners running
293+
// in an Angular digest.
294+
$timeout.flush();
295+
296+
expect(scope.items.length).toBe(4);
297+
298+
input.val('Another');
299+
300+
input.triggerHandler('change');
301+
input.triggerHandler('blur');
302+
303+
// Flush the timeout after each blur, because custom inputs have listeners running
304+
// in an Angular digest.
305+
$timeout.flush();
306+
307+
expect(scope.items.length).toBe(4);
308+
});
309+
310+
});
205311

206312
describe('when removable', function() {
207313

src/components/chips/js/chipsController.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ angular
88
* the models of various input components.
99
*
1010
* @param $scope
11+
* @param $attrs
1112
* @param $mdConstant
1213
* @param $log
1314
* @param $element
15+
* @param $timeout
1416
* @param $mdUtil
1517
* @constructor
1618
*/
17-
function MdChipsCtrl ($scope, $mdConstant, $log, $element, $timeout, $mdUtil) {
19+
function MdChipsCtrl ($scope, $attrs, $mdConstant, $log, $element, $timeout, $mdUtil) {
1820
/** @type {$timeout} **/
1921
this.$timeout = $timeout;
2022

@@ -52,7 +54,10 @@ function MdChipsCtrl ($scope, $mdConstant, $log, $element, $timeout, $mdUtil) {
5254
this.hasAutocomplete = false;
5355

5456
/** @type {string} */
55-
this.enableChipEdit = $mdUtil.parseAttributeBoolean(this.mdEnableChipEdit);
57+
this.enableChipEdit = $mdUtil.parseAttributeBoolean($attrs.mdEnableChipEdit);
58+
59+
/** @type {string} */
60+
this.addOnBlur = $mdUtil.parseAttributeBoolean($attrs.mdAddOnBlur);
5661

5762
/**
5863
* Hidden hint text for how to delete a chip. Used to give context to screen readers.
@@ -512,6 +517,23 @@ MdChipsCtrl.prototype.onInputFocus = function () {
512517

513518
MdChipsCtrl.prototype.onInputBlur = function () {
514519
this.inputHasFocus = false;
520+
521+
var chipBuffer = this.getChipBuffer().trim();
522+
523+
// Update the custom chip validators.
524+
this.validateModel();
525+
526+
var isModelValid = this.ngModelCtrl.$valid;
527+
528+
if (this.userInputNgModelCtrl) {
529+
isModelValid &= this.userInputNgModelCtrl.$valid;
530+
}
531+
532+
// Only append the chip and reset the chip buffer if the chips and input ngModel is valid.
533+
if (this.addOnBlur && chipBuffer && isModelValid) {
534+
this.appendChip(chipBuffer);
535+
this.resetChipBuffer();
536+
}
515537
};
516538

517539
/**

src/components/chips/js/chipsDirective.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@
9898
* @param {number=} md-max-chips The maximum number of chips allowed to add through user input.
9999
* <br/><br/>The validation property `md-max-chips` can be used when the max chips
100100
* amount is reached.
101+
* @param {boolean=} md-add-on-blur When set to true, remaining text inside of the input will
102+
* be converted into a new chip on blur.
101103
* @param {expression} md-transform-chip An expression of form `myFunction($chip)` that when called
102104
* expects one of the following return values:
103105
* - an object representing the `$chip` input string
@@ -224,7 +226,6 @@
224226
readonly: '=readonly',
225227
removable: '=mdRemovable',
226228
placeholder: '@',
227-
mdEnableChipEdit: '@',
228229
secondaryPlaceholder: '@',
229230
maxChips: '@mdMaxChips',
230231
transformChip: '&mdTransformChip',
@@ -360,11 +361,14 @@
360361
// input.
361362
scope.$watch('$mdChipsCtrl.readonly', function(readonly) {
362363
if (!readonly) {
364+
363365
$mdUtil.nextTick(function(){
364-
if (chipInputTemplate.indexOf('<md-autocomplete') === 0)
365-
mdChipsCtrl
366-
.configureAutocomplete(element.find('md-autocomplete')
367-
.controller('mdAutocomplete'));
366+
367+
if (chipInputTemplate.indexOf('<md-autocomplete') === 0) {
368+
var autocompleteEl = element.find('md-autocomplete');
369+
mdChipsCtrl.configureAutocomplete(autocompleteEl.controller('mdAutocomplete'));
370+
}
371+
368372
mdChipsCtrl.configureUserInput(element.find('input'));
369373
});
370374
}

0 commit comments

Comments
 (0)