Accessing a global variable that is been updated from an asynchronous function - javascript

i'm really struggling to understand the asynchronous side of JavaScript. the code i have is meant to collate specific details of certain users and then put all the collated information into a global variable array which i intent to manipulate when all the users have been added to the array. i'm finding it difficult to iterate the array because when i do an array.length on the printurlonPage() function i get a 0 despite the fact that when i do a console log on the array itself i can see that there are items there. Does anyone know a technique that allows me to work on the global variable only after the asynchronous function has completed?
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
var PeopleCompleteList = [];
function PersonConstructor(username,Title,Phone,Email,imageurl){
return {
name: username,
Title: Title,
phoneNumber: Phone,
Email: Email,
Picture: imageurl
}
}
var printurlonPage = function (){
for (var link in PeopleCompleteList) {
console.log(link['Picture']);
}
console.log(PeopleCompleteList);
}
var getIndividualPersonDetails = function(GetPictureUrl) {
listName = 'TeamInfo';
//var PeopleCompleteList = [];
// execute AJAX request
$.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 (data) {
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 and picture url
if(data.d.results[i]['Name'] != null){
var personName = data.d.results[i]['Name'].Name.split('|')[2];
var userName = data.d.results[i]['Name']['Name'];
var UserTitle = data.d.results[i]['Name']['Title'];
var UserphoneNumber = data.d.results[i]['Name']['WorkPhone'];
var UserEmail = data.d.results[i]['Name']['EMail'];
var myuserPicture = GetPictureUrl(userName);
console.log(myuserPicture);
PeopleCompleteList.push(PersonConstructor(personName, UserTitle, UserphoneNumber,UserEmail,myuserPicture));
}
}
},
error: function () {
alert("Failed to get details");
}
});
}
function GetPictureUrl(user) {
var userPicture="";
var requestUri = _spPageContextInfo.webAbsoluteUrl +
"/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=#v)?#v='"+encodeURIComponent(user)+"'";
$.ajax({
url: requestUri,
type: "GET",
async:false,
headers: { "ACCEPT": "application/json;odata=verbose" },
success: function (data) {
console.log(data);
var PictureDetails = data.d.PictureUrl != null ? data.d.PictureUrl : 'c:\apps\noimageurl.jpg';
userPicture=PictureDetails;
}
});
return userPicture;
};
$(function () {
getIndividualPersonDetails(GetPictureUrl);
printurlonPage();
});
</script>

You're printurlonPage() is not asynchronous, so it's running before getIndividualPersonDetails responds. You can do two things, use promises or use async/await from es7. I prefer async/await, but you'll need to babelify.
Or, you can just put your printurlonPage invocation inside your success: handler.
success: function (data) {
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 and picture url
if(data.d.results[i]['Name'] != null){
var personName = data.d.results[i]['Name'].Name.split('|')[2];
var userName = data.d.results[i]['Name']['Name'];
var UserTitle = data.d.results[i]['Name']['Title'];
var UserphoneNumber = data.d.results[i]['Name']['WorkPhone'];
var UserEmail = data.d.results[i]['Name']['EMail'];
var myuserPicture = GetPictureUrl(userName);
console.log(myuserPicture);
PeopleCompleteList.push(PersonConstructor(personName, UserTitle, UserphoneNumber,UserEmail,myuserPicture));
}
}
printurlonPage();
},
And then in document.ready:
$(function () {
getIndividualPersonDetails(GetPictureUrl);
});
So, getIndividualPersonDetails is invoked, and then when it receives the data, the callback is invoked with the data.

Related

How to access value outside of forEach in jquery

GetMandatoryFieldsforUser: function (data) {
var field = [];
$.get("api/mapping/mandatoryfield?type=USER", function (data) {
var self = this;
self.dt = [];
self.firmdata = JSON.parse(data.Data);
console.log(self.firmdata);
self.firmdata.forEach(function (item) {
field.push(item.DisplayName);
})
console.log(field) //able to print value
})
console.log(field) // not able to print value
return MandatoryFields.User;
},
EDIT
MandatoryFields = {
User: field,
}
my question here is i need to access field value outside forEach loop.How to achieve this using jquery or javascript
EDIT
"api/mapping/mandatoryfield?type=USER" returns
["First Name", "Last Name", "Location", "Email", "Password"],
see the edited question i want to use that field array inside MandatoryFields.User but if i use it its not showing the value
This implements $.ajax:
GetMandatoryFieldsforUser: function (data) {
var field = [];
$.ajax({
url: "api/mapping/mandatoryfield?type=USER"
}).done(function(data) {
// THIS PORTION IS EXECUTED AFTER DATA IS LOADED
var self = this;
self.dt = [];
self.firmdata = JSON.parse(data.Data);
console.log(self.firmdata);
self.firmdata.forEach(function (item) {
field.push(item.DisplayName);
})
console.log(field)
/*
USE return HERE!
*/
return field; // OR SOMETHING ELSE
})
// THIS WON'T WORK, BECAUSE DATA IS RETRIEVED IN ASYNC!
console.log(field)
},
Since $.get() is an asynchronous method, you can use async/await to access the returned value from the $.get method's callback.
GetMandatoryFieldsforUser: async function (data) {
var field = [];
const returnedField = await $.get("api/mapping/mandatoryfield?type=USER", function (data) {
var self = this;
self.dt = [];
self.firmdata = JSON.parse(data.Data);
console.log(self.firmdata);
self.firmdata.forEach(function (item) {
field.push(item.DisplayName);
})
console.log(field) //able to print value
return field;
}).promise()
console.log(returnedField) // not able to print value
},
You should use the ajax method in jquery.
function GetMandatoryFieldsforUser( data)
{
var field= [];
var scriptUrl = "api/mapping/mandatoryfield?type=USER";
$.ajax({
url: scriptUrl,
type: 'get',
dataType: 'html',
async: true,
success: function(data) {
var self = this;
self.dt = [];
self.firmdata = JSON.parse(data.Data);
console.log(self.firmdata);
self.firmdata.forEach(function (item) {
field.push(item.DisplayName);
})
console.log(field)
}
});
return field;
}

How to check if user belongs to a sharepoint AD group or not using REST/Javascript only?

How to check if current user belongs to a sharepoint AD group or not using REST/Javascript only?
Currently I am achieving it by adding my security group in a SP group and then checking properties mentioned in below code. But only issue with this is, I have large number of site collection , so everywhere I have to create one SP group & then add my security group inside it.
var clientContext = new SP.ClientContext();
var groupId = ...; // my group Id
var group = clientContext.get_web().get_siteGroups().getById(groupId);
clientContext.load(group,"CanCurrentUserViewMembership");
clientContext.load(group,"CanCurrentUserManageGroup");
clientContext.executeQueryAsync(
function(sender,args){
if(group.get_canCurrentUserViewMembership() == true)
{
if(group.get_canCurrentUserManageGroup() == false) // this check for group owners
{ //access denied logic
}
}
},
function(sender,args){ //failed });
This can be achieved by following function
remarks: It only works with "current user" but in many times that is enough.
I added Jquery promise creation so Jquery is needed, this in order for the function to work in IE11)
function _isCurrentUserInGroup(groupId) {
var promise = $.Deferred(function () {
var endpoint;
endpoint = _spPageContextInfo.webAbsoluteUrl + "/_api/web/sitegroups(" + groupId + ")/CanCurrentUserViewMembership"
jQuery.ajax({
"url": endpoint,
"type": "GET",
"contentType": "application/json;odata=verbose",
"headers": {
"Accept": "application/json;odata=verbose"
}
}).then(function (result) {
promise.resolve(result.d.CanCurrentUserViewMembership);
}, function (sender, args) {
console.log(args.get_message());
soc_appinsights.appInsights.trackException(args.get_message());
promise.reject(sender, args);
});
});
return promise;
}
It can be called like this:
_isCurrentUserInGroup(20).then(function(result)
{ console.log(result); //true or false. } ,
function (sender, args) { console.log(args.get_message(););
You need to know the id of the group but that can easily be retrieved.
You can do this by using a function like this:
function IsCurrentUserMemberOfGroup(groupName, OnComplete) {
var currentContext = new SP.ClientContext.get_current();
var currentWeb = currentContext.get_web();
var currentUser = currentContext.get_web().get_currentUser();
currentContext.load(currentUser);
var allGroups = currentWeb.get_siteGroups();
currentContext.load(allGroups);
var group = allGroups.getByName(groupName);
currentContext.load(group);
var groupUsers = group.get_users();
currentContext.load(groupUsers);
currentContext.executeQueryAsync(OnSuccess,OnFailure);
function OnSuccess(sender, args) {
var userInGroup = false;
var groupUserEnumerator = groupUsers.getEnumerator();
while (groupUserEnumerator.moveNext()) {
var groupUser = groupUserEnumerator.get_current();
if (groupUser.get_id() == currentUser.get_id()) {
userInGroup = true;
break;
}
}
OnComplete(userInGroup);
}
function OnFailure(sender, args) {
OnComplete(false);
}
}
Usage:
function CheckUserGroup()
{
IsCurrentUserMemberOfGroup("YourGroupName", function (isCurrentUserInGroup) {
if(isCurrentUserInGroup)
{
//Do something
}
else
{
//Do something else
}
});
}
You may try this apporach as well coded with REST.
<script src="https://code.jquery.com/jquery-1.11.2.min.js" type="text/javascript" ></script>
<script type="text/javascript">
$(function(){
isMember("Test Group");
});
function isMember(groupName){
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/sitegroups/getByName('"+ groupName +"')/Users?$filter=Id eq " + _spPageContextInfo.userId,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function(data){
if(data.d.results[0] != undefined){
// Exist in group
}
else
{
// Does not exist
}
}
});
}
</script>

How to filter JSON data for autosuggestion using Ajax (without jQuery ui)

I am trying to create an auto-suggestion from scratch. I am using canjs controller to control the DOM elements (ul and li).
I want smart and short code to implement this. I have tried with filter but I want Ajax filter method to use for this purpose.
I have tried the following thing:
can.Model:
var SearchDomainModel = can.Model.extend({
findAll: function(){
return this.getDomains;
}
}, { domainList: null,
getDomains: function(params, callback) {
var promise = $.ajax({
url: '/scripts/models/domains.json',
type: 'GET',
dataType: 'json',
dataFilter: function(data, type){
var parsed_data = JSON.parse(data);
var regex = new RegExp(params, 'gi')
var temp = [];
$.each(parsed_data, function(i, item){
for(var j in item)
if ((item[j].url).toLowerCase().indexOf(params) >= 0){
temp.push(item[j].url);
console.log(temp);
}
});
return temp;
}
});
This is my can.controller:
var DomainController = can.Control.extend({
defaults: {
view: 'views/domainSearch.hbs'
}
}, {
searchList: new can.List(),
domainModel: new DomainModel(),
init: function(element, options) {
this.element.html(can.view(this.options.view, this.searchList));
$('html,body').css({
percentWidth: 100,
percentHeight: 100
});
$('.error').hide();
}, // control domain filter on keyup event
'input keyup': function(element, event) {
var self = this;
var searchText = element.val();
if (searchText !== "") {
this.domainModel.getDomains(searchText, function (response, error) {
self.searchList.attr("domains",response);
console.log(error);
})
I am trying and searching from last two days. I could not have done it. Can anybody suggest me where is my mistake in the code and how to solve it?
Thanx in advance!!
I would probably do something like this:
var SearchDomainModel = can.Model.extend({
findAll: function(){
return this.getDomains;
}
}, { domainList: null,
getDomains: (function() {
var domains = null;
function search(searchText, callback){
var regex = new RegExp(searchText, 'gi')
var temp = [];
$.each(domains, function(i, item){
for(var j in item)
if (regex.test(item[j].url))
temp.push(item[j].url);
});
callback(temp);
}
return function(searchText, callback) {
if( domains ) {
search(searchText, callback);
return;
}
$.ajax({
url: '/scripts/models/domains.json',
type: 'GET',
dataType: 'json',
success: function(data) {
domains = data;
search(searchText, callback);
}
});
};
})()
});
I didn't test the code but it doesn't spawn one ajax request everytime you release a key but instead grabs the data once and then refers to the same data.

jQuery Ajax Race Condition best practice

In a button.click(function(){}); I have the following code:
var userId = $("#user-permission-edit").val();
var peId = $("#user-permission-entity-list").val();
var newParentPEId = $("#new-parent-pe").val();
var newPeName = $("#pe-name-add").val();
$.ajax({
type: "POST",
url: 'AddNewPE',
data: { 'targetUserId': userId, 'targetPEId': peId, 'newPeParentId': newParentPEId, 'newPeName': newPeName},
success: function (data) {
var dataObj = jQuery.parseJSON(data);
console.log(dataObj);
if (dataObj.status == "success") {
alert("Permissions have been updated.");
}
//update user PEs combo
}
});
However, I am concerned of a possible race condition of the variables not getting the values in time for the ajax call.
would something like this be safer?
var userId = $("#user-permission-edit").val();
var peId = $("#user-permission-entity-list").val();
var newParentPEId = $("#new-parent-pe").val();
var newPeName = $("#pe-name-add").val();
$.when(function() {
userId = $("#user-permission-edit").val();
peId = $("#user-permission-entity-list").val();
newParentPEId = $("#new-parent-pe").val();
newPeName = $("#pe-name-add").val();
}).done(function() {
$.ajax({
type: "POST",
url: 'AddNewPE',
data: { 'targetUserId': userId, 'targetPEId': peId, 'newPeParentId': newParentPEId, 'newPeName': newPeName},
success: function (data) {
var dataObj = jQuery.parseJSON(data);
console.log(dataObj);
if (dataObj.status == "success") {
alert("Permissions have been updated.");
}
//update user PEs combo
}
});
});
Is this even necessary?
The $('....').val() method is a synchronous call - your script execution won't continue past that line until you have received the value of that element.

JQuery won't pass data labeled sessid when calling drupal service module

Hey all I am working on a json call that will implement Drupal's services module with json. I am using jquery's ajax function to call the function but I am getting an error stating that no parameters are being passed. When I look at the query string being posted I notice that sessid is not being passed even though its with the parameters. Below is what Im running.
// JavaScript Document
$(document).ready(function() {
function drupalConnect(src) {
$.ajax({
url: src,
type: 'POST',
data: {
method: 'system.connect'
},
success: function(data) {
return data["result"]["sessid"];
}
});
}
function getTimestamp() {
return Math.round((new Date).getTime() / 1000);
}
function randString(length) {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < length; i++) {
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}
var session_id = drupalConnect('http://localhost/drupal/services/json-rpc');
var nonce = randString(10);
var timestamp = getTimestamp();
var username = "markusgray";
var password = "Markus1990";
var key = '2ae0392e0aebbfeeddefcc962ea1924f';
var domain = 'localhost';
var hashObj = new jsSHA(timestamp + ";" + domain + ";" + nonce + ";user.login", "TEXT");
var hash = hashObj.getHMAC(key, "TEXT", "SHA-256", "HEX");
var parameters = {
hash: hash,
domain_name: domain,
domain_time_stamp: timestamp,
nonce: nonce,
sessid: session_id,
username: username,
password: password
};
var par = JSON.stringify(parameters);
$.ajax({
url: 'http://localhost/drupal/services/json-rpc',
type: 'POST',
dataType: 'json',
data: {
method: 'user.login',
params: par
},
success: function() {
}
});
});​
drupalConnect doesn't return anything, also the return from the success callback is just thrown away. The best way to use the data returned from an ajax call is to use it in thee callback itself.
function drupalConnect(src){
$.ajax({
url: src,
type: 'POST',
data:{method:'system.connect'},
success: function(data){
var session_id = data["result"]["sessid"];
//use session_id here
}
});
}
It is because of the Asynchronous ajax, let me elaborate, to get the session_id you are making an ajax call. At the moment it will send the request, but it wont ensure that the session_id will be assigned at that moment. Hence when you making the second ajax call, the session_id may not be assigned for a value.
There are two workarounds for this,
One is, making the first ajax call with an option async:false and assign the value within the success call, something like
var session_id;
function drupalConnect(src) {
$.ajax({
url: src,
type: 'post',
async : false,
data: {
method: 'system.connect'
},
success: function(data) {
session_id = data["result"]["sessid"];
}
});
};
DEMO
The second one and preferred way is, use of deferred objects, something like
$.when(
// make your first ajax request
).then(function(data) {
session_id = data["result"]["sessid"];
// make your second ajax call
});​
DEMO

Categories