Reading in JSON through Angular Resources Service - javascript

How can I use angular-resources.js to read in a JSON file through a service?
I am working on a very basic Angular app for testing purposes and am just trying to read in data from JSON file right now. I am placing this code in a service so I can more easily swap it out when we move a server based data store.
My App and App.controller declaration are as follows:
'use strict';
// create module for custom directives
var App = angular.module('App', ['jsonService']);
// controller business logic
App.controller('AppCtrl', function AppCtrl($scope, JsonService) {
console.log("marker 1");
if (!$scope.jsonData) {
console.log("marker 2");
JsonService.getData(function (d) {
console.log(d);
$scope.jsonData = d;
$scope.records = d.length;
});
} else {
console.log("I have data already... " + $scope.jsonData);
}
console.log($scope.jsonData);
});
My JsonService is defined as the follow, at the moment:
'use strict';
angular.module('jsonService', ['ngResource'])
.factory('JsonService', function($resource, $filter) {
// define the remote service using Angular's $resource module
var service = $resource('/data/ProcessModeling-Resources.json', {});
var JsonService = {
// calls $resource.query() to retrieve the remote data.
getData : function getData(callback) {
console.log("marker 3");
service.query(function (data) {
console.log("marker 4");
});
}
};
return JsonService;
});
The console output I am getting follows:
marker 1 app.js:8
marker 2 app.js:11
marker 3 services.js:13
undefined app.js:21
TypeError: Object #<Resource> has no method 'push'
at copy (http://127.0.0.1:8000/lib/angular.js:556:21)
at new Resource (http://127.0.0.1:8000/lib/angular-resource.js:330:9)
at http://127.0.0.1:8000/lib/angular-resource.js:386:32
at forEach (http://127.0.0.1:8000/lib/angular.js:117:20)
at http://127.0.0.1:8000/lib/angular-resource.js:385:19
at wrappedCallback (http://127.0.0.1:8000/lib/angular.js:6650:59)
at http://127.0.0.1:8000/lib/angular.js:6687:26
at Object.Scope.$eval (http://127.0.0.1:8000/lib/angular.js:7840:28)
at Object.Scope.$digest (http://127.0.0.1:8000/lib/angular.js:7707:25)
at Object.Scope.$apply (http://127.0.0.1:8000/lib/angular.js:7926:24) angular.js:5582
I'm receiving my error when I attempt to call my service.query(function (data) { }, which (if I'm understanding correctly) should be pulling my JSON file in.
I've been using AngularJS Cats App as an example for pulling data.

I'd follow #pkozlowski's advice and make sure the response is an array. Anyway, here's an example that loads data from a JSON file similar to what you describe in your comments. It uses ngResource and can help you put things together: http://plnkr.co/edit/Ofq7Md8udEnIhAPF1NgL?p=preview
The service
angular.module('jsonService', ['ngResource'])
.factory('JsonService', function($resource) {
return $resource('cats.json',{ }, {
getData: {method:'GET', isArray: false}
});
});
Notice that isArray is set to false.
Your app and controller
var app = angular.module('app', ['jsonService']);
app.controller('ctrl', function($scope, JsonService){
JsonService.getData(function(data){
$scope.name = data.name;
$scope.children = data.children;
});
});
getData is actually not needed since the Resource class gives you some useful convenience methods such a get, you can just do this
angular.module('jsonService', ['ngResource'])
.factory('JsonService', function($resource) {
return $resource('cats.json');
});
app.controller('ctrl', function($scope, JsonService){
JsonService.get(function(data){
$scope.name = data.name;
$scope.children = data.children;
});
});

Related

How to store data in angularjs application?

Hi I am developing my first Angularjs application. I want to save data in Angularjs application for later use(I have used localstorage in jquery before).
For example, I will make ajax call and i will get some data, Lets say below example,
$http.post('http://192.168.0.213:1234/api/VerifyUser', $stateParams.pageList).then(function (response) {
alert(response.data);
another example, After succesfull login i will get some ID in response and i want to preserve this data all over the application. This ID i may use in all subsequent ajax calls.
I will get some data in response and i want to make use that data in other controllers as well. Is there any way i can do this? any help would be appreciated. Thank you.
you can store it in factory like below,
After your Ajax call
$http.post('http://192.168.0.213:1234/api/VerifyUser', $stateParams.pageList).then(function (response) {
alert(response.data)
SomeFactory.setData(response.data);
};
SomeFactory
(function () {
'use strict';
angular
.module('app.myApp')
.factory('SomeFactory', SomeFactory);
SomeFactory.$inject = [];
function SomeFactory() {
var someData;
var factory = {
setData: setData,
getData: getData
};
function setData(data) {
someData = data;
}
function getData() {
return someData;
}
return factory;
}
})();
In your Controllers
inject your factory to your controller and then getdata
(function () {
'use strict';
angular
.module('app.login')
.controller('LoginController', LoginController);
LoginController.$inject = ['SomeFactory'];
function LoginController(SomeFactory) {
var vm = this;
vm.someVariable = SomeFactory.getData();
console.log(vm.someVariable); // logs your data
}
})();
Sharing data between controllers can be achieved with the following options :
Factory
Service
Then you can inject the service across the controllers and use the data whenever you need.
app.service('myService', function($http) {
this.getJSON = function() {
$http.post('http://192.168.0.213:1234/api/VerifyUser', $stateParams.pageList).then(function(response) {
return response.data;
});
};
});
In Controller:
app.controller('myController', function($scope, myService) {
myService.getJSON().then(function(data) {
$scope.myData = data;
console.log(data);
});
});
DEMO
Use Service to store the data and get the data in another controller later on.
When you inject a Service, it's the same service in every controller - so you can access the properties and methods in that service all over.
https://docs.angularjs.org/guide/services
Example:
.service('YourService', function(){
var YourService = {};
YourService.yourvar = '';
return YourService;
})
.controller('controller1', function($scope, YourService){
YourService.yourvar = 'blah';
})
.controller('controller2', function($scope, YourService){
$scope.currentYourVar = YourService.yourvar;
})

How to get data from an API in a Angular Service and store it to be used by anyone in the future

This is more of a writing clean code/ optimizing existing code.
I am writing my Angular Services to fetch data from backend like this
angular.module('myApp').service('Auth', ['$http', '$q', 'Config', function($http, $q, Config) {
this.getUser = function() {
return $http.get(Config.apiurl + '/auth/user')
.then(function(response) {
return response.data;
}, function(error) {
return $q.reject(error.data);
});
};
}]);
Now in this, I am calling getUser function n number of times from the Database.
Now the question is, is it okay to call this service to get n times redundant data or I should it be saved somewhere say rootscope to be accessed later? Or storing in root scope would be bad practice and I should consider some other option or nothing at all?
Would like to get some views on Angular Community here.
Here is a sample example on how to use factory for sharing data across the application.
Lets create a factory which can be used in entire application across all controllers to store data and access them.
Advantages with factory is you can create objects in it and intialise them any where in the controllers or we can set the defult values by intialising them in the factory itself.
Factory
app.factory('SharedData',['$http','$rootScope',function($http,$rootScope){
var SharedData = {}; // create factory object...
SharedData.appName ='My App';
return SharedData;
}]);
Service
app.service('Auth', ['$http', '$q', 'SharedData', function($http, $q,SharedData) {
this.getUser = function() {
return $http.get('user.json')
.then(function(response) {
this.user = response.data;
SharedData.userData = this.user; // inject in the service and create a object in factory ob ject to store user data..
return response.data;
}, function(error) {
return $q.reject(error.data);
});
};
}]);
Controller
var app = angular.module("app", []);
app.controller("testController", ["$scope",'SharedData','Auth',
function($scope,SharedData,Auth) {
$scope.user ={};
// do a service call via service and check the shared data which is factory object ...
var user = Auth.getUser().then(function(res){
console.log(SharedData);
$scope.user = SharedData.userData;// assigning to scope.
});
}]);
In HTML
<body ng-app='app'>
<div class="media-list" ng-controller="testController">
<pre> {{user | json}}</pre>
</div>
</body>
Instead of rootScope just use a local variable of user in your service that can be accessed from anywhere in your code and so you doesn't have to call the api every time.
angular.module('metaiotAdmin').service('Auth', ['$http', '$q', 'Config', function($http, $q, Config) {
this.getUser = function() {
if(this.user){
return this.user;
}
else{
return $http.get(Config.apiurl + '/auth/user')
.then(function(response) {
this.user = response.data;
return response.data;
}, function(error) {
return $q.reject(error.data);
});
}
};
}]);
Hope it helps.
You don't have to, $http already caches your request for you, if the same request is applied in case you set the cache config option to true.
$http.get('/hello', { cache: true})
.then(onResponse)
or you can either set it for every request, by using either an interceptor or override the http instance in the $httpProvider, to apply the effect for every http request.
app.module('app.module')
factory('MyHttpInterceptor', function() {
return {
request : function(config) {
config.cache = true;
return config;
},
// rest of implementation of the interceptor
}
});
app.module('app.module')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('MyHttpInterceptor');
// ... rest of the configuration
}]);
Or :
app.module('app.module')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.cache = true;
// ...
}]);
see :
Angular doc for caching

AngularJS - I don't understand why factory is always undefined

I defined a factory that makes a get request but when I inject it in a controller it always throws an undefined error.
This is the factory:
(function() {
'use strict';
var app = angular
.module('myApp');
app.factory('homeFactory', homeFactory);
function homeFactory ($q, $http, $location) {
var data = {};
data.getProducts = getProducts;
function getProducts() {
return $http.get('http://localhost:8000/api/v1/products')
.error(errorMessage);
}
function errorMessage(response) {
console.log('There was an error', response);
}
return data;
}
})();
This is the controller:
(function() {
'use strict';
var app = angular
.module('myApp');
app.controller('homeController', homeController);
homeController.$inject =[homeFactory];
function homeController(homeFactory) {
var home = this;
homeFactory.getProducts()
.success(success);
function success(jsonData, statusCode) {
console.log('The request was successful', statusCode);
console.dir(jsonData);
home.products = jsonData;
}
}
})();
It appears to be ok, but the console throws:
Uncaught ReferenceError: homeFactory is not defined
The problem is in your DI annotation. You should only use strings
homeController.$inject = ['homeFactory'];
See https://docs.angularjs.org/guide/di#-inject-property-annotation
The $inject property is an array of service names to inject.
The controller function supports dependency injection. You don't need to use the $injector directly. Try this:
var app = angular
.module('myApp');
app.controller('homeController', homeController);
function homeController(homeFactory) {
var home = this;
homeFactory.getProducts()
.success(success);
function success(jsonData, statusCode) {
console.log('The request was successful', statusCode);
console.dir(jsonData);
home.products = jsonData;
}
}
The angular runtime will find the homeFactory service, and automatically pass it to your controller function when it's called.
In controller you shall put factory in dependecies
app.controller('homeController', ['homeFactory', '$scope',
function (homeFactory, $scope){
//scope code goes here
}]
);

How to pass data to different controller in my case?

I am trying to create factory for the restful services.
I need to make service calls. First call's data will be used to get the second calls data.
My problem is I don't know how to transfer data from one controller to another controller.
Is there a better way to do my codes?
Here are my codes...
var app = angular.module('myApp', []);
//getting init data via service
app.factory('myService', function($http) {
var myService = {
async: function() {
var promise = $http.get('test/test.json').then(function (response) {
return response.data;
});
return promise;
}
};
return myService;
});
//retrieve data
app.controller('testCtrl', function(myService, $scope, $http) {
myService.async().then(function(data) {
$scope.data = data
//using retrieve data to get another piece of data
vay first = data[0].employee[0];
})
$http({
url: "test?" + first +'.json',
method: "GET",
}).success(function(secondData) {
$scope.secondData=secondData //How do I pass data to my secondCtrl?
})
})
app.controller('secondCtrl', function($scope) {
// I need to be able to get the secondData from testCtrl.
console.log($scope.secondData)
})
Thanks for the help!
Why don't you store the data as an object in the service itself, then both controllers depend on the service and have access to the data. Like this:
app.factory('myService', function($http) {
var that = this;
var myService = function($http) {
this.set = function(url) {
var promise = $http.get(url).then(function (response) {
that.data = promise.data;
});
return promise;
}
};
return new myService($http);
});
Then your controller sets and gets the data in the way
app.controller('testCtrl', function(myService, $scope, $http) {
myService.set('someurl').then(function() {
$scope.data = myservice.data;
//using retrieve data to get another piece of data
vay first = data[0].employee[0];
myservice.set('someOtherUrl?data='+first);
})
app.controller('secondCtrl', function($scope, myservice) {
//the data object on the myservice function has been changed on the first controller and we can reasonably expect the data we need. If these 2 controllers coexist in the same space and time we can wrap this in a $watch service
console.log(myservice.data)
});
$watch service example
app.controller('secondCtrl', function($scope, $watch, myservice) {
$watch('myservice.data', function(newval, oldval) {
console.log(newval);
}, true)
//I will only log the newvalue of myservice.data when the data has changed. the last true argument is a neccesity so that angular will compare the values within the object
});
You could either extend 'myService' to contain the response data, using it in both controllers, or you could create another service for sharing data between them.
Both solutions would look similar, but here is what the second option (new service) might look like:
Factory
.factory('SharedService', function(){
var shared = {
data: ''
}
return shared;
})
This factory could act as just a place to store some data. In fact, if all you'd like to do is share data, you could just use a value provider. But a factory you could later extend with a more complex data structure and methods.
In your controllers, just inject the service and, optionally, set it to a scope variable:
Controller 1
.controller('FirstController', function($scope, SharedService){
$scope.shared = SharedService;
$scope.shared.data = 'foo';
})
$scope.shared now references the service object. If you were to do the same in the other controller, they could both read/write to that same object:
Controller 2
.controller('SecondController', function($scope, SharedService){
$scope.shared = SharedService;
console.log($scope.shared.data); // 'foo' if called after first ctrl set it
})
Demo

Best practice to set up a service or factory for $http contacting to REST API in AngularJS

I've created $http and REST API interface in AnguarJS service as a function that gets injected into different controllers like this:
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
// Method:
this.citiesGet = function() {
this.restCitiesGet().success(function (data) {
console.log(data);
return data;
})
};
}])
console.log(data); returns the right json output when I call citiesGet() .
// Main controller that prints list of cities.
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = appSharedService.citiesGet();
console.log($scope.cities);
}]);
This is my controller injecting my service. console.log($scope.cities); here returns undefined.
$scope.cities value doesn't get changed after route calls this controller.
Is there something wrong with my setup?
Something interesting is that after I change route and come back to this controller again, this time $scope.cities have my REST data and everything's fine.
I think there's something wrong with timing or asynchronous functionality problem here that I'm not aware of.
EDIT:
I could have had $http in my controller and this works all well:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
$http.get('http://localhost/nkhorasaniec7/api/v0/city').success(function (data) {
$scope.cities = data;
});
}]);
But I want to implement helper functions for this.
I would say that the common approach would be to return the promise directly to the controller, much like you have mentioned above by directly using the http request.
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returning the promise
this.citiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
}])
Controller:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
appSharedService.citiesGet().success(function (data) {
$scope.cities = data;
});
}]);
I think you are right about the timing issue. From what I understand, you are getting a promise, that at the moment you do console.log($scope.cities) is not yet resolved.
If you use $scope.cities inside your page, you should see the results as soon as they are loaded. Another option would be to use the promise then function if you really want to log.
$scope.cities = appSharedService.citiesGet().then(function(data) {
console.log(data);
return data;
};
Answering my own question:
I'm trying to make this happen in my a controller defined in my view using ng-controller, not a controller linked to a router (otherwise you could use resolve property like this Delaying AngularJS route change until model loaded to prevent flicker).
And I want to use REST using $http as a factory/service helper function for a cleaner code.
// Global service to share between states
.service("appSharedService", ['$http', '$q', function($http, $q) {
this.citiesGet = function() {
var deferred = $q.defer();
$http({method: 'GET', url: 'http://localhost/nkhorasaniec7/api/v0/city'}).success(function(data) {
deferred.resolve(data);
}).error(function(data, status) {
deferred.reject(data);
});
return deferred.promise;
};
}])
I used angular $q promise here.
// Our main controller that prints list of cities.
.controller('CityList', ['$scope', 'appSharedService', function($scope, appSharedService) {
var promise = appSharedService.citiesGet();
promise.then(
function(data){$scope.cities = data;}
,function(reason){alert('Failed: ' + reason);}
);
}])
And used then function to use that promise.
And now it always updates $scope.cities in any situation that template loads (not just in ng-view)
You can use $q service
.service("appSharedService", ['$http', '$q', function($http, $q) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
var deffered = $q.defer();
$http.get('http://example/nkhorasaniec7/api/v0/city').then(
//success
function(response){
deffered.resolve(response.data);},
//error
deffered.reject();
);
return deffered
};
and after that you can use promise in you controller
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = []
appSharedService.citiesGet().then(
//success
function(result){
angular.copy(result, $scope.cities)
console.log($scope.cities);
},
//error
function(){
console.log("load error");
});
}]);

Categories