Skip to content

Commit 1933a94

Browse files
committed
fix(ngBind): use same json conversion logic as $interpolate
Fixes angular#11716 BREAKING CHANGE: `ngBind` now uses the same logic as $interpolate (i.e. {{myString}}) when binding, which means objects are now transformed to string with an object's custom toString() function, except if the objects is a Date, Array, or Number, or if the object doesn't have a custom toString(), 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 1edbb15 commit 1933a94

File tree

4 files changed

+40
-2
lines changed

4 files changed

+40
-2
lines changed

src/.jshintrc

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
getBlockNodes: true,
8787
hasOwnProperty: true,
8888
createMap: true,
89+
stringify: true,
8990
9091
NODE_TYPE_ELEMENT: true,
9192
NODE_TYPE_ATTRIBUTE: true,

src/ng/directive/ngBind.js

Lines changed: 2 additions & 2 deletions
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
}
@@ -128,7 +128,7 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
128128
$compile.$$addBindingInfo(element, interpolateFn.expressions);
129129
element = element[0];
130130
attr.$observe('ngBindTemplate', function(value) {
131-
element.textContent = isUndefined(value) ? '' : value;
131+
element.textContent = stringify(value);
132132
});
133133
};
134134
}

test/ng/directive/ngBindSpec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,42 @@ 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+
58+
it('should use custom toString when present', inject(function($rootScope, $compile) {
59+
$rootScope.bind = {
60+
toString: function() {
61+
return 'foo';
62+
}
63+
};
64+
element = $compile('<div ng-bind="bind"></div>')($rootScope);
65+
$rootScope.$digest();
66+
expect(element.text()).toEqual('foo');
67+
}));
68+
69+
it('should NOT use toString on array objects', inject(function($rootScope, $compile) {
70+
$rootScope.bind = [];
71+
element = $compile('<div ng-bind="bind"></div>')($rootScope);
72+
$rootScope.$digest();
73+
expect(element.text()).toEqual('[]');
74+
}));
75+
76+
77+
it('should NOT use toString on Date objects', inject(function($rootScope, $compile) {
78+
$rootScope.bind = new Date(2014, 10, 10, 0, 0, 0);
79+
element = $compile('<div ng-bind="bind"></div>')($rootScope);
80+
$rootScope.$digest();
81+
expect(element.text()).toEqual('"2014-11-09T23:00:00.000Z"');
82+
}));
83+
84+
4985
it('should one-time bind if the expression starts with two colons', inject(function($rootScope, $compile) {
5086
element = $compile('<div ng-bind="::a"></div>')($rootScope);
5187
$rootScope.a = 'lucas';

0 commit comments

Comments
 (0)