Second promise is not working properly - javascript

I have the following promise that works perfectly:
self.getAll = function (callback) {
var users= [];
var promises = [];
$.ajax({
url: "/API/Users",
type: "GET",
success: function (results) {
var mappedContacts = $.map(results, function (item) {
promises.push($.ajax({
url: "/API/Users/contacts/" + item.id,
type: "GET"
}).then(function (contacts) {
users.push(new User(item, contacts));
}));
});
$.when.apply($, promises).then(function () {
callback(users);
});
}
});
}
I'm trying to add a second AJAX request but it's not working properly:
self.getAll = function (callback) {
var users= [];
var promises = [];
$.ajax({
url: "/API/Users",
type: "GET",
success: function (results) {
var mappedContacts = $.map(results, function (item) {
promises.push($.ajax({
url: "/API/Users/contacts/" + item.id,
type: "GET"
}).then(function (contacts) {
users.push(new User(item, contacts));
}));
});
var mappedContacts2 = $.map(results, function (item) {
promises.push($.ajax({
url: "/API/Users/contacts2/" + item.id,
type: "GET"
}).then(function (contacts2) {
users.push(new User(item, "",contacts2));
}));
});
$.when.apply($, promises).then(function () {
callback(users);
});
}
});
}
contacts2 is always empty, what am I doing wrong?
This is the User object:
var User= function (data, contacts, contacts2) {
this.id = ko.observable(data.id);
this.name = ko.observable(data.name);
this.contacts = ko.observableArray(contacts);
this.contacts2 = ko.observableArray(contacts2 );
}

Since you need both sets of contacts for each user to pass to new User() use one map() that returns a $.when() for both contacts requests. Create the user in then() of that $.when()
Something like:
self.getAll = function(callback) {
var users = [];
// return this promise ..... see notes below
return $.getJSON("/API/Users").then(results) {
// map array of promises to pass to final $.when
var promises = $.map(results, function(item) {
var req1 = $.getJSON("/API/Users/contacts/" + item.id);
var req2 = $.getJSON("/API/Users/contacts2/" + item.id);
// return this promise to mapped array
return $.when(req1, req2).then(function(contacts1, contacts2) {
// create user now that we have both sets of contacts
users.push(new User(item, contacts1, contacts2));
});
})
// should return this promise .... see notes below
return $.when.apply($, promises).then(function() {
callback(users);
// return `users` ...see notes below
});
})
}
Using a callback is an outdated approach when you could just return the promise chain shown in comments above and do :
self.getAll().then(function(users) {
// do something with users
})

Related

Service call in for loop angular js $q, promise

Service call in for loop angular js $q, promise
var FULLWEEKDAYS = [MONDAY, TUESDAY ... SATURDAY]
for (var i=0; i< FULLWEEKDAYS.length; i++) {
var reqParams = {
weekday: FULLWEEKDAYS[i],
teacherId : 97
}
TimetableService.getTeachersOccupancy(reqParams, function (data)
{
if (data) {
$scope.weeklyData.push(data);
}
}, function (err) {
//message.error('Timetable', err.data);
});
}
Serivice call is
function getTeachersOccupancy(data, successFunction, errorFunction) {
var params = $.param(data);
AjaxHandlerFactory.AjaxGet(BASETIMETABLEPATH + 'occupancy?' +
params, {}, function (response) {
successFunction(response.data);
}, function (error) {
errorFunction(error);
});
}
Question:
$scope.weeklyData.length = 0 outside for loop. Why and how to handle this in promises?
Serivce call
function getTeachersOccupancy(data, successFunction, errorFunction) {
// /SchoolAdminWS/services/schools/{schoolCd}/timeTable/occupancy?classroomId={classroomId}&date={YYYY-MM-DD}
var params = $.param(data);
***var deferred = $q.defer();***
AjaxHandlerFactory.AjaxGet(BASETIMETABLEPATH + 'occupancy?' + params, {}, function (response) {
successFunction(response.data);
***deferred.resolve(response.data);***
}, function (error) {
errorFunction(error);
***deferred.reject(error);***
});
***return deferred.promise;***
}
While calling above service, create a variable promise=[]; push all repsonses from service call, and resolve them.
var promises = [];
for (var i=0; i< FULLWEEKDAYS.length; i++) {
var reqParams = {
weekday: FULLWEEKDAYS[i],
teacherId : vm.employeeProfileId
}
var promise = TimetableService.getTeachersOccupancy(reqParams, function () {}, function () {});
promises.push(promise);
}
Now resolve using $q.all()
$q.all(promises).then(function(value) {
vm.weeklyData = value;
console.log(vm.weeklyData);
setTeacherOccupancyData(value);
vm.isSearch = true;
}, function (reason) {
console.log("Promise Rejected:" + reason);
});

Returning a Javascript Promise from $.ajax call

I am attempting to cast a $.ajax() statement to an es6 Promise and return the es6 promise. The idea is that I will have an application layer of Create, Update, Delete calls to the Microsoft Dynamics Web API which return an es6 Promise so that I can reuse the Create, Update, Delete calls across multiple pages. I've read through the Google, MDN, and David Walsh Blog articles about es6 Promises as well as several SO questions, but I haven't been able to quite put together the details yet.
In my code below, when ExpenseUpload.js calls expenseTransactionSetAPI.Create(newExpenseTransactionSet).then(...)); I see the execution getting to the then(), but nothing inside the then() is being executed. I'm not quite sure what changes I need to make so that my code execution actually processes the then() and I'm not even sure if I am using es6 Promises correctly. Any guidance would be appreciated.
ExpenseUpload.js
"use strict";
requirejs.config({
bundles: {
'CCSEQ.WebAPI.js': ['Model/ExpenseTransaction', 'Model/ExpenseTransactionSet', 'API/ExpenseTransaction', 'API/ExpenseTransactionSet']
}
});
require(["Model/ExpenseTransaction", "Model/ExpenseTransactionSet", "API/ExpenseTransaction", "API/ExpenseTransactionSet"], function (ExpenseTransactionModel, ExpenseTransactionSetModel, ExpenseTransactionAPI, ExpenseTransactionSetAPI) {
let file;
$(document).ready(() => {
setupHandlers();
});
function setupHandlers() {
$("#csv-file").change((e) => {
file = e.target.files[0];
});
$("#btnUploadFile").click(() => loadFile());
}
function loadFile() {
Papa.parse(file, {
complete: (results) => {
ImportExpenseTransaction(results.data);
console.log("import complete");
}
});
}
function ImportExpenseTransaction(data) {
let newExpenseTransactionSet = new ExpenseTransactionSetModel.ExpenseTransactionSet();
newExpenseTransactionSet.SetName = $("#UploadName").val();
newExpenseTransactionSet.Month = $("#UploadMonth").val();
newExpenseTransactionSet.Year = $("#UploadYear").val();
newExpenseTransactionSet.ImportDate = new Date();
newExpenseTransactionSet.Status = 100000000;
let newExpenseTransactions = new Array();
data.forEach((expense) => {
if (expense[0] !== "PR EMP ID") {
let newRecord = new ExpenseTransactionModel.ExpenseTransaction();
newRecord. = expense[n];
... // Load other records like above
newExpenseTransactions.push(newRecord);
}
});
let expenseTransactionSetAPI = new ExpenseTransactionSetAPI.ExpenseTransactionSet();
let expenseTransactionAPI = new ExpenseTransactionAPI.ExpenseTransaction();
expenseTransactionSetAPI.Create(newExpenseTransactionSet).
then((data) => {
console.log(data);
console.log("Transaction Set Created");
expenseTransactionAPI.
Create(newExpenseTransactions[0]).
then(() => {
console.log("Transaction Created");
}).catch(() => {
console.log("failure");
});
}).catch(() => {
(data) => {
console.log(data);
console.log("failure");
}
});
}
});
CCSEQ.WebAPI.js
define("API/ExpenseTransaction", ["require", "exports", "API/APIBase", "Model/ExpenseTransaction"], function (require, exports, APIBase_1, Model) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class ExpenseTransaction extends APIBase_1.APIBase {
constructor() {
super();
this.ConvertToEntity = (data) => {
let result = new Array();
for (let i = 0; i < data.length; i++) {
let newRecord = new Model.ExpenseTransaction();
newRecord.[field] = data[i]["fieldName"];
.
.
.
result[i] = newRecord;
}
return result;
};
}
Create(expense) {
return new Promise((resolve, reject) => {
$.ajax({
url: this.ExpenseTransaction,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(expense.toJSON()),
success: (data) => { resolve(data); },
error: (data) => { reject(data); }
});
});
}
;
}
exports.ExpenseTransaction = ExpenseTransaction;
});
define("API/ExpenseTransactionSet", ["require", "exports", "API/APIBase", "Model/ExpenseTransactionSet"], function (require, exports, APIBase_2, Model) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class ExpenseTransactionSet extends APIBase_2.APIBase {
constructor() {
super();
this.ConvertToEntity = (data) => {
let result = new Array();
for (let i = 0; i < data.length; i++) {
let newRecord = new Model.ExpenseTransactionSet();
newRecord.[field] = data[i]["fieldName"];
.
.
.
result[i] = newRecord;
}
return result;
};
}
Create(expenseSet) {
return new Promise((resolve, reject) => {
$.ajax({
url: this.ExpenseTransactionSet,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(expenseSet.toJSON()),
success: (data) => {
resolve(data);
},
error: (data) => {
reject(data);
}
});
});
}
;
}
exports.ExpenseTransactionSet = ExpenseTransactionSet;
});
//# sourceMappingURL=CCSEQ.WebAPI.js.map
Just return the ajax requests, it returns a promise-like Object.
The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the
Promise interface, giving them all the properties, methods, and
behavior of a Promise
Create(expense) {
return $.ajax({
url: this.ExpenseTransactionSet,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(expenseSet.toJSON())
});
}

JavaScript functions cannot be call one from another

I get desired output from below code. These are two JavaScript function expressions for printing data
(function(){
var getData=function()
{
console.log("getdata");
},
setData=function()
{
getData();
console.log("setData");
};
setData();
})();
But when I try something like this in another page.I didn't get desired output.
This is my code.
var employeesList = {
getemployees: function () {
var data= getData("Employees/GetEmployees");
},
init: function () {
this.getemployees();
}
}.init();
var getData = function (url) {
var error = false;
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: function (data) {
return data;
},
error: function () {
return error = true;
}
});
};
I got an error like this.
getData is not a function
please help.
You can't use a variable before have defined it, so you have to declare getData before employeesList
The variable data in getemployees couldn't be accessible, I added a return there, so you can use its value in init
var getData = function (url) {
var error = false;
/*$.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: function (data) {
return data;
},
error: function () {
return error = true;
}
});*/
return 'test_result';
};
var employeesList = {
getemployees: function () {
//Here you should return the result
return getData("Employees/GetEmployees");
},
init: function () {
var res = this.getemployees();
console.log(res);
}
}.init();
I hope it was clear, bye.
There are two methods to define "function":
var func_name = function(){...}
function func_name() {...}
The difference is that when you use the second one, it can be called before being declared.
var employeesList = {
getemployees: function () {
var data= getData("Employees/GetEmployees");
},
init: function () {
this.getemployees();
}
}.init();
//var getData = function (url) {
function getData (url) { // <====== change to this
var error = false;
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: function (data) {
return data;
},
error: function () {
return error = true;
}
});
};

undefined is not a function while writing a promise function in Nodejs

I am trying to write a function of mine using Bluebird promise Library.
I promisified the ldap-js the createClient function of ldap-js by:
var Promise= require('bluebird'); //done at the beginning
var createClientAsync = Promise.promisify(require('ldapjs').createClient);
getUser:function(user) {
var memberRoles = [];
var searchFilter = '(&(member='+user.dn+'))';
var opts = {
filter: searchFilter,
scope: 'sub',
attributes: ['dn']
};
createClientAsync({
url: 'ldap://x.x.x.x:3889'
})
.then(function(client){
return client.search('o=pic', opts);
})
.then(function(res) {
res.on('searchEntry', function(entry) {
console.log('entry: ' + JSON.stringify(entry.object));
for (var role in roles) {
var mapping = roles[role];
if (mapping.group === entry.object.dn) {
memberRoles.push(role);
}
}
});
})
.then(function() {
return memberRoles;
});
}
I get an error at createClientAsync undefined is not a function.
After a brief reading of the ldapjs documentation, I can suggest the following code
getUser:function(user) {
var searchFilter = '(&(member='+user.dn+'))';
var opts = {
filter: searchFilter,
scope: 'sub',
attributes: ['dn']
};
return createClientAsync({
url: 'ldap://x.x.x.x:3889'
})
.then(function(client){
return client.search('o=pic', opts);
})
.then(function(res) {
var memberRoles = [];
return new Promise(function(resolve, reject) {
res.on('searchEntry', function(entry) {
console.log('entry: ' + JSON.stringify(entry.object));
for (var role in roles) {
var mapping = roles[role];
if (mapping.group === entry.object.dn) {
memberRoles.push(role);
}
}
});
res.on('end', function() {
resolve(memberRoles);
});
});
});
}
note the "new Promise" and res.on('end' to resolve the promise once the "search" has completed
as I said, brief reading of documentation, so this may be completely invalid :p

Ajax promise not working

I'm trying to use promise to return a comparison of current logged in user and a field from a list in SharePoint.
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return this._list.filter(function (element, index, array) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
promise.done(function(data) {
return (data.d.Email.indexOf(userName) > -1);
});
});
}
function init() {
var userArray = this.compareCurrentUserWithListObject();
userArray.done(function(res) {
if (res.length > 0) {
//Do some stuff after compare...
}
});
}
I'm not sure I'm using the .done correct here. Can someone help me?
EDIT:
Working code:
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return this._list.filter(function (element, index, array) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
promise.done(function(data) {
return (data.d.Email.indexOf(userName) > -1);
});
return promise;
});
}
function init() {
var userArray = this.compareCurrentUserWithListObject();
if (userArray.length > 0) {
//Do some stuff after compare...
}
}
you need to return the promise
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return this._list.filter(function (element, index, array) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
promise.done(function(data) {
return (data.d.Email.indexOf(userName) > -1);
});
// return promise here
return promise;
});
}
or this (which is cleaner IMO):
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
}
function init() {
this.compareCurrentUserWithListObject()
.done(function(data) {
var res = data.d.Email.indexOf(userName) > -1;
if (res.length > 0) {
//Do some stuff after compare...
}
});
}
it looks like you want to modify the response before using it in init. There is a way to do that but I'd do it inside the .done callback when using it.
I didn't test this code so there might be mistakes. But the general answer is: you need to return the promise.
The idiomatic way to do this using promises is to use Promise.all(). (I'll use Q promises as an example, but Promise.all is built into the JS6 promise API and several other promise libraries):
function getUserInfo(listItem) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl +
"/_api/web/GetUserById(" + listItem.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
return Q.Promise.when(promise);
}
function filterUsers(users) {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return users.filter(function (user) {
return user.d.Email.indexOf(userName) > -1;
});
}
function init() {
Q.Promise.all(this._list.map(getUserInfo))
.then(filterUsers.bind(this))
.then(function (matchedUsers) {
// matchedUsers is an array of all the users you want.
// use it as needed
});
}

Categories