$http call to get data to other $http call in other file - javascript

I want to read URL from one json file and feed URL to other javascript file having $http GET request to execute that URL. I am using one service in another service file for getting data. Whenever I run it, it says undefined in url: property of bannerslides function.
common.js:
(function() {
angular.module('siteModule')
.service('loggerService', function($http, $q) {
var deffered = $q.defer();
$http.get('/config/config.json').then(function(data) {
deffered.resolve(data);
});
this.getPlayers = function() {
return deffered.promise;
}
})
})();
siteService.js:
(function() {
var confUrl;
angular.module('siteModule')
.service('siteService', function($http, $q, loggerService) {
this.bannerSlides = function() {
loggerService.getPlayers().then(function(data) {
confUrl = data.data.baseUrl + data.data.urls.site;
console.log("GOTURL", confUrl);
//move your return statement here
return $http({
method: "GET",
dataType: "json",
url: confUrl
})
});
}
})
})();

This error indicate that siteService.bannerSlides is not recognised as a promise. When i look at your code, you just return the actual value. Then what you need is callback in siteService.bannerSlides.
Error code is angular.js:14324 TypeError: Cannot read property 'then' of undefined
siteController.js
// modify this to accept callback instead of using then
siteService.bannerSlides(function (data) {
console.log(data);
})
siteService.js
this.bannerSlides = function(callback) {
loggerService.getPlayers().then(function(data) {
confUrl = data.data.baseUrl + data.data.urls.site;
console.log("GOTURL", confUrl);
//move your return statement here
$http({
method: "GET",
dataType: "json",
url: confUrl
}).then(function (response) {
// inspect/modify the received data and pass it onward
//console.log("MAke url", confUrl);
// add this
return callback(response.data);
}, function (error) {
// inspect/modify the data and throw a new error or return data
throw error;
});
}); //loggerService
}

Can you give an example on plunker/jsfiddle ?
You don't have to use deferred object and $q service with $http.
In loggerService you can just do
this.getPlayers = function() {
return $http.get('/config/config.json').then(function(data) {
return data;
});
}
Also, if you want to use then inside of siteController.js
siteService.bannerSlides().then
you are supposed to do a return inside bannerSlides functions, so it returns $http / promise.

On Jquery simple http GET jquery.getjson
$.getJSON( "ajax/test.json", function( data ) {
var items = [];
$.each( data, function( key, val ) {
items.push( "<li id='" + key + "'>" + val + "</li>" );
});
$( "<ul/>", {
"class": "my-new-list",
html: items.join( "" )
}).appendTo( "body" );
});

Related

How to pass the result of an Asynchronous function as a deffered object

i'm trying to get my head around working with Deffered objects especially in cases where you have to perform multiple asynchronous operations on every item in an array. In the code below i just want to be able to access the result of an asynchronous array after it is complete, in my case it is the results array.
To explain the code below
ListData function derives the source data which is an array that i intend to manipulate.
getPictureComplete1 perfroms an async operation (ListDataWithPicture) on every item in the array above
The idea of step 2 was to add an image url to every item in the array from Step 1 and then use the new array as an input to step 4
could be to print the images to the page or perform additional manipulations on the array
var mydeferred = $.Deferred();
var ListData = function (){
listName = 'TeamInfo';
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
type: "GET",
headers: { "ACCEPT": "application/json;odata=verbose" },
success: onQuerySucceded,
error: onQueryFailed
});
return mydeferred.promise();
}
var ListDataWithPicture = function(userId, callback) {
// execute AJAX request
$.ajax({
url: _spPageContextInfo.siteAbsoluteUrl + "/_api/web/SiteUserInfoList/items?$filter=Id eq " + userId + "&$select=Picture",
type: "GET",
async: false,
headers: { "ACCEPT": "application/json;odata=verbose" },
success: function(data){
console.log("Starting async operation for " + userId);
var pictureLink = "";
var mydata = callback(data.d.results[0].Picture.Url);
return mydata
},
error: onQueryFailed
});
}
function onQuerySucceded (data){
var PeopleCompleteList = [];
for (i=0; i< data.d.results.length; i++) {
//check if the user exists if he does store the following properties name,title,workphone,email
if(data.d.results[i]['Name'] != null){
personName = data.d.results[i]['Name'].Name.split('|')[2];
userName = data.d.results[i]['Name']['Name'];
UserTitle = data.d.results[i]['Name']['Title'];
UserphoneNumber = data.d.results[i]['Name']['WorkPhone'];
UserEmail = data.d.results[i]['Name']['EMail'];
Id = data.d.results[i]['Name']['Id'];
PeopleCompleteList.push(PersonConstructor(personName, UserTitle, UserphoneNumber,UserEmail,Id));
}
}
mydeferred.resolve(PeopleCompleteList);
}
function getPictureComplete1 (data){
var def = new $.Deferred();
var results = [];
var expecting = data.length;
data.forEach(function(entry, index) {
//this is the asynchronous function
ListDataWithPicture(entry.UserId, function(result) {
results[index] = {imageUrl: result, UserId: entry.UserId, name: entry.name, Title: entry.Title, phoneNumber: entry.phoneNumber, Email: entry.Email};
//console.log(result);
if (--expecting === 0) {
// Done!
console.log("Results:", results); //this works succeffully from here
def.resolve();
return results
//mydeferred.resolve(results);
}
});
});
return mydeferred.promise();
}
$(function () {
ListData().then(function(data){
//how can i access the results array in this function after it has completed??
var value = getPictureComplete1 (data);
//the line below results undefined,which i understand because the getPictureComplete1 function may not have completed at the time
console.log(value);
});
Because this is an asynchronous operation, the only time that you have access to the array of results from your ajax call in LineData is within the scope of the onQuerySucceded function that you assigned to the success property in your ajax configuration. The function you define here will be fired after a successful response was received.
When establishing a deferred promise, you will need to define what data resolves the promise. Whatever you pass into the resolve method will be available as a parameter within a subsequent then block on your promise chain.
I'm not seeing onQuerySucceded defined in your example, but it would look something like this:
var ListData = function (){
var mydeferred = $.Deferred();
listName = 'TeamInfo';
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
type: "GET",
headers: { "ACCEPT": "application/json;odata=verbose" },
success: function onQuerySuccess(data) {
mydeferred.resolve(data);
},
error: onQueryFailed
});
return mydeferred.promise();
}
Now, after a successful call, the promise will resolve with the data. So, something like this is possible:
ListData()
.then(function (data) {
// do something with the data
})
Similarly, you will want to define what are the rejection cases for your deferred promise. For example, maybe the ajax call doesn't succeed. For this, you will want to use the reject method on the deferred object.
For example:
var ListData = function (){
var mydeferred = $.Deferred();
listName = 'TeamInfo';
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
type: "GET",
headers: { "ACCEPT": "application/json;odata=verbose" },
success: function onQuerySuccess(data) {
mydeferred.resolve(data);
},
error: function onQueryFailed(error) {
mydeferred.reject(error);
}
});
return mydeferred.promise();
}
This works similarly to resolve, but will resolve to any subsequent catch or fail blocks. So, something like this will work
LineData()
.then(function (data) {
// it was successful, do something with the data
})
.catch(function (error) {
// There was an error. The then block was not called.
// Do something with the error.
})
Put even more simply, you can set mydeferred.resolve and mydeferred.reject as these properties directly. Like so:
var ListData = function (){
var mydeferred = $.Deferred();
listName = 'TeamInfo';
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+listName+"')/items?$select=Name/Title,Name/Name,Name/Id,Name/EMail,Name/WorkPhone&$expand=Name/Id",
type: "GET",
headers: { "ACCEPT": "application/json;odata=verbose" },
success: mydeferred.resolve,
error: mydeferred.reject
});
return mydeferred.promise();
}
You will want to do something similar with your ListDataWithPicture function so that it also returns a promise with the data that you need:
var ListDataWithPicture = function(userId, callback) {
var deferred = $.Deferred();
$.ajax({
url: _spPageContextInfo.siteAbsoluteUrl + "/_api/web/SiteUserInfoList/items?$filter=Id eq " + userId + "&$select=Picture",
type: "GET",
async: false,
headers: { "ACCEPT": "application/json;odata=verbose" },
success: function(data){
deferred.resolve(data.d.results[0].Picture.Url)
},
error: deferred.reject
});
return deferred.promise();
}
This allows you to do something like this:
LineData()
.then(function (data) {
// performing on just the first result:
return ListDataWithPicture(data[0]);
})
.then(function (url) {
// do something with the result
})
.catch(function (error) {
// do something with the error
});
Because you want to perform a aynchronous operation on each of the items in your array, I'd recommend to use Promise.all which executes and resolves an array of promises.
LineData()
.then(function (data) {
// create a map of promises
var promises = data.map(function (item) {
return ListDataWithPicture(item);
});
return Promise.all(promises);
})
.then(function (urls) {
// urls will be an array of urls resolved from calling
// ListDataWithPicture on each item in the array resolved
// from above
})
.catch(function (error) {
// do something with the error
});
Here are some good resources to learn more:
http://api.jquery.com/category/deferred-object/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Jquery ajax call assigned success val to window

I'm trying to fetch some urls from the back-end and assign data.Results in window.__env.{variable} so I can use it anywhere in the application.
I have this code
(function(window){
window.__env = window.__env || {};
$.ajax({
url: './assets/js/config/config.json',
method: 'GET',
success: function (data) {
let baseUrl = data.BaseApiUrl;
workflowDefinition(baseUrl);
}
})
function workflowDefinition(baseUrl) {
$.ajax({
url: baseUrl + 'api/Management/Configurations?name=SaveWorkflowDefinition&name=WorkflowDefinition',
method: 'GET',
success: function (data) {
if (data && data.Results && data.Results[0] && data.Results[0].Value) {
window.__env.saveWorkflowDefinition = data.Results[0].Value;
console.log(window.__env.saveWorkflowDefinition);
}
if (data && data.Results && data.Results[1].Value) {
window.__env.getWorkflowDefinition = data.Results[1].Value;
}
},
error: function (error) {
var errorMessage = "Failed to contact Workflow Server, please contact your IT administrator";
alert(errorMessage);
}
})
}
}(this))
I can see that the console.log is printing when this loads it gives me the right URL, then I tried passing window.__env.saveWorkflowDefinition to say another file xfunction.js where I want to use window.__env but it gives me undefined.
However if I pass it like this without ajax call, it works fine.
(function(window){
window.__env = window.__env || {};
window.__env.saveWorkflowDefinition= 'www.mybaseurl.com/api/Management/';
})
Can someone point out why its returning undefined when I pass it to xfunction.js when doing an ajax call?
Since your Ajax calls will only provide the response asynchronously, you cannot expect to have the response in the same synchronous execution context.
One idea to resolve this, is to abandon the idea to store the response in a global (window) property, but to store instead a promise, which you do get synchronously.
The code could look like this:
window.promiseWorkFlowDefinition = $.ajax({
url: './assets/js/config/config.json',
method: 'GET',
}).then(function (data) {
return $.ajax({
url: data.BaseApiUrl + 'api/Management/Configurations?'
+ 'name=SaveWorkflowDefinition&name=WorkflowDefinition',
method: 'GET',
})
}).then(function (data) {
return data && data.Results && (data.Results[0] && data.Results[0].Value
|| data.Results[1] && data.Results[1].Value)
|| ('No Results[0 or 1].Value found in:\n' + JSON.stringify(data));
}, function (error) {
var errorMessage =
"Failed to contact Workflow Server, please contact your IT administrator";
alert(errorMessage);
});
// Other file:
window.promiseWorkFlowDefinition.then(function(saveWorkflowDefinition) {
// Use saveWorkflowDefinition here. This is called asynchronously.
// ...
});

Angular promise after calling a service with $http

I m actually developping an application with angularjs, and I m facing a problem with $http, and the result of an asynchronous service request to my webservice.
Actually, I m using this code :
var promise = undefined;
UserService.getAll = function (callback) {
promise = $http({
url: __ADRS_SRV__ + "users",
method: "GET",
isArray: true
}).success(function(data){
return data;
}).error(function(data){
return $q.reject(data);
});
return promise;
}
This doesnt work, and give me some stuff like, I dont know why :
To know : in my controller, I want to use a really simple syntax like
var data = UserService.getAll();
Do you have any idea how should I process to access my data correctly ?
Thanks for advance
you get the promise in return. There are multiple ways to use this promise.
Example 1 (Use promise in service and return reference of an object):
UserService.getAll = function () {
var dataWrapper = {
myData: {},
error: null
};
$http({
url: __ADRS_SRV__ + "users",
method: "GET",
isArray: true
}).success(function(data){
dataWrapper.myData = data;
}).error(function(data){
dataWrapper.error = true;
return $q.reject(data);
});
return dataWrapper;
}
Example 2 (Return promise and use it directly in the controller):
// service
UserService.getAll = function () {
return $http({
url: __ADRS_SRV__ + "users",
method: "GET",
isArray: true
});
}
// controller
var promise = UserService.getAll();
promise.success(function(data) {
$scope.data = data;
});
Example 3 (Use regular callback):
// service
UserService.getAll = function (cb) {
$http({
url: __ADRS_SRV__ + "users",
method: "GET",
isArray: true
}).success(cb);
}
// controller
UserService.getAll(function(data) {
$scope.data = data;
});
The "stuff" you mention is the very promise you create and return.

How to optimize (minimize) jQuery AJAX calls

I have over 50 AJAX calls from different functions of my code. All these calls have a similar structure with different data/url/callback params:
var jqXHR = $.post('/dba/port.php', {
mode: "del_wallfunds",
pdata: cdata,
wname: wName
},
function (data) {}, "json")
.done(function (data) {
var msg = data.msg;
if (msg.indexOf("Error") == -1) {
alertify.success(msg);
delSelected(selGroup);
} else {
alertify.error(msg);
}
})
.fail(function () {
alertify.error("Error .....");
});
I am thinking how to write a function that would return that var jqXHR to minimize the total size of the code. It is not a problem to pass all static variables like URL, error strings etc. But the problem is that all callback functions on ".done" are different and I don't know how to pass these callback functions as variables.
One way would be to call a single "universal" function on .done and pass a "switch" variable to that function, but it doesn't seem to be an elegant solution.
Any suggestions how to it in some elegant way?
Thanks
Either pass the done callback function as an argument when calling your function:
function ajaxCall(url, data, doneCallback) {
return $.post(url, data, doneCallback, "json").fail(...);
// or
return $.post(url, data, function() {}, "json").done(doneCallback).fail(...);
}
var jqXhr = ajaxCall('yoururl.php', {key: 'value'}, function(data) {
// do something
});
Or return the jqXhr object from the function, and assign the done callback then:
function ajaxCall(url, data) {
return $.post(url, data, function() {}, "json").fail(...);
}
var jqXhr = ajaxCall('yoururl.php', {key: 'value'});
jqXhr.done(function(data) {
// do something
});
Alternatively switch to using jQuery.ajax() instead, and pass the entire options object in:
function ajaxCall(options) {
return $.ajax(options).fail(...);
}
var jqXhr = ajaxCall({
url: 'yoururl.php',
data: {key: 'value'},
dataType: 'json'
});
jqXhr.done(function(data) {
// do something
});
You can try to :
turn "request successfully returned a treatment error" into a "rejected request",
put the "alertify" processing in a common callback
Here is a sketch of what this could give :
function myAjaxApi(url, data){
var myAjaxCall = $.post(url, data, function (data) {}, "json")
.then(function (data) {
// using .then : change "request succesful with error state"
// to "rejected state"
var msg = data.msg;
if (msg !== undefined && msg.indexOf("Error") >= 0) {
var dfd = $.Deferred();
// try to match the same signature as the "error" option
dfd.reject(this, msg);
return dfd;
} else {
return data
}
});
myAjaxCall.done(function(data){
if (data.msg) {
alertify.success(data.msg);
}
}).fail(function (jqxhr, msg) {
if (!msg) { msg = "Error ....."; }
alertify.error(msg);
});
return myAjaxCall;
}
//usage
myAjaxApi('/dba/port.php', {mode: "del_wallfunds", pdata: cdata, wname: wName})
.done(function (data) {
// the ".done()" queue will not be executed if msg contains "Error" ...
delSelected(selGroup);
});
Some parts should be written with more care ; the above example is meant to illustrate how you can wrap your repeated ajax calls inside a common api.

How to wait ajax callback result from another callback?

I have a method below:
self.getOrAddCache = function (key, objectFactory) {
var data = self.getFromCache(key);
if (!data) {
data = objectFactory();
if (data && data != null)
self.addToCache(key, data);
}
return data;
};
I use like this:
function getCities()
{
var cities = getOrAddCache(CacheKeys.Cities, function() {
var cityArray = new Array();
// get city informations from service
$.ajax({
type: "GET",
async: true,
url: "service/cities",
success: function (response) {
$.each(response, function(index, value) {
cityArray.push({
name: value.name,
id: value.id
});
});
}
});
if (cityArray.length > 0)
return cityArray;
else {
return null;
}
});
return cities;
}
getCities function always return null because getCities not waiting for completion async ajax request.
How can i resolve this problem? (Request must be async)
The best solution for this is to use Deferred objects. Since you require your AJAX call to be asynchronous, you should have your getCities function return a promise to return that data at some point in the future.
Instead of storing the raw data in the cache, you store those promises.
If you request a promise that has already been resolved, that will complete immediately. If there's already a pending request for the cached object, the async AJAX call will be started and all outstanding callbacks waiting for that promise will be started in sequence.
Something like this should work, although this is of course untested, E&OE, etc, etc.
self.getCached = function(key, objectFactory) {
var def = self.getCache(key);
if (!def) {
def = objectFactory.call(self);
self.addToCache(key, def);
}
return def;
}
function getCities() {
return getCached(CacheKeys.Cities, function() {
return $.ajax({
type: 'GET',
url: 'service/cities'
}).pipe(function(response) {
return $.map(response, function(value) {
return { name: value.name, id: value.id };
});
});
});
}
Note the usage of .pipe to post-process the AJAX response into the required format, with the result being another deferred object, where it's actually the latter one that gets stored in your cache.
The usage would now be:
getCities().done(function(cities) {
// use the cities array
});
With a callback:
function getCities(callbackFunction)
{
var cities = getOrAddCache(CacheKeys.Cities, function() {
var cityArray = new Array();
// get city informations from service
$.ajax({
type: "GET",
async: true,
url: "service/cities",
success: function (response) {
$.each(response, function(index, value) {
cityArray.push({
name: value.name,
id: value.id
});
});
callbackFunction(cityArray);
}
});
});
}
getCities(function(cityArray){
// do stuff
});
You can't return the result from a function fetching asynchronously the data.
Change your getCities function to one accepting a callback :
function fetchCities(callback) {
var cities = getOrAddCache(CacheKeys.Cities, function() {
var cityArray = new Array();
// get city informations from service
$.ajax({
type: "GET",
async: true,
url: "service/cities",
success: function (response) {
$.each(response, function(index, value) {
cityArray.push({
name: value.name,
id: value.id
});
});
if (callback) callback(cityArray);
}
});
});
}
And use it like this :
fetchCities(function(cities) {
// use the cities array
});
Note that it's technically possible, using async:true, to make the code wait for the response but don't use it : that's terrible practice and it locks the page until the server answers.
You seem to be contradicting yourself.
Something that is asynchronous, by definition, does not pause the script to wait for the end of it's execution. If it does wait, it cannot be asynchronous.
The best wayto fix this is by adding a callback function in your ajax success function that passes the end result to another function, which handles the rest of the execution.

Categories

Resources