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

Change what is contained in the result of a resolved $resource promise #14460

Closed
gaultier opened this issue Apr 18, 2016 · 4 comments
Closed

Comments

@gaultier
Copy link

gaultier commented Apr 18, 2016

Do you want to request a feature or report a bug?
Feature request.

What is the current behavior?
The result of a resolved promise from $resource is an object (if isArray: false) containing the actual results returned over http, as well as custom keys such as $resolved and $$state.
This can cause problems when iterating over the response.
In my case, the actual response is an object whose keys are strings and values are objects (it is a dictionary of objects). It looks like:

{'joe': {id: 1, name: 'joe'}, 'jim': {id: 2, name: 'jim'}}

But when then-callback is called, it is actually passed:
{'joe': {id: 1, name: 'joe'}, 'jim': {id: 2, name: 'jim'}, $resolved: true, $$state: ...}

Which can be problematic/surprising. Consider the following code:

promise.then(function(result) {
    angular.forEach(result, function(value, key) {
      value.foo = 'foo';
    });
  });

which is a simplified version of real production code. This will run perfectly in non-strict mode on all browsers. But in strict mode, this will (in some browsers like Chrome) cause an exception:

Cannot create property 'foo' on boolean 'true'".

Because the pair ($resolved, true) will be iterated over and we will try to basically do true.foo = 'foo'. It is surprising/unclear to the developer.

See the ticket I reported on Chromium bug tracker: https://bugs.chromium.org/p/v8/issues/detail?id=4929
It appears that in strict mode, this exception should trigger. Some browsers (like Firefox 44) are not compliant on this point.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).

Here is a plunkr reproducing the situation:
http://plnkr.co/edit/cKjfdYu2dLGxNOkfGHaF?p=preview

It passes on Firefox 44, IE11, Edge, and breaks with Chrome 50. It should break with Firefox 48 because it seems they made some fixes to comply more closely with the spec.
Tested on Linux and Windows.

I used the $q API to simulate $resource because I did not have an open API at hand, but it should be equivalent.

What is the expected behavior?
I suggest that either no custom key/value pair is inserted in the result object passed to the then-callback, or that it is not iterated over with angular.forEach.

What is the motivation / use case for changing the behavior?
Different behavior with non-strict/strict mode, and in different browsers, especially in the light of recent changes in major browsers like Firefox. I expect some production code in some apps to break because of this. Especially with the typescript compiler adding use strict in the build files since 1.8.

Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.
Tested on 1.5.3.

Other information (e.g. stacktraces, related issues, suggestions how to fix)

@gkalpak
Copy link
Member

gkalpak commented Apr 19, 2016

TBH, everything is working as expected imho.

Instances created using a $resource factory are documented to have some extra properties (which is a feature, not something to be fixed).
angular.forEach is also documented to iterate over all enumerable own properties; changing it would be a bug (not to mention a major breaking change).

If you want to iterate over an object's keys you are free to choose the object and the iterator you are going to use. But if you choose an object that has $-prefixed properties and an iterator function that iterates over them, you shouldn't be surprized that such properties are iterated over 😛

Also note that modifying $-prefixed properties (even if it didn't break), is recommened against, as it might affect the behavior of Angular.

Bottom line: Using angular.forEach with an iterator function that doesn't skip $-prefixed properties is a bug in user code, not in Angular (imo).

@gkalpak
Copy link
Member

gkalpak commented Apr 19, 2016

BTW, the fact that JS behaves differently in strict vs non-strict mode, that browsers don't always follow the spec close enough or have varying implementations and that you have different modes in dev vs prod, does not change the fact that there is a bug in the code (it just hides it under certain circumstances).

@sawajid
Copy link

sawajid commented Apr 28, 2016

any workaround to avoid this issue ?

@Narretz
Copy link
Contributor

Narretz commented Oct 9, 2017

You can use the toJson method on the resource instance to obtain an object without the extra properties.

@Narretz Narretz closed this as completed Oct 9, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants