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?
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.)
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)
]
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, ...},
...}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With