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

Commit

Permalink
fix(chips): fix chips focus functionality
Browse files Browse the repository at this point in the history
- The normal mobile devices won't trigger the focus on the element.
Focusing the element on `ng-click` fixes that issue.
Through keeping and redirecting to `ng-focus` it's still possible to select chips through keyboard
- At the moment, we only reset the selectedChip variable but we don't
  apply that to the view, so we need to run an async evaluation.

Fixes #5897. Fixes #5662. Closes #5941

# Conflicts:
#	src/components/chips/chips.spec.js
  • Loading branch information
devversion authored and ThomasBurleson committed Apr 1, 2016
1 parent a1ff0d5 commit cfb285c
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 5 deletions.
168 changes: 164 additions & 4 deletions src/components/chips/chips.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ describe('<md-chips>', function() {
'<md-chips ng-model="items" md-on-remove="removeChip($chip, $index)"></md-chips>';
var CHIP_SELECT_TEMPLATE =
'<md-chips ng-model="items" md-on-select="selectChip($chip)"></md-chips>';
var CHIP_READONLY_TEMPLATE =
'<md-chips ng-model="items" readonly="isReadonly"></md-chips>';
var CHIP_READONLY_AUTOCOMPLETE_TEMPLATE =
'<md-chips ng-model="items" readonly="true">' +
' <md-autocomplete md-items="item in [\'hi\', \'ho\', \'he\']"></md-autocomplete>' +
Expand Down Expand Up @@ -254,12 +256,53 @@ describe('<md-chips>', function() {
expect(scope.items[3].uppername).toBe('GRAPE');
});

it('should not throw an error when using readonly with an autocomplete', function() {
var element = buildChips(CHIP_READONLY_AUTOCOMPLETE_TEMPLATE);
describe('when readonly', function() {
var element, ctrl;

$timeout.flush();
it("properly toggles the controller's readonly property", function() {
element = buildChips(CHIP_READONLY_TEMPLATE);
ctrl = element.controller('mdChips');

expect(ctrl.readonly).toBeFalsy();

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

expect(ctrl.readonly).toBeTruthy();
});

it("properly toggles the wrapper's .md-readonly class", function() {
element = buildChips(CHIP_READONLY_TEMPLATE);
ctrl = element.controller('mdChips');

expect(element.find('md-chips-wrap')).not.toHaveClass('md-readonly');

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

expect(element.find('md-chips-wrap')).toHaveClass('md-readonly');
});

it('is false with empty items should not hide the chips wrapper', function() {
scope.isReadonly = false;
scope.items = [];
element = buildChips(CHIP_READONLY_TEMPLATE);

expect(element.find('md-chips-wrap').length).toBe(1);
});

it('is true with empty items should not hide the chips wrapper', function() {
scope.isReadonly = true;
scope.items = [];
element = buildChips(CHIP_READONLY_TEMPLATE);

expect(element.find('md-chips-wrap').length).toBe(1);
});

it('is true should not throw an error when used with an autocomplete', function() {
element = buildChips(CHIP_READONLY_AUTOCOMPLETE_TEMPLATE);
$timeout.flush();

expect($exceptionHandler.errors).toEqual([]);
expect($exceptionHandler.errors).toEqual([]);
});
});

it('should disallow duplicate object chips', function() {
Expand Down Expand Up @@ -451,6 +494,123 @@ describe('<md-chips>', function() {
}));
});

describe('md-max-chips', function() {

beforeEach(function() {
// Clear default items to test the max chips functionality
scope.items = [];
});

it('should not add a new chip if the max-chips limit is reached', function () {
var element = buildChips('<md-chips ng-model="items" md-max-chips="1"></md-chips>');
var ctrl = element.controller('mdChips');

element.scope().$apply(function() {
ctrl.chipBuffer = 'Test';
simulateInputEnterKey(ctrl);
});

expect(scope.items.length).toBe(1);

element.scope().$apply(function() {
ctrl.chipBuffer = 'Test 2';
simulateInputEnterKey(ctrl);
});

expect(scope.items.length).not.toBe(2);
});

it('should update the md-max-chips model validator for forms', function() {
var template =
'<form name="form">' +
'<md-chips name="chips" ng-model="items" md-max-chips="1"></md-chips>' +
'</form>';

var element = buildChips(template);
var ctrl = element.find('md-chips').controller('mdChips');

element.scope().$apply(function() {
ctrl.chipBuffer = 'Test';
simulateInputEnterKey(ctrl);
});

expect(scope.form.chips.$error['md-max-chips']).toBe(true);
});

it('should not reset the buffer if the maximum is reached', function() {
var element = buildChips('<md-chips ng-model="items" md-max-chips="1"></md-chips>');
var ctrl = element.controller('mdChips');

element.scope().$apply(function() {
ctrl.chipBuffer = 'Test';
simulateInputEnterKey(ctrl);
});

expect(scope.items.length).toBe(1);

element.scope().$apply(function() {
ctrl.chipBuffer = 'Test 2';
simulateInputEnterKey(ctrl);
});

expect(ctrl.chipBuffer).toBe('Test 2');
expect(scope.items.length).not.toBe(2);
});
});

describe('focus functionality', function() {
var element, ctrl;

beforeEach(function() {
element = buildChips(CHIP_SELECT_TEMPLATE);
ctrl = element.controller('mdChips');
document.body.appendChild(element[0]);
});

afterEach(function() {
element.remove();
element = ctrl = null;
});

it('should focus the chip when clicking / touching on the chip', function() {
ctrl.focusChip = jasmine.createSpy('focusChipSpy');

var chips = getChipElements(element);
expect(chips.length).toBe(3);

chips.children().eq(0).triggerHandler('click');

expect(ctrl.focusChip).toHaveBeenCalledTimes(1);
});

it('should focus the chip through normal content focus', function() {
scope.selectChip = jasmine.createSpy('focusChipSpy');
var chips = getChipElements(element);
expect(chips.length).toBe(3);

chips.children().eq(0).triggerHandler('focus');

expect(scope.selectChip).toHaveBeenCalledTimes(1);
});

it('should blur the chip correctly', function() {
var chips = getChipElements(element);
expect(chips.length).toBe(3);

var chipContent = chips.children().eq(0);
chipContent.triggerHandler('focus');

expect(ctrl.selectedChip).toBe(0);

chipContent.eq(0).triggerHandler('blur');

scope.$digest();

expect(ctrl.selectedChip).toBe(-1);
});

});

describe('md-autocomplete', function() {
var AUTOCOMPLETE_CHIPS_TEMPLATE = '\
<md-chips ng-model="items">\
Expand Down
3 changes: 2 additions & 1 deletion src/components/chips/js/chipDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ function MdChip($mdTheming, $mdUtil) {

if (ctrl) angular.element(element[0].querySelector('.md-chip-content'))
.on('blur', function () {
ctrl.selectedChip = -1;
ctrl.resetSelectedChip();
ctrl.$scope.$applyAsync();
});
};
}
Expand Down
1 change: 1 addition & 0 deletions src/components/chips/js/chipsDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
<div class="md-chip-content"\
tabindex="-1"\
aria-hidden="true"\
ng-click="!$mdChipsCtrl.readonly && $mdChipsCtrl.focusChip($index)"\
ng-focus="!$mdChipsCtrl.readonly && $mdChipsCtrl.selectChip($index)"\
md-chip-transclude="$mdChipsCtrl.chipContentsTemplate"></div>\
<div ng-if="!$mdChipsCtrl.readonly"\
Expand Down

0 comments on commit cfb285c

Please sign in to comment.