Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
fix(input): fix bad char counter when value is a number. Fixes #4635.
Browse files Browse the repository at this point in the history
  • Loading branch information
jelbourn committed Oct 1, 2015
1 parent 5d4ef55 commit 74b4bae
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 68 deletions.
4 changes: 3 additions & 1 deletion src/components/input/input.js
Expand Up @@ -408,7 +408,9 @@ function mdMaxlengthDirective($animate) {
};

function renderCharCount(value) {
charCountEl.text(( element.val() || value || '' ).length + '/' + maxlength);
// Force the value into a string since it may be a number,
// which does not have a length property.
charCountEl.text(String(element.val() || value || '').length + '/' + maxlength);
return value;
}
}
Expand Down
167 changes: 100 additions & 67 deletions src/components/input/input.spec.js
@@ -1,47 +1,64 @@
describe('md-input-container directive', function() {
var $compile, pageScope;

beforeEach(module('material.components.input'));
beforeEach(module('ngAria'));
beforeEach(module('ngAria', 'material.components.input'));

beforeEach(inject(function($injector) {
$compile = $injector.get('$compile');

var pageScope = $injector.get('$rootScope').$new();
}));

function setup(attrs, isForm) {
var container;
inject(function($rootScope, $compile) {
container = $compile((isForm ? '<form>' : '') +
'<md-input-container><input ' + (attrs || '') + '><label></label></md-input-container>' +
(isForm ? '<form>' : ''))($rootScope);
$rootScope.$apply();
});

var template =
'<md-input-container>' +
'<input ' + (attrs || '') + '>' +
'<label></label>' +
'</md-input-container>';

if (isForm) {
template = '<form>' + template + '</form>';
}

container = $compile(template)(pageScope);

pageScope.$apply();
return container;
}

it('should by default show error on $touched and $invalid', inject(function($rootScope) {
it('should by default show error on $touched and $invalid', function() {
var el = setup('ng-model="foo"');

expect(el).not.toHaveClass('md-input-invalid');

var model = el.find('input').controller('ngModel');
model.$touched = model.$invalid = true;
$rootScope.$apply();
pageScope.$apply();

expect(el).toHaveClass('md-input-invalid');

model.$touched = model.$invalid = false;
$rootScope.$apply();
pageScope.$apply();
expect(el).not.toHaveClass('md-input-invalid');
}));
});

it('should show error with given md-is-error expression', inject(function($rootScope, $compile) {
var el = $compile('<md-input-container md-is-error="$root.isError"><input ng-model="foo"></md-input-container>')($rootScope);
it('should show error with given md-is-error expression', function() {
var el = $compile(
'<md-input-container md-is-error="isError">' +
'<input ng-model="foo">' +
'</md-input-container>')(pageScope);

$rootScope.$apply();
pageScope.$apply();
expect(el).not.toHaveClass('md-input-invalid');

$rootScope.$apply('isError = true');
pageScope.$apply('isError = true');
expect(el).toHaveClass('md-input-invalid');

$rootScope.$apply('isError = false');
pageScope.$apply('isError = false');
expect(el).not.toHaveClass('md-input-invalid');
}));
});

it('should set focus class on container', function() {
var el = setup();
Expand Down Expand Up @@ -76,124 +93,140 @@ describe('md-input-container directive', function() {
expect(el).not.toHaveClass('md-input-has-value');
});

it('should set has-value class on container for ng-model input', inject(function($rootScope) {
$rootScope.value = 'test';
var el = setup('ng-model="$root.value"');
it('should set has-value class on container for ng-model input', function() {
pageScope.value = 'test';
var el = setup('ng-model="value"');
expect(el).toHaveClass('md-input-has-value');

$rootScope.$apply('value = "3"');
pageScope.$apply('value = "3"');
expect(el).toHaveClass('md-input-has-value');

$rootScope.$apply('value = null');
pageScope.$apply('value = null');
expect(el).not.toHaveClass('md-input-has-value');
}));
});

it('should match label to given input id', inject(function() {
it('should match label to given input id', function() {
var el = setup('id="foo"');
expect(el.find('label').attr('for')).toBe('foo');
expect(el.find('input').attr('id')).toBe('foo');
}));
});

it('should match label to automatic input id', inject(function() {
it('should match label to automatic input id', function() {
var el = setup();
expect(el.find('input').attr('id')).toBeTruthy();
expect(el.find('label').attr('for')).toBe(el.find('input').attr('id'));
}));
});

describe('md-maxlength', function() {
function getCharCounter(el) {
return angular.element(el[0].querySelector('.md-char-counter'));
}

it('should work with a constant', inject(function($rootScope, $compile) {
var el = $compile('<form name="form">' +
' <md-input-container>' +
' <input md-maxlength="5" ng-model="foo" name="foo">' +
' </md-input-container>' +
'</form>')($rootScope);
$rootScope.$apply();
expect($rootScope.form.foo.$error['md-maxlength']).toBeFalsy();
it('should work with a constant', function() {
var el = $compile(
'<form name="form">' +
'<md-input-container>' +
'<input md-maxlength="5" ng-model="foo" name="foo">' +
'</md-input-container>' +
'</form>')(pageScope);

pageScope.$apply();
expect(pageScope.form.foo.$error['md-maxlength']).toBeFalsy();
expect(getCharCounter(el).text()).toBe('0/5');

$rootScope.$apply('foo = "abcde"');
expect($rootScope.form.foo.$error['md-maxlength']).toBeFalsy();
pageScope.$apply('foo = "abcde"');
expect(pageScope.form.foo.$error['md-maxlength']).toBeFalsy();
expect(getCharCounter(el).text()).toBe('5/5');

$rootScope.$apply('foo = "abcdef"');
pageScope.$apply('foo = "abcdef"');
el.find('input').triggerHandler('input');
expect($rootScope.form.foo.$error['md-maxlength']).toBe(true);
expect(pageScope.form.foo.$error['md-maxlength']).toBe(true);
expect(getCharCounter(el).text()).toBe('6/5');

$rootScope.$apply('foo = "abc"');
pageScope.$apply('foo = "abc"');
el.find('input').triggerHandler('input');
expect($rootScope.form.foo.$error['md-maxlength']).toBeFalsy();
expect(pageScope.form.foo.$error['md-maxlength']).toBeFalsy();
expect(getCharCounter(el).text()).toBe('3/5');
}));
});

it('should render correct character count when value is a number', function() {
var template =
'<md-input-container>' +
'<input ng-model="item.numberValue" md-maxlength="6">' +
'</md-input-container>';
var element = $compile(template)(pageScope);
pageScope.$apply();

pageScope.item = {numberValue: 456};
pageScope.$apply();

expect(getCharCounter(element).text()).toBe('3/6');
});

it('should add and remove maxlength element & error with expression', inject(function($rootScope, $compile) {
it('should add and remove maxlength element & error with expression', function() {
var el = $compile('<form name="form">' +
' <md-input-container>' +
' <input md-maxlength="max" ng-model="foo" name="foo">' +
' </md-input-container>' +
'</form>')($rootScope);
'</form>')(pageScope);

$rootScope.$apply();
expect($rootScope.form.foo.$error['md-maxlength']).toBeFalsy();
pageScope.$apply();
expect(pageScope.form.foo.$error['md-maxlength']).toBeFalsy();
expect(getCharCounter(el).length).toBe(0);

$rootScope.$apply('max = 5');
$rootScope.$apply('foo = "abcdef"');
expect($rootScope.form.foo.$error['md-maxlength']).toBeTruthy();
pageScope.$apply('max = 5');
pageScope.$apply('foo = "abcdef"');
expect(pageScope.form.foo.$error['md-maxlength']).toBeTruthy();
expect(getCharCounter(el).length).toBe(1);
expect(getCharCounter(el).text()).toBe('6/5');

$rootScope.$apply('max = -1');
$rootScope.$apply('foo = "abcdefg"');
expect($rootScope.form.foo.$error['md-maxlength']).toBeFalsy();
pageScope.$apply('max = -1');
pageScope.$apply('foo = "abcdefg"');
expect(pageScope.form.foo.$error['md-maxlength']).toBeFalsy();
expect(getCharCounter(el).length).toBe(0);
}));
});
});

it('should put placeholder into a label element', inject(function($rootScope, $compile) {
var el = $compile('<md-input-container><input ng-model="foo" placeholder="some placeholder"></md-input-container>')($rootScope);
it('should put placeholder into a label element', function() {
var el = $compile('<md-input-container><input ng-model="foo" placeholder="some placeholder"></md-input-container>')(pageScope);
var placeholder = el[0].querySelector('.md-placeholder');
var label = el.find('label')[0];

expect(el.find('input')[0].hasAttribute('placeholder')).toBe(false);
expect(label).toBeTruthy();
expect(label.textContent).toEqual('some placeholder');
}));
});

it('should ignore placeholder when a label element is present', inject(function($rootScope, $compile) {
it('should ignore placeholder when a label element is present', function() {
var el = $compile(
'<md-input-container>' +
' <label>Hello</label>' +
' <input ng-model="foo" placeholder="some placeholder" />' +
'</md-input-container>'
)($rootScope);
)(pageScope);

var label = el.find('label')[0];

expect(el.find('input')[0].hasAttribute('placeholder')).toBe(true);
expect(label).toBeTruthy();
expect(label.textContent).toEqual('Hello');
}));
});

it('should put an aria-label on the input when no label is present', inject(function($rootScope, $compile) {
it('should put an aria-label on the input when no label is present', function() {
var el = $compile('<form name="form">' +
' <md-input-container md-no-float>' +
' <input placeholder="baz" md-maxlength="max" ng-model="foo" name="foo">' +
' </md-input-container>' +
'</form>')($rootScope);
'</form>')(pageScope);

$rootScope.$apply();
pageScope.$apply();

var input = el.find('input');
expect(input.attr('aria-label')).toBe('baz');
}));
});

it('should put the container in "has value" state when input has a static value', inject(function($rootScope, $compile) {
var scope = $rootScope.$new();
it('should put the container in "has value" state when input has a static value', function() {
var scope = pageScope.$new();
var template =
'<md-input-container>' +
'<label>Name</label>' +
Expand All @@ -204,5 +237,5 @@ describe('md-input-container directive', function() {
scope.$apply();

expect(element.hasClass('md-input-has-value')).toBe(true);
}));
});
});

0 comments on commit 74b4bae

Please sign in to comment.