From 74b4bae235743efbf5add559543a5f1d1538913a Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Wed, 30 Sep 2015 16:37:25 -0700 Subject: [PATCH] fix(input): fix bad char counter when value is a number. Fixes #4635. --- src/components/input/input.js | 4 +- src/components/input/input.spec.js | 167 +++++++++++++++++------------ 2 files changed, 103 insertions(+), 68 deletions(-) diff --git a/src/components/input/input.js b/src/components/input/input.js index 019a436688d..4506226c672 100644 --- a/src/components/input/input.js +++ b/src/components/input/input.js @@ -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; } } diff --git a/src/components/input/input.spec.js b/src/components/input/input.spec.js index 4618bc216d3..c3a793fdfca 100644 --- a/src/components/input/input.spec.js +++ b/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 ? '
' : '') + - '' + - (isForm ? '' : ''))($rootScope); - $rootScope.$apply(); - }); + + var template = + '' + + '' + + '' + + ''; + + if (isForm) { + template = '' + template + '
'; + } + + 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('')($rootScope); + it('should show error with given md-is-error expression', function() { + var el = $compile( + '' + + '' + + '')(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(); @@ -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('
' + - ' ' + - ' ' + - ' ' + - '
')($rootScope); - $rootScope.$apply(); - expect($rootScope.form.foo.$error['md-maxlength']).toBeFalsy(); + it('should work with a constant', function() { + var el = $compile( + '
' + + '' + + '' + + '' + + '
')(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 = + '' + + '' + + ''; + 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('
' + ' ' + ' ' + ' ' + - '
')($rootScope); + '')(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('')($rootScope); + it('should put placeholder into a label element', function() { + var el = $compile('')(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( '' + ' ' + ' ' + '' - )($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('
' + ' ' + ' ' + ' ' + - '
')($rootScope); + '')(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 = '' + '' + @@ -204,5 +237,5 @@ describe('md-input-container directive', function() { scope.$apply(); expect(element.hasClass('md-input-has-value')).toBe(true); - })); + }); });