Promise in javascript, function does not get executed after using $q.defer - javascript

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.

Related

Controller --- Factory: passing parameters

I have this function in my controller :
$scope.goToPath = function ( path, pid ) {
$scope.pid = pid;
console.log("scope pid : " + $scope.pid);
$scope.edit = true;
$state.go(path);
};
then i'm calling this function to get a promise from my factory :
$scope.getProjectById = function () {
projectFactory.getProject($scope.pid)
.success(function (data) {
if(data == null){
$scope.errorMessage = "Le projet avec l'id : " + pid + " n'existe pas";
}else {
$scope.project = data;
}
})
.error(function (data, status, headers, config) {
$scope.errorMessage = "Erreur : " + data.error + ' ' + status;
})
};
And my Factory looks like this :
factory.getProject = function (projectId) {
console.log('Project Id factory : '+projectId);
return $http.get('http://localhost:8080/gestionprojet/Project/' + projectId)
};
return factory;
but the variable here projectId is null, now I've checked as your see with console.log() and the pid in my controller has a value but in the factory it's equal to null.
In my view I'm calling it like :
ng-init="getProjectById()"
Any help would be appreciated. Thank you
With this scenario,your current scope is getting destroyed and new scope is getting creates.So,pid assigned to scope is also getting destroyed.
You can do like this one.
In function $scope.goToPath,
$scope.goToPath = function(path, pid ){
....
$state.go(path,{project_id:pid })
}
And in the target controller where your view is getting landed,
access it using $stateParams by injecting it.
You can refer here angular-ui routing

what is wrong with this code in angular?

In my console the error is coming "getIdData is not defined" what is wrong with my code. Here deal is my service and getIdData is my function in service.
$scope.editUserDetail = function editUserDetail(){
$scope.showEditView = !$scope.showEditView;
$scope.showSubmitView = !$scope.showSubmitView;
console.log(deal);
deal.getIdData().then(function successCb(data){
$scope.editIdOptionsData=data;
});
};
Please check working example here: Demo
You are forget to return service object from service.
i.e
Write following code in your service,
return service;
i.e
angular.module('account').service('deal', function deal($http, accountConfiguration, $q, $log, httpHelper) {
var service = {};
var baseUrl = account.app.url;
service.getIdData = function(data, accountId, decisionMakerDetail) {
var def = $q.defer();
var url = baseUrl + '/api/accountsusers/' + accountId + '?role=' + decisionMakerDetail;
httpHelper._$http({
method: 'post',
url: url,
data: data,
def: def
}, function(resp) {
def.resolve(resp.msg);
});
return def.promise;
};
return service;
});
Or as you are using service you can write it using this
angular.module('account').service('deal', function deal($http, accountConfiguration, $q, $log, httpHelper) {
var baseUrl = account.app.url;
this.getIdData = function(data, accountId, decisionMakerDetail) {
var def = $q.defer();
var url = baseUrl + '/api/accountsusers/' + accountId + '?role=' + decisionMakerDetail;
httpHelper._$http({
method: 'post',
url: url,
data: data,
def: def
}, function(resp) {
def.resolve(resp.msg);
});
return def.promise;
};
});
For more information please check - Services
Please clean your browser and inspect source.Look deal.getIdData() is loaded or not.May be it is not loaded.Please load properly.
The object you are sending as a parameter doesn't have the getIdData() function defined.
Change your log to:
console.log(deal.getIdData);
and then check whether it returns the function code/definition.
Here is a link with an example of how implement a factory and service.
Angular factory and service
You are not returning the object holding the service reference from you your service registration function. Change your code as below for it to work.
angular.module('account')
.service('deal', function deal($http, accountConfiguration, $q, $log, httpHelper) {
var service = {};
var baseUrl = account.app.url;
service.getIdData = function(data,accountId,decisionMakerDetail){
var def = $q.defer();
var url = baseUrl + '/api/accountsusers/' + accountId + '?role=' + decisionMakerDetail;
httpHelper._$http({
method: 'post', url: url, data: data, def: def
}, function (resp) {
def.resolve(resp.msg);
});
return def.promise;
};
return service;
});
S8nce you were not returning anything from the service, even though deal service gets registered, its value is undefined and when you try to access deal.getIddata() you get the aforementioned error

How to access a factory method inside a controller ?

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

How to get used http call parameter in AngularJs promise?

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) {
// ...
);
}});

Using Promises in AngularJS for chaining in two different controllers

I have a provider for my REST-Services named MyRestServices:
app.provider('MyRestServices', function() {
this.baseUrl = null;
this.setBaseUrl = function(_baseUrl) {
this.baseUrl = _baseUrl;
};
this.$get = ['$http', function($http) {
var _baseUrl = this.baseUrl;
function getMyData() {
return $http.get(_baseUrl + 'data1/?token=' + token + '&key=' + key);
}
function preGetTokenAndKey() {
return $http.get(_baseUrl + 'keyAndToken/');
}
return {
getMyData: getMyData,
preGetTokenAndKey: preGetTokenAndKey
};
}];
});
I configure it before calling the first REST service.
app.config(function(MyRestServicesProvider) {
MyRestServicesProvider.setBaseUrl('https://www.test.com/rest/');
});
And then I have a HeadCtrl controller which should call preGetTokenAndKey to get key and token which is needed for some other REST calls like getMyData.
app.controller('HeadCtrl', function (MyRestServices) {
MyRestServices.preGetTokenAndKey().success(function(data) {
var key = data.dataSection.key;
var token = data.dataSection.token;
});
});
My problem is I want to call getMyData from another controller, but I need key and token to make this call.
So I need to wait until preGetTokenAndKey was successful and I have to provide the two values to the MyRestServices provider.
How can I solve these problems?
It sounds like a better solution would be to chain them within your service itself. You'd setup your own promise within preGetTokenAndKey, which gets resolved by the $http call. Subsequent calls to preGetTokenAndKey() would just return the already resolved data w/o making additional $http calls.
So something along the lines of the following should get you started:
app.provider('MyRestServices', function() {
this.baseUrl = null;
this.setBaseUrl = function(_baseUrl) {
this.baseUrl = _baseUrl;
};
this.$get = ['$http', function($http) {
var _baseUrl = this.baseUrl;
var _tokenAndKey = {};
function getMyData() {
return preGetTokenAndKey().then(function (data) {
return $http.get(_baseUrl + 'data1/?token=' + data.dataSection.token + '&key=' + data.dataSection.key);
});
}
function preGetTokenAndKey() {
if(!_tokenAndKey.set) {
_tokenAndKey.deferred = $http.get(_baseUrl + 'keyAndToken/').then(function(data) {
_tokenAndKey.set = true;
return data;
});
}
return _tokenAndKey.deferred.promise;
}
return {
getMyData: getMyData,
preGetTokenAndKey: preGetTokenAndKey
};
}];
});
My problem is I want to call getMyData from another controller,
If so, you can use $broadcast to notify other controller that async call resolved and you have key/token
app.controller('HeadCtrl', function($rootScope, MyRestServices) {
MyRestServices.preGetTokenAndKey().success(function(data) {
var key = data.dataSection.key;
var token = data.dataSection.token;
$rootScope.$broadcast("getMyDataTrigger", {key: key,token: token});
});
});
In other controller implement listener:
$rootScope.$on("getMyDataTrigger", function(event, data){
if(data){
MyRestServices.getMyData(data.key, data.token);
// ...
}
});
Just override getMyData:
function getMyData(key, token) {
return $http.get(_baseUrl + 'data1/?token=' + token + '&key=' + key);
}

Categories