using angular factory with $http - angularjs

I need translate value factory. this factory receive translateData from server. and angular controller call convertValue function. but $http is async method so controller get undefined value. because http response not yet received.
I wonder that I can factory initialize complete(= download data from server) and create controller sequentially.
angular.module("app")
.factory("service", function ($http) {
var allDataMap = {};
$http({
method: 'GET',
url: '/data'
}).then(function (response) {
angular.forEach(response.data.datas, function (value) {
allDataMap[value.key] = value.value;
});
});
return {
convertValue: function (key) {
return key + '(' + allDataMap[key] + ')';
},
};
});

You're thinking of async call to be accomplish in sync way. That won't happen, you have to wait until the ajax call is done, you can easily make this happen using promise.
angular.module("app")
.factory("service", function ($http) {
var allDataMap = {};
// create a promise
var promise = $http({
method: 'GET',
url: '/data'
}).then(function (response) {
angular.forEach(response.data.datas, function (value) {
allDataMap[value.key] = value.value;
});
return allDataMap;
});
return {
convertValue: function (key) {
// wait until promise finish
return promise.then(function() {
return key + '(' + allDataMap[key] + ')';
});
},
};
});

Related

defer.promise returning same result in angularJS

I have a Service which fetch the data from API.When I am trying to call this service. It's returning with same value.
appName.service('FetchCustomerDate', ['$http', '$q', function($http, $q) {
var self = this;
self.getCustomerData = function(token,name) {
var deferred = $q.defer();
return $http({
method: 'GET',
url: ,
headers: {
"Authorization": token,
"x-xcmc-auth": ''
}
}).then(function(response) {
deferred.resolve(response);
return deferred.promise;
}, function(response) {
deferred.reject(response);
return deferred.promise;
});
};
}]);
I see a bit of confusion here. Let's try to clear it. If you want to use deferred object, you need to change your code a bit:
appName.service('FetchCustomerDate', ['$http', '$q', function ($http, $q) {
var self = this;
self.getCustomerData = function (token, name) {
var deferred = $q.defer();
$http({ // Do not return here, you need to return the deferred.promise
method: 'GET',
url: '...some URL here...',
headers: {
"Authorization": token,
"x-xcmc-auth": ''
}
}).then(function (response) {
deferred.resolve(response); // It's correct, you are resolving the deferred promise here.
// return deferred.promise; // You do not need to return the deferred.promise here.
}, function (response) {
deferred.reject(response); // It's correct, you are rejecting the deferred promise here.
// return deferred.promise; // You do not need to return the deferred.promise here.
});
return deferred.promise; // The function must return the deferred.promise
};
}]);
In detail, function getCustomerData must return the promise belonging to deferred object with return deferred.promise. Inside then() callback you simply resolve or reject deferred promise. You do not need to return the deferred.promise.
You can improve the code. The $http service returns a promise, and the value returned by then callbacks is wrapped by then method in a promise. Knowing that, you can remove the use of deferred object:
appName.service('FetchCustomerDate', ['$http', function ($http) {
var self = this;
self.getCustomerData = function (token, name) {
return $http({ // Here, you need to return the promise returned by $http. Than promise will contain the response returned inside "then" callbacks.
method: 'GET',
url: '...some URL here...',
headers: {
"Authorization": token,
"x-xcmc-auth": ''
}
}).then(function (response) {
return response; // Simply return the response, it will be wrapped in a resolved promise by "then()"
}, function (response) {
return response; // Simply return the response, it will be wrapped in a rejected promise by "then()"
});
};
}]);
As you can see, the 2 then callbacks simply returns the response object, for this reason you can omit them:
appName.service('FetchCustomerDate', ['$http', function ($http) {
var self = this;
self.getCustomerData = function (token, name) {
return $http({ // Here, you need to return the promise returned by $http. Than promise will contain the response form the GET call
method: 'GET',
url: '...some URL here...',
headers: {
"Authorization": token,
"x-xcmc-auth": ''
}
});
};
}]);
Usually when you fetch data with the $httpservice, you want to obtain data from the response and affect it to the $scope for instance, or process it somehow. What are you trying to do? Please clarify your question.
Normally a fetch will look something like this:
appName.service('FetchCustomerDate', ['$http', '$q', function($http, $q) {
var self = this;
function notifyError(reason) {
console.error(reason);
}
self.getCustomerData = function(token,name) {
var deferred = $q.defer();
return $http({
method: 'GET',
url: ,
headers: {
"Authorization": token,
"x-xcmc-auth": ''
}
})
.then(function onSuccess(response) {
var cfg = response.data; // process data
})
.then(function onSuccess(response) {
// chained promises
})
.then(
function onSuccess(res) {
// ... this will trigger the chain reaction
deferred.resolve(res);
},
function onFailure(reason) {
notifyError(reason); // manage the error
deferred.reject(reason);
})
;
return deferred.promise;
}
}]);

Return deferred.promise 2 services back

I have 3 services.
HttpSender - It controls the $http request
app.service("HttpSender", ["$http", "$q", function ($http, $q) {
this.send = function (path, method, params) {
var deferred = $q.defer();
$http({
url: path,
method: method,
params: params
}).then(function successCallback(response) {
deferred.resolve(response.data);
}, function errorCallback(response) {
deferred.reject(response);
});
return deferred.promise;
};
this.sendRequestWithFile = function (path, method, params) {
//todo check if needed
};
}]);
Api - controls all the api/ access token processes
service("API", ["HttpSender", "$q", 'WindowOpen', function(HttpSender, $q, WindowOpen){
var self = this;
var API = {};
API.requestTypes = {
GetMethod: "GET",
PostMethod: "POST",
DeleteMethod: "DELETE",
PutMethod: "PUT"
};
API.sendRequest = function (path, method, parameters, isCheckAccessToken)
{
path = ServersConfig.getApiServerUrl() + path;
parameters.access_token = getAccessToken();
HttpSender.send(path, method, parameters);
};
return API;
}]);
Api - Endpoint which activate the api request
app.factory('SelectedEndpoint', ['API',
function (API) {
var getPath = function (campaign) {
return "/campaigns/" + campaign.id + '/content/selected';
};
return {
get: function (campaign) {
API.sendRequest(getPath(campaign), API.requestTypes.GetMethod, {}, true).then(function (content) {
});
}
};
}]);
How can return the deferred.promise to the endpoint function so the then will get the answer? The following process only works if i add then also in the api factory the then return it to the endpoint
How can return the deferred.promise to the endpoint function so the then will get the answer?
By properly returning promises on each step.
1. HttpSender service. Do not use deferred here, just return promise directly:
app.service("HttpSender", ["$http", "$q", function($http, $q) {
this.send = function(path, method, params) {
return $http({
url: path,
method: method,
params: params
}).then(function successCallback(response) {
return response.data;
});
};
}]);
2. Api service. Make sure you return previous promise with return HttpSender.send(path, method, parameters);:
service("API", ["HttpSender", "$q", 'WindowOpen', function(HttpSender, $q, WindowOpen) {
var self = this;
var API = {};
API.requestTypes = {
GetMethod: "GET",
PostMethod: "POST",
DeleteMethod: "DELETE",
PutMethod: "PUT"
};
API.sendRequest = function(path, method, parameters, isCheckAccessToken) {
path = ServersConfig.getApiServerUrl() + path;
parameters.access_token = getAccessToken();
return HttpSender.send(path, method, parameters); // note return promise
};
return API;
}]);

How can I make a $http call return a promise and data for $q?

I have the following script:
$q.all([
getActive(),
getUser()
])
.then(function (results) {
var x = results[0];
var y = results[1];
}
function getActive() {
$http({
url: '/api/Test/GetActive',
method: "GET"
})
};
function getUser() {
$http({
url: '/api/Test/GetUser',
method: "GET"
})
};
I was expecting to see that the variables x and y would contain the results of the $http calls but they both show as undefined.
Can someone suggest how I can make these calls return a promise. I actually thought $http did return a promise so I am confused.
You seem to be missing the return statement in both the getActive() and getUser() functions.
Try this:
$q.all([
getActive(),
getUser()
])
.then(function (results) {
var x = results[0];
var y = results[1];
}
function getActive() {
return $http({
url: '/api/Test/GetActive',
method: "GET"
});
};
function getUser() {
return $http({
url: '/api/Test/GetUser',
method: "GET"
});
};
Here's a working example. I changed your code in a few small ways. Note: The returned promises from the individual calls, the simplified way of calling $http, and pulling the data out of the returned results in the then() function:
http://plnkr.co/edit/YStkRt?p=info
function MainCtrl($scope, $q, $http) {
$q.all([
getActive(),
getUser()
])
.then(function (results) {
$scope.ip = results[0].data;
$scope.headers = results[1].data;
});
function getActive() {
return $http.get('http://ip.jsontest.com/');
}
function getUser() {
return $http.get('http://headers.jsontest.com/');
}
}

AngularJS: Creating a $http service

I'm a little new to Angular, and I'm trying to set up a very simple RPC implementation that uses angulars $http service (factory) to do the work. Here's what I have for the service so far:
'use strict';
angular.module('xxx')
.factory('rpcService', function ($http) {
return {
request: function(method, params, callback) {
var service = method.split('.');
params = params || {};
params.method = service[1];
return $http.post('/services/' + service[0] + '.sjs', params).then(function (response) {
return response.data;
});
}
}
});
Then when I want to use the service, I call it like the following:
rpcService.request('Users.facebookLogin', { token: response.authResponse.accessToken })
.then(function(response) {
debugger;
$rootScope.user = response.user;
console.log($rootScope.user);
$rootScope.loggedIn = true;
$rootScope.$apply();
});
The code never gets to the lines after debugger; In fact, the code never makes the $http request at all. For some reason it stops and doesn't continue with the callback...or promise...I'm a bit confused as to what the technical difference is. :)
That being said, I've tested the POST call with $.ajax and everything returns properly, so something is off with my Angular code.
And the code that actually fires the request and does work with $.ajax:
'use strict';
angular.module('xxx')
.factory('rpcService', function ($http) {
return {
request: function (method, params, callback) {
var service = method.split('.');
params = params || {};
params.method = service[1];
$.ajax('/services/' + service[0] + '.sjs', {
type: 'POST',
dataType: 'json',
data: params,
success: function(data, status, xhr) {
if (callback) {
callback(data);
}
}
});
}
}
});
I'm just unsure why the XHR request isn't being made.
The API call may get an error so the callback was never triggered. Try to add error() callback like this:
return $http("POST", '/services/' + service[0] + '.sjs', params)
.error(function (response) {
return 'blah';
}).then(function (response) {
return response.data;
});
You can try it on this demo. Your code actually looks good.
Demo on jsFiddle

How can I pass back a promise from a service in AngularJS?

I have some code in my controller that was directly calling $http to get data.
Now I would like to move this into a service. Here is what I have so far:
My service:
angular.module('adminApp', [])
.factory('TestAccount', function ($http) {
var TestAccount = {};
TestAccount.get = function (applicationId, callback) {
$http({
method: 'GET',
url: '/api/TestAccounts/GetSelect',
params: { applicationId: applicationId }
}).success(function (result) {
callback(result);
});
};
return TestAccount;
});
Inside the controller:
TestAccount.get(3, function (data) {
$scope.testAccounts = data;
})
How can I change this so rather than passing the result of success back it
passes back a promise that I can check to see if it succeeded or failed?
Make your service to return a promise and expose it to service clients. Change your service like so:
angular.module('adminApp', [])
.factory('TestAccount', function ($http) {
var TestAccount = {};
TestAccount.get = function (applicationId) {
return $http({
method: 'GET',
url: '/api/TestAccounts/GetSelect',
params: { applicationId: applicationId }
});
};
return TestAccount;
});
so in a controller you can do:
TestAccount.get(3).then(function(result) {
$scope.testAccounts = result.data;
}, function (result) {
//error callback here...
});

Resources