I'm using AngularJS' $resource to fetch and update an object. To save a round trip on page load, I have the JSON object in a variable on the page. How can I initialize the $resource with this data rather than calling $get?
-
[$cacheFactory](http://docs.angularjs.org/api/ng.$cacheFactory) is probably the answer, but you'll probably have to look at the Angular source code to figure out what cacheId they use. Also/instead, can't you just set your $scope property to the JSON object (or do you wrap $resource in a service that alters the data so that it is "fit" for $scope consumption)? – Mark Rajcok Jan 30 '13 at 04:54
-
I need the $resource actions, like update, so can't use the raw JSON object on the scope. – Kris Braun Jan 30 '13 at 13:20
-
1Okay, so looking at @Brandon's answer, $cacheFactory is not the answer for $resource. ($cacheFactory might be useful if you switch to $http though, if you someday find $resource [too limiting](http://stackoverflow.com/questions/11850025/recommended-way-of-getting-data-from-the-server).) – Mark Rajcok Jan 30 '13 at 17:13
4 Answers
You can use new
to create instances of resources created with $resource
:
window.somePreloadedJson = {
id: 1,
name: 'lancelot',
quest: 'holy grail',
color: 'blue',
};
app.factory('myResource', function($resource) {
return $resource('/my/fake/:id', { id: '@id' });
});
...
$scope.resource = new myResource(window.somePreloadedJson);
Here is an example of this technique on jsFiddle, which demonstrates that $save
, $delete
, etc. work as expected on the created instance. (Some debugging code has been added to log out HTTP requests rather than actually make them, so you can see what requests would have been made in the page.)

- 157,729
- 40
- 374
- 311
-
2Can you do similar if window.somePreloadedJson was an array? i.e. what you would get if you did a $resource('foo/:id').query() call? – Godders Jun 27 '13 at 14:31
You can use the angular-mocks.js
script, available here. This script allows you to intercept service calls and substitute responses at runtime, very useful for testing purposes.
For example, given a service:
app.factory('MyService', ['$resource', function($resource) {
return $resource('http://myservice/service', {}, {
get: {
method:'GET',
params:{},
isArray:false
}
});
}]);
it can be redirected this way:
app.config(function($provide) {
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
});
app.run(function($httpBackend) {
$httpBackend.whenGET(new RegExp(".*/myservice/service.*")).respond(200, mockData.fake);
...
}
where mock data is defined somewhere like this:
var mockData = new Object();
mockData.fake = ...
To activate the fake service just include the angular-mocks script and the above mentioned definitions, to switch to regular one just comment out or remove them.
-
1Interesting solution, but my use case is for production, where I probably don't want to include the mock framework. Also, I only want to avoid the initial get then use the regular $reaource service from then on. – Kris Braun Jan 30 '13 at 13:10
It is blindingly frustrating to me that this is not better answered. Here is my solution. I don't know if it qualifies as lame or not, but it works for me:
# Loading json data from the document into angular seems to be a pain.
# The sole purpose of this controller is to make that easier.
# Let's say you want to load up the following JSON: [{"name": "Joe", "id": 1}]
# AND you have an angularjs service called People with a list
# You would do the following:
# <any_element ng-controller='JsonDataController' data-json='[{"name": "Joe", "id": 1}]' data-service='People' data-binding='list'></any_element>
# The controller would then set People.list = JSON.parse($attrs.json)
# And that's all there is to it.
window.JsonDataController = ['$scope', '$attrs', '$injector', ($scope, $attrs, $injector) ->
service = $injector.get($attrs.service)
attributeName = $attrs.binding
service[attributeName] = JSON.parse($attrs.json)
]

- 2,225
- 22
- 25
You can use a custom $cacheFactory to initialize the $resource with the data.
Let's say you have:
window.initData = {
'/request1': 'a',
'/request2': [1, 2, 3],
'/request3': {c: 'c', d: 'd'}
};
First, create the custom cache factory:
angular.module('app').factory('PreloadedCache', function($cacheFactory, $window) {
var PreloadedCache = $cacheFactory('preloadedCache');
// Pre-populating the $resource cache
angular.forEach($window.initData, function(item, key) {
PreloadedCache.put(key, item);
});
// Overwrite the put cache function - prevent saving in two places
PreloadedCache.put = function() {};
return PreloadedCache;
});
Then, declare a cache property on the resource action (from the docs):
cache – {boolean|Cache} – If true, a default $http cache will be used to cache the GET request, otherwise if a cache instance built with $cacheFactory, this cache will be used for caching.
{action1: {method:?, params:?, cache: PreloadedCache, ...},
action2: {method:?, params:?, isArray:?, headers:?, cache: PreloadedCache, ...},
...}

- 267
- 2
- 13