I would like to log if there is no data in some returned Javascript object. Since http calls are asynchronous, my implementation doesn't work. I'm checking if the object is empty and if it is, I would like to log it's id. How could I get the right scenarioId to my else statement?
for (var i in $scope.scenarioData){
var scenarioId = $scope.scenarioData[i].id;
dataService.getResultsByScenarioId(scenarioId).then(function(response){
if (Object.keys(response.data).length != 0){
//This is not interesting in this context
}
else{
//I would like to log the called scenarioId here
$log.info("No data in scenarioId: " + scenarioId);
}
});
}
This is the used service
ptraApp.service('dataService', function($http) {
this.getResultsByScenarioId = function(id) {
return $http({
method: 'GET',
url: '/ptra/resultArchive/' + id,
});
}
});
Extract the function that call to servive to external function
for example:
for (var i in $scope.scenarioData){
var scenarioId = $scope.scenarioData[i].id;
getResult(scenarioId)
}
function getResult(scenarioId){
dataService.getResultsByScenarioId(scenarioId).then(function(response){
if (Object.keys(response.data).length != 0){
//This is not interesting in this context
}
else{
//I would like to log the called scenarioId here
$log.info("No data in scenarioId: " + scenarioId);
}
});
}
Should be something like that snippet:
ptraApp.service('dataService', function($http) {
this.getResultsByScenarioId = function(id) {
return $http({ method: 'GET', url: '/ptra/resultArchive/' + id}).
success(function (data, status, headers, config) {
console.log(data);
}).
error(function (data, status, headers, config) {
// ...
);
}});
Related
I am trying to call an http service within a for loop through a function (callAPI).
Here is my code. The problem I am having with this code is that I don't get the correct id called in the right order when the http service catches up. On the callAPI function it goes through all the calls of console.log(id) before even running one http service async request then it runs the http service calls but with the wrong order of id's..For instance I get back an array of [6,6,3] and it runs it in the order of [3,6,6]. Any help is appreciated.
for (var i = 0; i < idArray.length; i++) {
callAPI(idArray[i]);
}
function getItems() {
return self.choices;
}
function callAPI(id) {
console.log(id);
$http({
method: 'GET',
url: '/api/organizations/' + orgID + '/' + id + '/meal'
}).success(function (data) {
console.log(id);
console.log(data);
// idLocal = id;
angular.forEach(data, function(value,key) {
angular.forEach(value, function(value,key) {
angular.forEach(value, function(value,key) {
if (key == 'description') {
items.push(value);
}
if (key == 'drop_name') {
self.dropName = value;
}
});
});
});
self.choices.push({
id: id,
choice: items,
dropname: self.dropName
});
items = [];
getItems();
}).error(function (data) {
console.log('failed');
});
}
I prefer to do something like this but there are multiple other solutions:
//set index
var index = 0;
function callAPI(id) {
//increment index
index++
$http({
method: 'GET',
url: '/api/organizations/' + orgID + '/' + id + '/meal'
}).success(function (data) {
//call function again with next index if exists
if (index <= idArray.length) {
callAPI(idArray[index])
}
}).error(function (data) {
console.log('failed');
});
}
//call function with 0 index
callApi(idArray[index])
This will run one async request, when that is returned then run the next. You can of course handle the return data any way you want. Also, as mentioned using the promise library included with angular "q" is another good option.
EDIT : i get an error like this when i last checked in browser console.
TypeError: Cannot read property 'defer' of undefined
I need to call one $http request which gives the token that can be used to call another $http request and finally the required response.
Hence i am using promises to make it work synchronously.However the function does not get executed after the $q.defer() function
Following is my code:
$scope.firstTimeAuth = function($q) {
var deferred = $q.defer();
var ref = window.open('https://accounts.google.com/o/oauth2/auth?client_id=' + clientId + '&redirect_uri=http://localhost/callback&scope=https://www.googleapis.com/auth/fitness.activity.write &approval_prompt=force&response_type=code&access_type=offline', '_blank', 'location=no');
ref.addEventListener('loadstart', function(event) {
if((event.url).startsWith("http://localhost/callback")) {
requestToken = (event.url).split("code=")[1];
$http({
method: "post", url: "https://accounts.google.com/o/oauth2/token",
data: "client_id=" + clientId + "&client_secret=" + clientSecret + "&redirect_uri=http://localhost/callback" + "&grant_type=authorization_code" + "&code=" + requestToken
})
.success(function(data) {
defer.resolve(true);
accessToken = data.access_token;
refreshToken = data.refresh_token;
alert("firstTimeAuth success");
if(typeof(Storage) != "undefined") {
localStorage.setItem("refreshToken",refreshToken);
alert(localStorage.getItem("refreshToken"));
} else {
alert("Sorry, your browser does not support Web Storage...");
}
//functions here
})
.error(function(data, status) {
alert("ERROR: " + data);
defer.resolve(true);
});
ref.close();
}
});
return deferred.promise;
}
This is my second function
$scope.getAcessToken = function($q)
{
var deferred = $q.defer();
alert("inside getAcessToken function");
refreshToken = localStorage.getItem("refreshToken");
if(refreshToken)
{
$http({
method: "post", url: "https://accounts.google.com/o/oauth2/token",
data: "client_secret=" + clientSecret + "&grant_type=refresh_token" + "&refresh_token="+ refreshToken + "&client_id=" + clientId
})
.success(function(data){
accessToken = data.access_token;
alert("getAcessToken success" + accessToken);
deferred.resolve(true);
})
.error(function(data,status){
alert("ERROR: " + JSON.stringify(data) + status);
deferred.resolve(true);
});
}
else
{
$scope.firstTimeAuth();
}
return deferred.promise;
}
and i call them like this.
alert("not installed");
var lastSaved = $scope.getFirstEpochTime();
//walkthroug
//Registe
$scope.firstTimeAuth().then(function(){
alert("firstime done");
$scope.getDataSets().then(function(){
alert(" in the last block");/*
$scope.handleResponse().then(function(){
$scope.insert().then(function(){
$scope.select();
})
alert("done in installed");
})
*/})
})
Please let me know what is wrong with the code. i am very new to this.. thanks.
Are you injecting $q in your controller at first place.
angular.module('module.name').controller('ControllerName',
['$scope', '$q', function ($scope, $q) {
}]);
I am not really getting why are you passing $q to your function, you don't need that to be. $scope.firstTimeAuth = function($q) {
By defining a parameter for a function, you're creating a local variable which hides anything with the same name in outer scope. In your case you're defining:
$scope.firstTimeAuth = function($q) {}
And then you're invoking it like $scope.firstTimeAuth(); in many places. Since you don't pass anything, $q in the functions scope will be undefined. You should only inject it in the entire controller scope and remove such parameters specified in scope methods so that it doesn't hide the injected service.
Or if you must pass them around for some reason, do it properly.
how to access the response inside controller from a nested $http which is inside a factory. here we are having two service calls.one inside another.I need the response of the second service call in my controller. I am able to access the factory from controller and also the response inside the factory but when comes to controller success function, it's showing success function is not defined.
factory code : here i am calling nested $http service calls
bosAppModule.factory("ServiceCalls",function($http){
var ServiceCalls={};
var createFilterString = function(crudObject, callback) {
var filterString = "";
var keyValuePairs = [];
// iterate over the property
for(var property in crudObject) {
if(!(crudObject[property] instanceof Object)) {// if it is primitive type
// check the value is not null or undefined
if(crudObject[property] && crudObject[property] != "")
// added the key value string
keyValuePairs.push(property + "~;~" + crudObject[property]);
}
}
// add first key value pair
if(keyValuePairs[0])
filterString += keyValuePairs[0];
// iterate over the key value strings
for(var i = 1; i < keyValuePairs.length; i++) {
filterString += "~$~" + keyValuePairs[i];
}
try {
if(callback) callback(filterString);
} catch(e) {
console.log("Exception inside $dataTransactor->createFilterString" + e.message);
}
};
// var headers = {Authorization: COOKIES.readCookie("Authorization"),requestmode:"ACK_URL"};
// headers.isRender = file.isRender;
// if(file.inputDataHeaders)
// headers.inputData = file.inputDataHeaders;
ServiceCalls.getData = function(filterObject, file){
createFilterString(filterObject, function(filterString){
var headers = {Authorization: COOKIES.readCookie("Authorization"),requestmode:"ACK_URL"};
headers.isRender = file.isRender;
if(file.inputDataHeaders)
headers.inputData = file.inputDataHeaders;
$http({
method: 'GET',
url: file.fileUrl + "/" + $securityComponent.cryptograghicFunctions.encryptor(filterString),
headers: headers
})
.then(function(requestHandlerResponce) {
console.log(requestHandlerResponce);
$http({
method: 'GET',
url: requestHandlerResponce.data.links[1].href,
headers: headers
}).then(function(responceHandlerResponce) {
console.log("##### : "+JSON.stringify(responceHandlerResponce.data));
return responceHandlerResponce;
});
})
});
};
return ServiceCalls
});
controller code : here I need the response
bosAppModule
.controller(
"custom-entity-design-ctrl",
function($scope, $document, $http, $localStorage, navigateEntityUrl, entityFormation,layoutDesignFactory, ServiceCalls) {
var layoutDesignFac=new layoutDesignFactory();
var entityJson='{"entityInfo":{"entity":"","tenantId":"2b69af63-e2dc-43e5-9f0e-9fde52032d4c","timeStamp":"Tue Jun 16 2015 19:05:09 GMT+0530 (India Standard Time)"},"collections":{"Entity":{"meta":{"parentReference":"***","pkName":"***","fkName":"***"},"rowSet":[],"rowFilter":[]}}}';
var crudObject = {};
var file = {
fileUrl: $config.UIMetaData,
inputDataHeaders: entityJson
};
ServiceCalls.getData(crudObject,file).success(function(response){console.log(response)});
});
Your services should be returning the promises (the $http call in your case) to the controller:
return $http({ // return this promise
method: 'GET',
url: file.fileUrl + "/" + $securityComponent.cryptograghicFunctions.encryptor(filterString),
headers: headers
}).then(function(requestHandlerResponce) {
console.log(requestHandlerResponce);
return $http({ // return this promise as well
method: 'GET',
url: requestHandlerResponce.data.links[1].href,
headers: headers
}).then(function(responceHandlerResponce) {
console.log("##### : "+JSON.stringify(responceHandlerResponce.data));
return responceHandlerResponce;
});
And just to be consistent try to use the standard .then method rather than .success or .error in your controller:
ServiceCalls.getData(crudObject,file).then(function(response) {
console.log(response)
});
Last somewhat irrelevant note, I think 'response' is misspelled in your service ;)
here is a piece of code I am struggling with - I have a controller (zmApp.MonitorCtrl) that is calling a factory (ZMFactory) with an HTTP request.
The problem I am facing is this:
a) When the controller calls ZMFactory.getMonitors() it returns undef and I get an error
ERROR: Error: undefined is not an object (evaluating 'ZMFactory.getMonitors().then')
b) After this error comes up, the http request in the factory is processed
I am a little confused. Can you please check if the factory has been set up correctly to return a promise?
var app = angular.module('zmApp.controllers');
app.controller('zmApp.MonitorCtrl', function($ionicPlatform, $scope,$http,ZMFactory)
{
$scope.monitors=[];
console.log("***CALLING FACTORY");
ZMFactory.getMonitors().then(function(data)
{
$scope.monitors = data;
console.log ("I GOT " +$scope.monitors);
});
});
app.factory('ZMFactory',['$http', '$rootScope',function($http,$rootScope)
{
//var factory = {};
var monitors =[];
return {
getMonitors: function()
{
console.log("***MAKING REQUEST");
$http({
url:'http://myurl.com:9999/zm/index.php?skin=xml',
method:'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*',
},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
var foo= str.join("&");
console.log ("****RETURNING "+foo);
return foo;
},
transformResponse: function(data)
{
var x2js = new X2JS();
var json = x2js.xml_str2json(data);
console.log ("***Transmogrifying XML to JSON");
return json;
},
data: {username:'xxx',
password:'xxxx',
action:'login',
view:'console'}
}) //http
.success (function(data)
{
console.log("****YAY"+JSON.stringify(data));
var subobj =data.ZM_XML.MONITOR_LIST.MONITOR;
var len = subobj.length;
for (var i =0; i< len; i++)
{
console.log ("HERE " + subobj[i].NAME);
monitors.push(subobj[i]);
}
// $rootScope.$broadcast ('handleZoneMinderMonitorsUpdate',monitors);
return monitors;
}) //success
.error(function(data, status, headers, config)
{
console.log("***OOPS "+status + " H: "+data);
return monitors;
});
} //getMonitors
};//return
console.log ("**** NEVER *****");
}]);
The key to the answer is in the wording of your own question:
Can you please check if the factory has been set up correctly to return a promise
You need to return it. Right now your getMonitors function (if I remove all the code irrelevant to the question) is as follows:
getMonitors: function(){
$http({})
.success(function(data){
// convert data to monitors
return monitors;
});
}
This is a function call that doesn't return anything, or rather, returns undefined. There is no "magic" with promises - it's just as any other object - you need to return it to the caller.
So, two things you need to do:
1) Change from .success to .then. .then generates a new chained promise that delivers, when returned, the monitors to the consumer (that you are returning in the .then handler). On the other hand, .success returns the original promise (generated by $http) and data returning from .success is lost.
2) Actually return the $http call (or, rather, $http().then() call)
Here's conceptually how this would look like:
app.factory('ZMService', function ZMServiceFactory($http){
return {
// getMonitors function of the ZMService service
getMonitors: function(){
return $http({})
.then(function(response){
var data = response.data;
// convert data to monitors
return monitors;
});
}
};
});
(also, noticed how I renamed your service from ZMFactory to ZMService. A "factory" in the name is a misnomer. The factory is the function that generates the instance - hence "the factory" - but the instance itself is an object, which is called a "service" in Angular)
try with this,here i am returning the promise as is
var app = angular.module('zmApp.controllers');
app.controller('zmApp.MonitorCtrl', function($ionicPlatform, $scope,$http,ZMFactory)
{
$scope.monitors=[];
console.log("***CALLING FACTORY");
ZMFactory.getMonitors().then(function(data)
{
$scope.monitors = data;
console.log ("I GOT " +$scope.monitors);
});
});
app.factory('ZMFactory',['$http', '$rootScope',function($http,$rootScope)
{
//var factory = {};
var monitors =[];
return {
getMonitors: function()
{
return $http({
url:'http://myurl.com:9999/zm/index.php?skin=xml',
method:'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*',
},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
var foo= str.join("&");
console.log ("****RETURNING "+foo);
return foo;
},
transformResponse: function(data)
{
var x2js = new X2JS();
var json = x2js.xml_str2json(data);
console.log ("***Transmogrifying XML to JSON");
return json;
},
data: {username:'xxx',
password:'xxxx',
action:'login',
view:'console'}
}) //http
.then(function(data)
{
console.log("****YAY"+JSON.stringify(data));
var subobj =data.ZM_XML.MONITOR_LIST.MONITOR;
var len = subobj.length;
for (var i =0; i< len; i++)
{
console.log ("HERE " + subobj[i].NAME);
monitors.push(subobj[i]);
}
// $rootScope.$broadcast ('handleZoneMinderMonitorsUpdate',monitors);
return monitors;
},function(error)
{
return error;
});
}
};
}]);
I am getting the following error when I attempt to get a typeahead values from AngularUI-Bootstrap, using a promise.
TypeError: Cannot read property 'length' of undefined
at http://localhost:8000/static/js/ui-bootstrap-tpls-0.6.0.min.js:1:37982
at i (http://localhost:8000/static/js/angular.min.js:79:437)
at i (http://localhost:8000/static/js/angular.min.js:79:437)
at http://localhost:8000/static/js/angular.min.js:80:485
at Object.e.$eval (http://localhost:8000/static/js/angular.min.js:92:272)
at Object.e.$digest (http://localhost:8000/static/js/angular.min.js:90:142)
at Object.e.$apply (http://localhost:8000/static/js/angular.min.js:92:431)
at HTMLInputElement.Va.i (http://localhost:8000/static/js/angular.min.js:120:156)
at HTMLInputElement.x.event.dispatch (http://localhost:8000/static/js/jquery-1.10.2.min.js:5:14129)
at HTMLInputElement.v.handle (http://localhost:8000/static/js/jquery-1.10.2.min.js:5:10866)
My HTML tag is:
<input type="text" class="form-control" id="guestName" ng-model="name" typeahead="name for name in getTypeaheadValues($viewValue)">
With my getTypeaheadValues function doing the following:
$scope.getTypeaheadValues = function($viewValue)
{
// return ['1','2','3','4'];
$http({
method: 'GET',
url: 'api/v1/person?name__icontains=' + $viewValue
}).error(function ($data) {
console.log("failed to fetch typeahead data");
}).success(function ($data) {
var output = [];
$data.objects.forEach(function (person)
{
output.push(person.name);
});
console.log(output);
return output;
});
}
I do not understand what AngularUI-Bootstrap is complaining about as being undefined. If I remove the comment on the top-most return the values show up fine. The console.log output in the success also return all the values I'm expecting in an array.
What am I missing that would cause AngularUI-Bootstrap not see the returned array?
This problem was two fold.
The first is that I was not returning the promise event (the $http call). The lack of a return statement (as #tobo points out) is what was causing the error directly. I needed to be returning the promise though, not the array.
The second is that I need to be using .then rather than .success for AngularUI-Bootstrap to pick up the results.
I ran across the following question:
How to tie angular-ui's typeahead with a server via $http for server side optimization?
Which updated my function call to the below:
$scope.getTypeaheadValues = function($viewValue)
{
return $http({
method: 'GET',
url: 'api/v1/person?name__icontains=' + $viewValue
}).then(function ($response) {
var output = [];
console.log($data);
$response.data.objects.forEach(function (person)
{
output.push(person.name);
});
console.log(output);
return output;
});
}
$scope.getTypeaheadValues is not returning any array. It returns null, because
your return statement is in the callback function "success", which is called asynchrony.
Maybe this will work:
$scope.getTypeaheadValues = function($viewValue)
{
var output = [];
$http({
method: 'GET',
url: 'api/v1/person?name__icontains=' + $viewValue
}).error(function ($data) {
console.log("failed to fetch typeahead data");
}).success(function ($data) {
$data.objects.forEach(function (person)
{
output.push(person.name);
});
console.log(output);
});
return output;
}
$scope.getTypeaheadValues = function($viewValue)
{
var someOutput="";//return something
$http({
method: 'GET',
url: 'api/v1/person?name__icontains=' + $viewValue
}).error(function (data) {
console.error(data);
}).success(function (data) {
console.log(data);//Do whatever you want
});
return someOutput;
}
//The return statement is missing