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

Commit

Permalink
fix(input): always format viewValue as a string inputs with text cont…
Browse files Browse the repository at this point in the history
…rols

Backported from 1eda183

NgModel will format all scope-based values to string when setting the viewValue for
the associated input element. The formatting, however, only applies to input elements
that contain a text, email, url or blank input type. In the event of a null or undefined
scope or model value, the viewValue will be set to null or undefined instead of being
converted to an empty string.

Closes #5936
Closes #9277
  • Loading branch information
caitp committed Sep 25, 2014
1 parent 37f2265 commit 1b8b41a
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/ng/directive/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,18 @@ function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, va
}
}

function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
function stringBasedInputType(ctrl) {
ctrl.$formatters.push(function stringifier(value) {
return ctrl.$isEmpty(value) ? value : value.toString();
});
}

function textInputType(scope, element, attr,ctrl, $sniffer, $browser) {
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
stringBasedInputType(ctrl);
}

function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
var validity = element.prop(VALIDITY_STATE_PROPERTY);
var placeholder = element[0].placeholder, noevent = {};
var type = lowercase(element[0].type);
Expand Down Expand Up @@ -1535,6 +1546,8 @@ var requiredDirective = function() {
*/
var ngListDirective = function() {
return {
restrict: 'A',
priority: 100,
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
var match = /\/(.*)\//.exec(attr.ngList),
Expand Down
81 changes: 81 additions & 0 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,87 @@ describe('ngModel', function() {
}));


it('should always format the viewValue as a string for a blank input type when the value is present',
inject(function($compile, $rootScope, $sniffer) {

var form = $compile('<form name="form"><input name="field" ng-model="val" /></form>')($rootScope);

$rootScope.val = 123;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe('123');

$rootScope.val = null;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe(null);

dealoc(form);
}));


it('should always format the viewValue as a string for a `text` input type when the value is present',
inject(function($compile, $rootScope, $sniffer) {

var form = $compile('<form name="form"><input type="text" name="field" ng-model="val" /></form>')($rootScope);
$rootScope.val = 123;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe('123');

$rootScope.val = null;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe(null);

$rootScope.val = undefined;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBeUndefined();

dealoc(form);
}));


it('should always format the viewValue as a string for an `email` input type when the value is present',
inject(function($compile, $rootScope, $sniffer) {

var fakeEmail = {};
fakeEmail.toString = function() { return 'fake@email'; };
var form = $compile('<form name="form"><input type="email" name="field" ng-model="val" /></form>')($rootScope);
$rootScope.val = fakeEmail;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe('fake@email');

$rootScope.val = null;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe(null);

$rootScope.val = undefined;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBeUndefined();

dealoc(form);
}));


it('should always format the viewValue as a string for a `url` input type when the value is present',
inject(function($compile, $rootScope, $sniffer) {

var fakeUrl = {};
fakeUrl.toString = function() { return 'https://www.angularjs.org'; };
var form = $compile('<form name="form"><input type="url" name="field" ng-model="val" /></form>')($rootScope);
$rootScope.val = fakeUrl;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe('https://www.angularjs.org');

$rootScope.val = null;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBe(null);

$rootScope.val = undefined;
$rootScope.$digest();
expect($rootScope.form.field.$viewValue).toBeUndefined();

dealoc(form);
}));


it('should register/deregister a nested ngModel with parent form when entering or leaving DOM',
inject(function($compile, $rootScope) {

Expand Down

1 comment on commit 1b8b41a

@jeffbcross
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit is breaking some projects internally (only on stable branch). I'll try to find the source and fix it.

Please sign in to comment.