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

Commit ef52432

Browse files
committed
fix(ngBind): use same json conversion logic as $interpolate
Fixes #11716 BREAKING CHANGE: `ngBind` now uses the same logic as $interpolate (i.e. {{myString}}) when binding, which means objects are now transformed to string either with an object's custom toString() function, or if the object doesn't have one, with JSON.stringify. Previously, ngBind would use always use toString(). The following examples show the different output: ```js $scope.myPlainObject = {a: 1, b: 2}; $scope.myCustomObject = {a: 1, b: 2, toString: function() {return 'a+b';}}; ``` Plain Object: ```html <!-- Before: --> <span ng-bind="myPlainObject">[object Object]</span> <!-- After: --> <span ng-bind="myPlainObject">{"a":1,"b":2}</span> ``` Object with custom toString(): ```html <!-- Before: --> <span ng-bind="myCustomObject">[object Object]</span> <!-- After: --> <span ng-bind="myCustomObject">a+b</span> ``` Migration: If you want the output of `toString()`, use a custom filter: ```js angular.module('myApp').filter('toString', function() { return function toString(value) { return value.toString(); }; }); ``` ```html <span ng-bind="myObject | toString">[object Object]</span> ```
1 parent a5d804d commit ef52432

File tree

5 files changed

+34
-22
lines changed

5 files changed

+34
-22
lines changed

src/.jshintrc

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"createMap": false,
9797
"VALIDITY_STATE_PROPERTY": false,
9898
"reloadWithDebugInfo": false,
99+
"stringify": false,
99100

100101
"NODE_TYPE_ELEMENT": false,
101102
"NODE_TYPE_ATTRIBUTE": false,

src/Angular.js

+23
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
getBlockNodes: true,
8888
hasOwnProperty: true,
8989
createMap: true,
90+
stringify: true,
9091
9192
NODE_TYPE_ELEMENT: true,
9293
NODE_TYPE_ATTRIBUTE: true,
@@ -1929,6 +1930,28 @@ function createMap() {
19291930
return Object.create(null);
19301931
}
19311932

1933+
1934+
function stringify(value) {
1935+
if (value == null) { // null || undefined
1936+
return '';
1937+
}
1938+
switch (typeof value) {
1939+
case 'string':
1940+
break;
1941+
case 'number':
1942+
value = '' + value;
1943+
break;
1944+
default:
1945+
if (isFunction(value.toString) && value.toString !== Object.prototype.toString && !isArray(value)) {
1946+
value = value.toString();
1947+
} else {
1948+
value = toJson(value);
1949+
}
1950+
}
1951+
1952+
return value;
1953+
}
1954+
19321955
var NODE_TYPE_ELEMENT = 1;
19331956
var NODE_TYPE_ATTRIBUTE = 2;
19341957
var NODE_TYPE_TEXT = 3;

src/ng/directive/ngBind.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ var ngBindDirective = ['$compile', function($compile) {
6060
$compile.$$addBindingInfo(element, attr.ngBind);
6161
element = element[0];
6262
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
63-
element.textContent = isUndefined(value) ? '' : value;
63+
element.textContent = isUndefined(value) ? '' : stringify(value);
6464
});
6565
};
6666
}

src/ng/interpolate.js

-21
Original file line numberDiff line numberDiff line change
@@ -111,27 +111,6 @@ function $InterpolateProvider() {
111111
replace(escapedEndRegexp, endSymbol);
112112
}
113113

114-
function stringify(value) {
115-
if (value == null) { // null || undefined
116-
return '';
117-
}
118-
switch (typeof value) {
119-
case 'string':
120-
break;
121-
case 'number':
122-
value = '' + value;
123-
break;
124-
default:
125-
if (isFunction(value.toString) && value.toString !== Object.prototype.toString && !isArray(value)) {
126-
value = value.toString();
127-
} else {
128-
value = toJson(value);
129-
}
130-
}
131-
132-
return value;
133-
}
134-
135114
//TODO: this is the same as the constantWatchDelegate in parse.js
136115
function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
137116
var unwatch;

test/ng/directive/ngBindSpec.js

+9
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ describe('ngBind*', function() {
4646
expect(element.text()).toEqual('-0false');
4747
}));
4848

49+
they('should jsonify $prop', [[{a: 1}, '{"a":1}'], [true, 'true'], [false, 'false']], function(prop) {
50+
inject(function($rootScope, $compile) {
51+
$rootScope.bind = prop[0];
52+
element = $compile('<div ng-bind="bind"></div>')($rootScope);
53+
$rootScope.$digest();
54+
expect(element.text()).toEqual(prop[1]);
55+
});
56+
});
57+
4958
it('should one-time bind if the expression starts with two colons', inject(function($rootScope, $compile) {
5059
element = $compile('<div ng-bind="::a"></div>')($rootScope);
5160
$rootScope.a = 'lucas';

0 commit comments

Comments
 (0)