From 0325341d9edc3247ef8a1af72eee8c0d798710c0 Mon Sep 17 00:00:00 2001 From: pmartin Date: Sun, 4 Mar 2018 21:36:08 +0100 Subject: [PATCH] fix(input): make md-maxlength validation happen on initialization Closes #10320 --- src/components/input/input.js | 32 ++++++++++++++------------ src/components/input/input.spec.js | 37 ++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/components/input/input.js b/src/components/input/input.js index 66e64b81a79..d65bd42c998 100644 --- a/src/components/input/input.js +++ b/src/components/input/input.js @@ -634,11 +634,25 @@ function mdMaxlengthDirective($animate, $mdUtil) { }; function postLink(scope, element, attr, ctrls) { - var maxlength; + var maxlength = parseInt(attr.mdMaxlength); + if (isNaN(maxlength)) maxlength = -1; var ngModelCtrl = ctrls[0]; var containerCtrl = ctrls[1]; var charCountEl, errorsSpacer; + + ngModelCtrl.$validators['md-maxlength'] = function(modelValue, viewValue) { + if (!angular.isNumber(maxlength) || maxlength < 0) { + return true; + } + + // We always update the char count, when the modelValue has changed. + // Using the $validators for triggering the update works very well. + renderCharCount(); + + return ( modelValue || element.val() || viewValue || '' ).length <= maxlength; + }; + // Wait until the next tick to ensure that the input has setup the errors spacer where we will // append our counter $mdUtil.nextTick(function() { @@ -663,23 +677,11 @@ function mdMaxlengthDirective($animate, $mdUtil) { $animate.leave(charCountEl); } }); - - ngModelCtrl.$validators['md-maxlength'] = function(modelValue, viewValue) { - if (!angular.isNumber(maxlength) || maxlength < 0) { - return true; - } - - // We always update the char count, when the modelValue has changed. - // Using the $validators for triggering the update works very well. - renderCharCount(); - - return ( modelValue || element.val() || viewValue || '' ).length <= maxlength; - }; }); function renderCharCount(value) { - // If we have not been appended to the body yet; do not render - if (!charCountEl.parent) { + // If we have not been initialized or appended to the body yet; do not render + if (!charCountEl || !charCountEl.parent) { return value; } diff --git a/src/components/input/input.spec.js b/src/components/input/input.spec.js index 7a72ee17991..feb5e49e7ae 100644 --- a/src/components/input/input.spec.js +++ b/src/components/input/input.spec.js @@ -257,6 +257,40 @@ describe('md-input-container directive', function() { return angular.element(el[0].querySelector('.md-char-counter')); } + it('should error with a constant and incorrect initial value', function() { + var el = $compile( + '
' + + ' ' + + ' ' + + ' ' + + '
')(pageScope); + + pageScope.$apply('foo = "ABCDEFGHIJ"'); + + // Flush any pending $mdUtil.nextTick calls + $timeout.flush(); + + expect(pageScope.form.foo.$error['md-maxlength']).toBe(true); + expect(getCharCounter(el).text()).toBe('10 / 2'); + }); + + it('should work with a constant and correct initial value', function() { + var el = $compile( + '
' + + ' ' + + ' ' + + ' ' + + '
')(pageScope); + + pageScope.$apply('foo = "abcde"'); + + // Flush any pending $mdUtil.nextTick calls + $timeout.flush(); + + expect(pageScope.form.foo.$error['md-maxlength']).toBeFalsy(); + expect(getCharCounter(el).text()).toBe('5 / 5'); + }); + it('should work with a constant', function() { var el = $compile( '
' + @@ -341,11 +375,10 @@ describe('md-input-container directive', function() { ' ' + '
')(pageScope); - pageScope.$apply(); + pageScope.$apply('max = -1'); // Flush any pending $mdUtil.nextTick calls $timeout.flush(); - expect(pageScope.form.foo.$error['md-maxlength']).toBeFalsy(); expect(getCharCounter(el).length).toBe(0);