i've this factory thar call external api that return an array:
angular.module('starter.services', [])
.factory('PlacesService', function($http) {
var places = "";
var request = $http({
method: "get",
url: 'http://someurl/getPlaces.php'
});
request.then(function (data) {
places = data.response
});
console.log(places); // return empty string
return {
all: function() {
return places;
},
get: function(placesId) {
return places[placesId];
}
}
});
Places variable returned by http is an empty string.
If I initialize places as an array and the I use places.push(data.response) it works, but return an array of array.
Could you help me?
Your log here is outside of the context of the promise the $http call is returning. Basically the log gets executed before the promise is resolved, so your string is still empty when the log executes.
Related
Did not get value for
$scope.objectives.length ..... data to $scope.objectives assigned at the time of page load....
it takes value from database...showing output like this
http is asynchronus. it mean that the code executed in success or error will be after some time.
1) USE THEN for http, success is depreceated !
https://docs.angularjs.org/api/ng/service/$http
2)
when $http is done, call a function who use the $scope.objective :
$http({
method: 'GET',
url: '/getObjective'
}).then(function successCallback(response) {
console.log("test1"); // this will printed after test2 because http is asynchronus
$scope.objective = doc ;
anotherFunction();
}, function errorCallback(response) {
});
console.log("test2");
var anotherFunction = function(){
console.log($scope.objective.length);
}
3) another way is to set a watcher on $scope.objective
$scope.$watch('objective', function (newValue, oldValue, scope) {
console.log(newValue);
});
'Cannot read property length of undefined' error shows due to not initialization of $scope.objectives variable at first. So initialize this to empty array [] at top.
$http.get() is asynchronous function. This means the result or error will be obtained after the response status return back from the server after the succesfull HTTP request.
var myApp = angular.module('routingApp');
myApp.controller('objectiveController', ['$scope', '$http',
function($scope, $http) {
$scope.objectives = [];
$http.get('/getObjective').success(function (doc) {
$scope.objectives = doc;
//gets the actual length of result array
console.log($scope.objectives.length);
}).error(function (error) {
console.log('error');
});
//get the result 0
console.log($scope.objectives.length);
}]);
I have a state defined like this:
.state('list', {
url: '/list',
controller: 'ctrl',
resolve: {
data: ['DataService', function(DataService) {
return DataService.getList();
}]
}
})
The getList of DataService makes the http request:
var httpRequest = $http(categoryRequest);
httpRequest.then(function (response) {
return response.data;
})
.catch(function (error) {
console.log('could not get categories from server');
});
return httpRequest;
In controller I just assign the list to its list property:
function ctrl(data) {
this.list = data.data;
}
The problem:
No matter what I return in success callback of http request, I always get the whole response in resolve of state provider.
So I have to do data.data in controller to get the data from response.
Questions:
Is my assumption true that I will always get the whole reponse in resolve?
How to get just the data form response that I do not have to get it in controller.
Best regards,
var httpRequest = $http(categoryRequest);
So httpRequest is a Promise<Response>
httpRequest.then(function (response) {
This creates another promise, but this new promise is not assigned to anything.
return httpRequest;
This returns the original Promise<Response>.
You want
httpRequest = httpRequest.then(function (response) {
Or simply
return httpRequest.then(function (response) {
So that what you return is the new promise.
To give you a simpler analog example, your code is similar to
var a = 1;
a + 1;
return a;
That returns 1, not 2.
To return 2, you need
var a = 1;
a = a + 1;
return a;
or
var a = 1;
return a + 1;
There are two problems. First, the service is returning the original httpPromise and not the promise derived from the original promise. Second, the error handler is converting the rejection to a success.
var httpRequest = $http(categoryRequest);
//httpRequest.then(function (response) {
var derivedPromise = httpRequest.then(function onSuccess(response) {
//return to chain data
return response.data;
}).catch(function onReject(error) {
console.log('could not get categories from server');
//IMPORTANT to avoid conversion
throw error;
//OR
//return $q.reject(error);
});
//return httpRequest;
return derivedPromise;
The .then method of a promise returns a new promise derived from the original promise. It does not mutate the original promise.
A common problem is the omission of a throw or return $q.reject statement from a rejection handler. Functions without such statements return a value of undefined which will convert a rejection to a success which resolves as undefined.
I have a factory where I'm getting data from a server using the $http methods:
.factory('$factory', function ($q, $http, $timeout, $state, $ionicHistory, $localstorage) {
var obj = [];
var functions = {
getData: function () {
var dfd = $q.defer();
if(!obj){
$http({
url: remoteUrl+'/getdata',
method: 'POST',
data: {}
}).then(function(response) {
$timeout(function(){
obj = response.data;
dfd.resolve(response.data);
}, 2000)
}, function(response) {
}
}else{
return obj;
}
return dfd.promise;
}
}
}
So this gets the data and puts it in an object. Correct me if I'm wrong, but this method of using a factory for this type of action is so it's not tied to a controller, and can be used anywhere in my application.
With this in mind, I wish to make it so I can get the data anywhere in my app without having to query the server each time. i.e. once it's queried the server the factory saves the response to an object (like I'm doing now). But I'm having trouble accessing the data afterwards in another controller for example.
I've started to make what I think it should look like by using the if(!obj) line, but in the else statement I cant seem to just return the obj object. It throws errors as it's not returning a promise like it's expected too.
I'm not sure if I'm even along the right lines with this.
Thanks
You're returning a promise so you need to always return a promise even on the cached response, you can do it relatively easy at this level by wrapping it in a $q.when (https://docs.angularjs.org/api/ng/service/$q) which will return a promise immediately resolved.
return $q.when(obj);
Although $http service has built in caching, so you may want to take a look under the Cache section.
https://docs.angularjs.org/api/ng/service/$http
https://www.ng-book.com/p/Caching/
This should work:
Insteada assigning obj = [] assign as a null. Usually I prefer callback. You can try this code:
.factory('$factory', function($q, $http, $timeout, $state, $ionicHistory, $localstorage) {
var obj = [];
var functions = {
getData: function(cb) {
// instead of checking !obj you have to check for length or you have to set obj as null
if (obj && obj.length == 0) {
$http({
url: remoteUrl + '/getdata',
method: 'POST',
data: {}
}).then(function(response) {
obj = response.data;
cb(response.data)
}, function(response) {
}
}
else {
cb(obj)
}
}
}
}
})
// You can use callback by following code
$factory.getData(function(response){
// response will come here
})
I'm trying to create an AngularJS service, which returns data based on several HTTP requests. But i seem to just not get it to work.
The REST call works as follow:
get /index which returns an array of urls
call each of the url's, and add the result to an array
I expect that at the end of the call of the service function, that i receive a data structure containing all the data from the url's.
My current, somewhat working code uses callbacks, but even though it works in one controller, it does not in another. I want to correctly use promises, but i'm already confused with success vs then.
My service:
// Get a image
obj.getByUrl = function (imageUrl, callback) {
$http.get('https://localhost:9000' + imageUrl).success(function (data) {
callback(data);
});
}
// Get all images
obj.getAll = function(callback) {
$http.get('https://localhost:9000/1.0/images').success(function (data) {
if (data.status != "Success") {
console.log("Err");
}
var images = [];
for(var n=0; n < data.metadata.length; n++) {
var c = data.metadata[n];
obj.getByUrl(c, function(data2) {
images.push(data2.metadata);
});
}
callback(images);
});
}
i'd like to use the service in a controller resolve like this:
resolve : {
images: function(ImagesServices, $route) {
return ImagesServices.getState($route.current.params.containerName)
},
I came as far as this, but it does only return the data of the index call, not the aggregated data:
obj.getAll3 = function() {
var images = [];
var promises = [];
//var httpPromise = $http.get('https://localhost:9000/1.0/images');
var httpPromise = $http({
url: 'https://localhost:9000/1.0/images',
method: 'GET',
});
return httpPromise.success(function(data) {
var data2 = data.metadata[0];
// angular.forEach(data.metadata, function(data2) {
console.log("D11: " + JSON.stringify(data2));
//var inPromise = $http.get('https://localhost:9000' + data2)
var inPromise = $http({
url: 'https://localhost:9000' + data2,
method: 'GET',
})
.success(function (data2) {
console.log("D2: " + JSON.stringify(data2));
images.push(data2);
});
promises.push(inPromise);
// });
return $q.all(promises).then(function() {
return images;
});
});
}
Maybe someone can point me into the right direction?
This is the typical case where chaining promises, and using $q.all(), is adequate:
/**
* returns a promise of array of images
*/
obj.getAll = function() {
// start by executing the first request
return $http.get('https://localhost:9000/1.0/images').then(function(response) {
// transform the response into a promise of images
// if that's not possible, return a rejected promise
if (data.status != "Success") {
return $q.reject("Error");
}
// otherwise, transform the metadata array into
// an array of promises of image
var promises = data.metadata.map(function(imageUrl) {
return $http.get('https://localhost:9000' + imageUrl).then(function(resp) {
return resp.data;
});
});
// and transform this array of promises into a promise
// of array of images
return $q.all(promises);
});
}
This avoid the callback antipattern, and uses chaining. It's a bit long to explain here, but I wrote a blog post that should, hopefully, make the above code clear: http://blog.ninja-squad.com/2015/05/28/angularjs-promises/
I am new to angularjs so I am struggling to pass a parameter to service method from controller.
My controller looks like this:
userControllers.controller('StartController', function(startService,$scope) {
var server='http://localhost:8080/terminal/1';
// Call the async method and then do stuff with what is returned inside our own then function
startService.async().then(function(d) {
$scope.message = d;
});
});
Service method:
myService.factory('startService', function($http) {
var startService = {
async: function () {
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http.get('http://localhost:8080/terminal/1').then(function (response) {
// The then function here is an opportunity to modify the response
console.log(response.headers('link'));
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
}
};
return startService;
});
And this code works fine. Now I want to pass variable 'server' from controller to be used in service instead of link. Any idea how to do that? How to use more than one variable in service function call?
Updated code is in between ** **
userControllers.controller('StartController', function(startService,$scope) {
var server='http://localhost:8080/terminal/1';
// Call the async method and then do stuff with what is returned inside our own then function
**startService.async(server).then(function(d) {**
$scope.message = d;
});
});
myService.factory('startService', function($http) {
var startService = {
async: **function (server) {**
// $http returns a promise, which has a then function, which also returns a promise
var promise = **$http.get(server)**.then(function (response) {
// The then function here is an opportunity to modify the response
console.log(response.headers('link'));
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
}
};
return startService;
});