Angular factory with $http [duplicate] - json

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I am writing a factory that calls a JSON feed and returns the results.
Here is the factory using $http
nearestLocationApp.factory("allTheLocationsFactory", function($http){
var locations = "Not sure why it don't work";
$http.get('/json/locations/').then(function(res){
locations = res.data;
});
return locations;
});
When I include this in the controller I get the first version of the locations variable. It's like there are 2 different scopes here. I am pretty sure that's my problem but I don't know why.
Here is me calling and printing out the console.log for the controller.
nearestLocationApp.controller("getTheLocation", function($scope, allTheLocationsFactory){
$scope.locationResponse = "Find your location";
$scope.locations = allTheLocationsFactory;
console.log($scope.locations);
});
What I need to know is why I have multiple scopes in my factory and how to fix it.
If anyone is interested the JSON data looks like this.
[
{
"Name":"#########",
"ID":#########,
"address1":"#########",
"address2":"#########",
"city":"#########",
"state":"#########",
"zip":"#########",
"phoneNumber":"#########",
"thumbnail":[
"#########",
#########,
#########,
#########
],
"permalink":"#########",
"weekdayHours":"#########",
"saturdayHours":"#########",
"sundayHours":"#########",
"coords":{
"longitude":"#########",
"latitude":"#########"
},
"options":{"animation":#########}
}, ......

You are dealing with asynchronous call, that gets data asynchronously for you. In this Your factory should return $http promise & you could get that promise inside your controller and put .then function, That will get call when the factory $http returns a locations from it success callback.
Factory
nearestLocationApp.factory("allTheLocationsFactory", function($http){
return $http.get('/json/locations/').then(function(res){
return res.data;
});
});
Controller
nearestLocationApp.controller("getTheLocation", function($scope, allTheLocationsFactory){
allTheLocationsFactory.then(function(data){
$scope.locations = data;
console.log($scope.locations);
})
});

Your factory instance should ideally return a promise instance that can be resolved either within a controller or ideally within a routers resolve option.
nearestLocationApp.factory("allTheLocationsFactory", function($http){
var jsonURL = '/json/locations/',
getLocations = function(){
return $http.get(jsonURL).then(function(result){
return result.data;
});
};
return {
getLocations: getLocations
};
});
Then within your application config or router something like;
var nearestLocationsApp = angular.module('myApp', [
'ngRoute'
])
.config(function($routeProvider) {
$routeProvider.when("/", {
templateUrl: "templates/someTemplate.html",
controller:'SomeCtrl',
controllerAs: 'ctrl',
resolve: {
locations: function(allTheLocationsFactory) {
return allTheLocationsFactory.getLocations();
}
}
});
});
And within your controller something similar to;
nearestLocationApp.controller('someController', [
'$scope',
'allTheLocationsFactory',
'locations',
function($scope, allTheLocationsFactory, locations) {
$scope.locations = locations;
}
]);
Or without using the resolve option in your router;
nearestLocationApp.controller('someController', [
'$scope',
'allTheLocationsFactory',
function($scope, allTheLocationsFactory) {
allTheLocationsFactory.getLocations().then(function(res) {
$scope.locations = res;
});
}
]);
The former option is one I personally prefer rather to relying on promises within the controller. You can check out some other useful angular tips here
Hope some of that helps you out!

Related

Login Service implementation in angularjs not working

This is my controller which is calling the login service
mod.controller("loginCtrl",function($scope,loginService,$http)
{
$scope.Userlogin = function()
{
var User = {
userid :$scope.uname,
pass:$scope.pass
};
var res = UserloginService(User);
console.log(res);
alert("login_succ");
}
});
And this is the login service code which takes the User variable and checks for username & password
mod.service("loginService",function($http,$q) {
UserloginService = function(User) {
var deffered = $q.defer();
$http({
method:'POST',
url:'http://localhost:8080/WebApplication4_1/login.htm',
data:User
}).then(function(data) {
deffered.resolve(data);
}).error(function(status) {
deffered.reject({
status:status
});
});
return deffered.promise;
// var response = $http({
//
// method:"post",
// url:"http://localhost:8080/WebApplication4_1/login.htm",
// data:JSON.stringify(User),
// dataType:"json"
// });
// return "Name";
}
});
I have created a rest api using springs which upon passing json return back the username and password in json like this
Console shows me this error for angular
You need to enable CORS for your application for guidance see this link
https://htet101.wordpress.com/2014/01/22/cors-with-angularjs-and-spring-rest/
I prefer to use Factory to do what you're trying to do, which would be something like this:
MyApp.factory('MyService', ["$http", function($http) {
var urlBase = "http://localhost:3000";
return {
getRecent: function(numberOfItems) {
return $http.get(urlBase+"/things/recent?limit="+numberOfItems);
},
getSomethingElse: function(url) {
return $http.get(urlBase+"/other/things")
},
search: function (searchTerms) {
return $http.get(urlBase+"/search?q="+searchTerms);
}
}
}]);
And then in your controller you can import MyService and then use it in this way:
MyService.getRecent(10).then(function(res) {
$scope.things = res.data;
});
This is a great way to handle it, because you're putting the .then in your controller and you are able to control the state of the UI during a loading state if you'd like, like this:
// initialize the loading var, set to false
$scope.loading = false;
// create a reuseable update function, and inside use a promise for the ajax call,
// which is running inside the `Factory`
$scope.updateList = function() {
$scope.loading = true;
MyService.getRecent(10).then(function(res) {
$scope.loading = false;
$scope.things = res.data;
});
};
$scope.updateList();
The error in the console shows two issues with your code:
CORS is not enabled in your api. To fix this you need to enable CORS using Access-Control-Allow-Origin header to your rest api.
Unhandled rejection error, as the way you are handling errors with '.error()' method is deprecated.
'Promise.error()' method is deprecated according to this and this commit in Angular js github repo.
Hence you need to change the way you are handling errors as shown below :
$http().then(successCallback, errorCallback);
function successCallback (res) {
return res;
}
function errorCallback (err) {
return err;
}
One more thing in your code which can be avoided is you have defined a new promise and resolving it using $q methods, which is not required. $http itself returns a promise by default, which you need not define again inside it to use it as a Promise. You can directly use $http.then().

Angular factory does not return array of objects but a single object

I am new to angular and I am trying to load a CSV list inside a factory and then convert it to json. I am using Papaparse (CSV to json library) inside the factory. When I console log the factory I get the array of objects which is exactly what I want but when I pass it inside my controller I get a single object which holds all the data.
This is my factory
(function() {
var app = angular.module('test');
app.factory('testFactory', ['$http', function($http) {
var url = 'my-list.csv';
var getContact = function() {
return $http.get(url).success(function(data) {
Papa.parse(data, {
header: true,
complete: function(results) {
console.log(results.data);
return results.data;
}
});
});
};
return {
getContact: getContact
};
}]);
}());
And this is my controller
(function() {
var app = angular.module('test');
app.controller('testCtrl', ['$scope', 'testFactory', function($scope, testFactory) {
testFactory.getContact().then(function(data) {
$scope.contacts = data;
console.log(data);
});
}]);
}());
I want be able to do something like this inside my view
{{ contact.firstname }}
The issue is the order of resolution. Inspecting the console statements shows that you're assigning $scope.contacts to the resolution of the $http.get promise, and not the actual parsing.
Instead of returning the $http.get promise, return a deferred promise and resolve at the end of parsing:
var parsePromise = $q.defer();
$http.get(url).success(function(data) {
Papa.parse(data, {
header: true,
complete: function(results) {
console.log(results.data);
parsePromise.resolve(results.data);
}
});
});
return parsePromise.promise;
See working demo here.
Update: As per the comments, you could use .then to chain promises instead of creating a new deferred. The plunkr has both, you can use the changelog to toggle methods.

Caching JSON with AngularJS [duplicate]

This question already has answers here:
AngularJS : Initialize service with asynchronous data
(10 answers)
Closed 8 years ago.
I'm loading JSON in my controller, changing routes the JSON gets reloaded. I would like to cache it.
var sampleApp = angular.module('sampleApp', [
'ngRoute',
'sampleAppControllers',
]);
var sampleControllers = angular.module('sampleControllers', []);
sampleControllers.controller('PostsCtrl', ['$scope', '$http',
function($scope, $http) {
// Should be loaded only on app load
$http.get('http://example.org/source.json').success(function(data) {
$scope.posts = data;
});
$scope.orderProp = 'id';
}]);
I tried using .constant, but couldn't get it work:
sampleApp.constant('myCache', ['$http',
function($http) {
$http.get('http://example.org/source.json').success(function(data) {
return data;
});
}]);
sampleControllers.controller('PostsCtrl', ['$scope', 'myCache',
function($scope, myCache) {
$scope.posts = myCache;
$scope.orderProp = 'id';
}]);
I'm looking for a way to load JSON on app start, and use it in controllers.
That's what Angular Services are for - load the data inside the service instead of inside the controller, and have the controller access this data. Services are instantiated once in the lifetime of an app, which is exactly what you want here.

Fetching data from a JSON object (from a given API) in AngulaJS

I have the following code to present data from a link (API) as suggestion for an autocomplete box. Although it is working for one link and not the other. I observed that data format for both are different, modified my code accordingly but it is still not helpful.
.js file:
var plunker= angular.module('plunker', ['ui.bootstrap', 'ngGrid']);
function TypeaheadCtrl($scope, $window, $http, limitToFilter) {
$scope.cities = function (cityName) {
return $http.jsonp("http://mtapi.azurewebsites.net/api/institute").then(function (response) {
return response[0].description;
});
};
}
HTML file:
<input type="text" id="depn" ng-model="formdata.department"
typeahead="suggestion.description for suggestion in cities($viewValue)"
placeholder="department" class="form-control">
If you replace the cities function with this one,
$scope.cities = function (cityName) {
return $http.jsonp("http://gd.geobytes.com/AutoCompleteCity?callback=JSON_CALLBACK &filter=US&q=" + cityName).then(function (response) {
return response.data;
});
};``
Even after I changed my code jsonP request to .get, it is still not working
var plunker= angular.module('plunker', ['ui.bootstrap', 'ngGrid']);
function TypeaheadCtrl($scope, $window, $http, limitToFilter) {
$scope.cities = function (cityName) {
return $http.get("http://mtapi.azurewebsites.net/api/institute").success(function(data) {
return data[0].description;
});
};
}
It is working fine.
Is there a problem with my code, or a back end server issue?
Change your cities function to use the data property of the response in your .then (that's how you'll access the response from a resolved HttpPromise):
var plunker= angular.module('plunker', ['ui.bootstrap', 'ngGrid']);
function TypeaheadCtrl($scope, $window, $http, limitToFilter) {
$scope.cities = function (cityName) {
return $http.get("http://mtapi.azurewebsites.net/api/institute").then(function (response) {
return response.data[0].description;
});
};
EDIT
Even making that code change won't solve your problem. This url does not support cross-origin requests, so you either need to host your angularjs app on the same domain and use a plain $http.get instead of $http.jsonp, or this url needs to support JSONP requests (the content-type of the response from this url is application/json. For JSONP to work it should be application/javascript).
I figured it out lately. Apart from the problem at back end there were issues in this code as well. I was returning the promise, but promise was never resolved to return the value also I was trying to return a string, whereas I should return array of strings. Here's the change:
$scope.aap = result.data;
var res = [];
res.push($scope.aap[0].Description);
return res;

Angularjs $resource and $http synchronous call?

I want write two services one with a $http.get method and one with $resource
This service should receive a Json Object and looks like this, at the moment this code is direct in my controller and not in a service:
var csvPromise= $http.get(base_url + 'DataSource/1').success(function(data) {
$scope.data4=JSON.stringify(data);
});
The problem is, I want save received data in $scope.data4 and I want use this data after the $http.get call but the value is empty.
Direct after this call there is and Object that needs this value:
new myObject($scope.data4)
so myObject must wait so long until the data has arrived.
or can I make a synchronous call with $http or $resource ?
How can i do this ? I have found so many examples with promise and .then but nothing has worked for me.
EDIT: I have now written a service but it didn`t work:
var test=angular.module('myApp.getCSV', ['ngResource']);
test.factory('getCSV',function($log, $http,$q, $resource){
return {
getData: function (id) {
var csvPromise= $http.get(base_url +'DataSource/'+id)
.success(function(data) {
return data;
});
return csvPromise;
}
}
});
and then in my controller I call this:
getCSV.getData(1).then(function(theData){
$scope.data4=JSON.stringify(theData);
new myObject( $scope.data4); });
but this did not work. I thought if the $http.get receives the data then the then Function is called.
I don't believe you can do synchronous calls. That said, you have at least two options:
1) Pass in the data using the $routeProvider resolve feature. From the documentation:
An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected
An example on how to use this:
$routeProvider
.when('/your/path', {
templateUrl: '/app/yourtemplate.html',
controller: 'yourController',
resolve: {
data: ['$route', '$http', function($route, $http) {
return $http.get(base_url +'DataSource/1');
}]
}
})
And then in your controller:
app.controller('yourController', ['$scope', 'data', function($scope, data) {
$scope.data4 = JSON.stringufy(data);
var yourObj = new myObject($scope.data4);
}]);
2) The second option is to use promises and only instantiate your new myObject($scope.data4) once the promise successfully completes.
Your code needs to be changed just a bit:
$scope.data4 = '';
var csvPromise= $http.get(base_url +'DataSource/1');
csvPromise.then(function(data){
$scope.data4 = JSON.stringify(data);
}, function(data){
//error handling should go here
window.alert(data);
});
This should give you what it sounds to me like you need.
As i know, there's no way to sync~ call the http or resource. They're hard coded on AngularJS core file :
xhr.open(method, url, true);
And you don't want to hurt your users too by blocking the browser wait the data arrived. You'll better show how you make the nothing has worked for me so we can start working to fix it.
Have you try call new myObject($scope.data4) inside success method?
$http.get(...).success(function(data){
$scope.data4 = JSON.stringify(data); // I've no idea why do you need this.
var stuff = new myObject($scope.data4); // THis is now your.
});