Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing AngularJS $resource with in-page JSON

Tags:

angularjs

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?

like image 503
Kris Braun Avatar asked Jan 30 '13 04:01

Kris Braun


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.)

like image 93
Michelle Tilley Avatar answered Nov 01 '22 15:11

Michelle Tilley


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)
  ]
like image 40
kwerle Avatar answered Nov 01 '22 14:11

kwerle


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, ...},
...}
like image 1
dbabaioff Avatar answered Nov 01 '22 16:11

dbabaioff


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.

like image 1
remigio Avatar answered Nov 01 '22 16:11

remigio