Dynamic variable creation for multiple AJAX calls (SharePoint Online) - javascript

I use the following code to generate jquery datatables with data returned from SharePoint Online JSON on AJAX call. As My SPO list has over 50K rows and SPO has a 5000 view threshold limit, i make multiple ajax calls with REST API multiple date range filters and concat the results. The concatenated results are then passed as data source for the datatables plugin.
Kindly assist to shorten the following code for year variables and make the same to dynamically enter date ranges to make multiple AJAX calls. I'm guessing the process is to first read current year, generate first and last dates for current year, and then create new variables in descending order till 2005.
var results;
var allResults = [];
$(document).ready(function () {
load();
});
function load() {
var year2021 = $.ajax({
url: "SPO_Site/_api/web/lists/getbytitle('SPO_List')/items?$top=5000&$select=*,EncodedAbsUrl&$filter=(Date%20ge%20datetime%272020-12-31T00:00:00.000Z%27)%20and%20(Date%20le%20datetime%272021-12-31T00:00:00.000Z%27)",
type: "GET", dataType: "json", headers: {"accept": "application/json;odata=verbose"},
success: mySuccHandler, error: myErrHandler});
var year2020 = $.ajax({
url: "SPO_Site/_api/web/lists/getbytitle('SPO_List')/items?$top=5000&$select=*,EncodedAbsUrl&$filter=(Date%20ge%20datetime%272019-12-31T00:00:00.000Z%27)%20and%20(Date%20le%20datetime%272020-12-31T00:00:00.000Z%27)",
type: "GET", dataType: "json", headers: {"accept": "application/json;odata=verbose"},
success: mySuccHandler, error: myErrHandler});
.
.
.
.
.
var year2005 = $.ajax({
url: "SPO_Site/_api/web/lists/getbytitle('SPO_List')/items?$top=5000&$select=*,EncodedAbsUrl&$filter=(Date%20ge%20datetime%272004-12-31T00:00:00.000Z%27)%20and%20(Date%20le%20datetime%272005-12-31T00:00:00.000Z%27)",
type: "GET", dataType: "json", headers: {"accept": "application/json;odata=verbose"},
success: mySuccHandler, error: myErrHandler});
function mySuccHandler(a) {
results = a.d.results;
if (allResults.length > 0)
allResults = allResults.concat(results);
else
allResults = results;
}
function myErrHandler(data, errorCode, errorMessage) {
console.log("Could not complete call: " + errorMessage);
};
$.when(year2021, year2020, year2019, year2018, year2017, year2016, year2015, year2014, year2013, year2012, year2011, year2010, year2009, year2008, year2007, year2006, year2005).done(function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17){
$('#table_id').DataTable({
data:allResults,
dom: 'Bfrtip',
columns: [
{ data: "Reg" },
{ data: "EncodedAbsUrl",
"render": function (data, type, full)
{return 'View';}
}
]
});
});
};

When your find yourself copy-pasting code, stop immediately and write a function and a loop.
When you find yourself copy-pasting code 15 times, you should have stopped 14 times ago to write a function and a loop.
The function:
function getItemsByYear(year, topRows=5000) {
return $.ajax({
type: "GET",
headers: {
Accept: "application/json;odata=verbose"
},
url: "SPO_Site/_api/web/lists/getbytitle('SPO_List')/items?" + $.param({
$top: topRows,
$select: '*,EncodedAbsUrl',
$filter: `(Date ge datetime'${year}-01-01T00:00:00.000Z') and (Date lt datetime'${year + 1}-01-01T00:00:00.000Z')`
}),
})
.then(function (response) {
return response.d.results;
})
.fail(function (data, errorCode, errorMessage) {
console.log("Could not complete call: " + errorMessage);
});
}
The loop:
$(function () {
let currentYear = (new Date()).getFullYear(),
requests = [];
for (let counter = 0; counter < 15; counter++) {
requests.push(getItemsByYear(currentYear - counter));
}
$.when.apply($, requests).done(function (itemsByYear) {
$('#table_id').DataTable({
data: itemsByYear.flat(),
dom: 'Bfrtip',
columns: [
{ data: "Reg" },
{ data: "EncodedAbsUrl", "render": function (data, type, full)
{return 'View';}
}
]
});
});
});

Related

ajax loading before document despite using when().then() function with leaflet JS

Here is what the console reads:
Uncaught TypeError: Cannot read property 'addTo' of undefined
I am currently working with leaflet JS and before the page loads, there is quite a number of Ajax calls going on so that the website can render the acquired data for the user.
I have used two particular methods to synchronize certain ajax calls which rely on the previous. One method is passing the next ajax call into the complete function, whilst another is the when().then() function
The objective with the function below, which is called with the window.onload method, is to determine the users location using the javascript navigator, set the map, and proceed with the ajax calls as mentioned above.
$(window).on('load', function() {
//Pre-loader Jquery
if ($('#preloader').length) {
$('#preloader').delay(200).fadeOut('slow', function() {
$(this).remove();
});
}
//Determine users location, initiate leaflet map, synchornised ajax calls to retreive country core information
navigator.geolocation.getCurrentPosition((success) => {
const crd = success.coords;
onLoadLat = crd.latitude;
onLoadLng = crd.longitude;
currentMap = L.map('map').setView([onLoadLat, onLoadLng], 5);
mapTileLayer.addTo(currentMap);
$.ajax({
url: "libs/php/openCage.php",
type: "POST",
dataType: "JSON",
data: {
latLng: onLoadLat + "+" + onLoadLng
},
success: function(data, textStatus, jqXHRs) {
iso_a2 = data["results"][0]["components"]["ISO_3166-1_alpha-2"];
},
complete: function() {
//Retreive GeoJson file, mark polygon and set initial map for to reflect user location
$.ajax({
url: "libs/php/getCountryBorder.php",
type: "POST",
dataType: "JSON",
data: {
countryCode: iso_a2
},
success: function(geoData, txtSt, jq) {
//Reference details of existing country for further API's and functionality
nameOfCountry = geoData["properties"]["name"];
//Use the index to target the array and create polygon border on map
targetMapData = L.geoJSON(geoData, {
style: borderStyle
});
targetMapData.addTo(currentMap);
currentMap.fitBounds(targetMapData.getBounds(), {
padding: [50, 50],
});
},
complete: function() {
$.ajax({
url: "libs/php/keyCountryInfo.php",
type: "POST",
dataType: "JSON",
data: {
country_code: iso_a2
},
success: function(data, textStatus, jqXHR) {
capitalCity = data["capital"];
currencyCode = data.currencies[0].code;
coordinates = [...data.latlng];
$("#timezoneList").empty();
$("#countryName").text(data["name"]);
$("#region").text(data["region"]);
$("#sub-region").text(data["subregion"]);
$("#countryFlag").attr("src", data["flag"]);
$("#population").text(numeral(data["population"]).format(0, 0));
$("#capital").text(data["capital"]);
$("#timezoneList").text(data["timezones"][0]);
},
complete: function() {
$.when(**getPopularCities()**, getCityWeatherList(), getWikiEntries(onLoadLat, onLoadLng), getGeoNameId(), getCountryImages(), getPublicHolidays(), getLatestExchange(), populateSelect()).
then(function(data, textStatus, jqXHR) {
infoEasyBtn.addTo(currentMap);
wikiEasyBtn.addTo(currentMap);
currencyEasyBtn.addTo(currentMap);
covidEasyBtn.addTo(currentMap);
newsEasyBtn.addTo(currentMap);
weatherEasyBtn.addTo(currentMap);
airportMarkers.addTo(currentMap);
cityMarkers.addTo(currentMap);
siblingMarkers.addTo(currentMap);
});
}
})
}
})
}
})
})
});
within the onload function above, is the getPopularCities() method, which is where the issue is. I have set markers to be shown on the map, but there is one group of markers which do not load, from within that function
Get Popular Cities Method
function getPopularCities() {
let cityPopulation = [];
cityMarkers = new L.MarkerClusterGroup();
if (mainLayer) {
currentMap.removeControl(mainLayer);
}
$.ajax({
url: "libs/php/getCountryCities.php",
type: "POST",
dataType: "JSON",
data: {
getCountryIso: iso_a2
},
success: function(success, textStatus, jqXHRs) {
$("#top10CityTable").empty();
let cityList = success["cities"]; //grab all the cities from the response
//create an array in global variable named cityPopulation, to contain all the markers
cityList.sort((a, b) => {
if (a["population"] > b["population"]) {
return -1
} else {
return 1
}
})
cityList.forEach((element, index) => {
let formatedPop = numeral(element["population"]).format(0, 0);
//depending on how many citys have returned, title the heading accordingly
if (cityList.length < 10) {
$("#top10CityHeading").text("Major Cities")
}
if (cityList.length >= 10) {
$("#top10CityHeading").text("Top 10 Most Populated Cities");
}
//stop index at 9 to get data of top 10 most populated cities for modal section
if (index <= 9) {
$("#top10CityTable").append(`<tr><td>${element["name"]}</td><td>${formatedPop}</td></tr>`)
}
cityMarkers.addLayer(L.marker([element["latitude"], element["longitude"]], {
icon: populatedCities
}).bindPopup(`<h3>${element["name"]}</h3></br>Population: ${formatedPop}`));
})
//create a new overlay prop/value pairing in the global overlays variable
overlays["Major Cities"] = cityMarkers;
},
error: function(text, xh, errorThrown) {
console.log(errorThrown);
},
complete: function() {
let siblingsMapArr = [];
siblingMarkers = new L.MarkerClusterGroup();
$.ajax({
url: "libs/php/getCountrySiblings.php",
type: "POST",
dataType: "JSON",
data: {
countryGeoId: geoNameId
},
success: function(success, textStatus, jqXHRs) {
$("#countrySiblings").empty();
let siblingsArr = success["geonames"];
siblingsArr.sort((a, b) => {
if (a["population"] > b["population"]) {
return -1
} else {
return 1
}
})
let top10Sib = siblingsArr.slice(0, 10);
top10Sib.forEach((element, index) => {
let formatedPop = numeral(element["population"]).format(0, 0);
let rank = index + 1;
siblingMarkers.addLayer(L.marker([element["lat"], element["lng"]], {
icon: citySiblings
}).bindPopup(`<h3>${rank}. ${element["countryName"]}</h3><br/>Population: ${formatedPop}`));
$("#countrySiblings").append(`
<tr>
<td>${element["countryName"]}</td>
<td>${formatedPop}</td>
<td>${element["lat"]} / ${element["lng"]}</td>
</tr>`)
})
overlays["Top 10 Siblings (By Population)"] = siblingMarkers;
},
complete: function(success, data, jq) {
$.ajax({
url: "libs/php/getAirports.php",
type: "POST",
dataType: "JSON",
data: {
countryCode: iso_a2
},
success: function(success, txtStatus, jqXHR) {
let airportsArr = [];
airportMarkers = new L.MarkerClusterGroup();
const airportsList = success["data"];
airportsList.forEach((element) => {
airportMarkers.addLayer(L.marker([element["location"]["latitude"], element["location"]["longitude"]], {
icon: airportIcon
}).bindPopup(`<h3>${element["name"]["original"]}</h3></br>ICAO: ${element["icao"]}</br>Elevation: ${element["elevationFeet"]}<br/>Classification: ${element["classification"]}`));
})
overlays["Airports"] = airportMarkers;
mainLayer = L.control.layers(baseMaps, overlays);
mainLayer.addTo(currentMap);
airportMarkers.addTo(currentMap);
cityMarkers.addTo(currentMap);
siblingMarkers.addTo(currentMap);
}
})
}
})
}
})
}
The markers saved in the variable airportMarkers and cityMarkers appear on the map as well as the leaflet control panel, but the siblings markers do not.
So Im guessing the safe bet is that it is not bringing the data back in time before the page loads? Does anyone have a solution for this or perhaps I have done something wrong in my code?

select2 returning position of items, not ID of items

I'm using a select2 to allow the user to select multiple options. Everything is working fine, except for one frustrating issue.
The first time I click the save button to save the items, it works. But then on subsequent calls, the ID of the items are replaced with the position of the items. For for example, if I have IDs 3, 6 and 10 selected, the first Save will work and 3,6,10 are passed to the controller.
But then if I reload the view and click save, the numbers 0,1,2 are passed in (ie, their relative positions in the select).
Here is the code:
Firstly, the HTML:
<select id="selectGroup" class="form-control" multiple="true">
On $(document).ready:
// Load Groups
$("#selectGroup").select2({ placeholder: 'Select' });
$.ajax({
url: ROOT_URL + "Group/GroupList",
type: "GET",
success: function (data) {
let dropdown = $('#selectGroup');
dropdown.empty();
dropdown.append($('<option></option>').attr('value', 0).text("(Select)"));
$.each(JSON.parse(data), function (key, entry) {
dropdown.append($('<option></option>').attr('value', entry.GroupID).text(entry.GroupName));
})
},
error: function (passParams) {
Notify(passParams, "Unexpected Error Loading Groups", "error");
}
});
And finally the js for the save (called from a button which passes in the loanID):
function LoanGroupSave(loanID) {
var grpIDs = '';
[].forEach.call(document.querySelectorAll('#selectGroup :checked'), function (elm) {
grpIDs += elm.value + ',';
})
var editURL = location.protocol + '//' + location.host + "/Loan/LoanGroupSave";
//alert(editURL);
var obj = { "LoanID": loanID, "GroupIDs": grpIDs };
alert(JSON.stringify(obj));
$.ajax({
type: "POST",
url: editURL,
data: JSON.stringify(obj),
contentType: "application/json; charset=utf-8",
dataType: "json",
}).done(function (response) {
if (response.success) {
Notify("Group(s) information has been saved", "Saved", "success", false, "toast-top-right", 5000);
}
else {
OpenPopupGeneral("Error(s)", response.message);
}
}).fail(function (jqXHR, textStatus, errorThrown) {
OpenPopupGeneral("Unexpected Error(s)", "Error = " + errorThrown);
});
}
Posting for people who make the same mistake.
Problem was in my load - I needed to add the GroupID as the key, not the row number which was in the key parameter value:
success: function (data) {
$.each(JSON.parse(data), function (key, entry) {
var $newOption = $("<option selected='selected'></option>").val(entry.GroupID).text(entry.GroupName);
$("#selectGroup").append($newOption).trigger('change');
}

Create variable in one script and use in another script. JQuery/HTML/JS

How can I turn the results from Script 1, Name, Email, Teamsinto variables I can use in script 2?
I am making an API call to fetch some JSON I then want to use certain values as text in a message I then send to slack.
Example.
$('.Name').html(data.user.name); // Returns John
$('.Email').html(data.user.email); // Returns John#John.com
$('.Teams').html(data.user.teams[0].name); // Returns JohnsTeam
var text = 'Hello my name is $Name + my email is $Email + From $Teams'
Output = Hello my name is John my email is John#John.com From JohnsTeam
Script 1
function currentUrl() {
return new Promise(function (resolve) {
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
resolve(tabs[0].url)
})
})
}
function userIdfromUrl(url) {
var parts = url.split('/')
return parts[parts.length - 1]
}
var authorizationToken = "xxxxxxxxxxxxxxxxxxxxxxxxx";
function myapiRequest(endpoint, options) {
$.ajax($.extend({}, {
type: 'GET',
dataType: "json",
success: function(data) {
$('.Name').html(data.user.name);
$('.Email').html(data.user.email);
$('.Teams').html(data.user.teams[0].name);
},
url: "https://api.myapi.com/" + endpoint,
headers: {
"Authorization": "Token token=" + authorizationToken,
"Accept": "application/vnd.myapi+json;version=2"
}
},
options));
}
currentUrl()
.then(function (url) {
return userIdfromUrl(url)
})
.then(function (userId) {
return myapiRequest('users/' + userId + '?include%5B%5D=contact_methods&include%5B%5D=teams')
})
.then(function (data) {
console.log(data.user.name)
console.log(data.user.email)
console.log(data.user.teams[0].name)
})
Script 2
$(document).ready(function(){
$('#contact-submit').on('click',function(e){
e.preventDefault();
var url = 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
var text = 'This is a message'
$.ajax({
data: 'payload=' + JSON.stringify({
"text": text // What I want to dynamically change
}),
dataType: 'json',
processData: false,
type: 'POST',
url: url
});
});
});
One great solution is to set the variable you get from the response in the HTML5 localstorage as follows:
Inside ur success:
success: function(data) {
localStorage.setItem("urdata",JSON.stringify(data));
}
In the other script, u can retrieve the data like this:
var data = localStorage.getItem("urdata"); data = JSON.parse(data);

How do I get the right $.ajax data type

could you please help with this. I have the following javascript:
$('form').click(function (e)
{
if (e.target.getAttribute('id') === 'SubmitAddLevel')
{
var parent = $('#' + e.target.getAttribute('attr')),
var Data = [];
parent.find('.input').children().each(function (i, e)
{
Data.push(e.getAttribute('id') + ":" + e.value);
console.log(Data);
});
$.ajax({
type: "POST",
url: 'AjaxControls.aspx/CreateUserLevel',
//data: Data, //.join(','),
dataType: "text",
contentType: "application/json; charset=utf-8",
//error: function (er) { alert(er); },
success: function (response)
{
if (response.d === "true")
{
$("#ErrorDivAddLevel").html('Level created successfully!').fadeIn('slow');
}
else
{
$("#SuccessDivAddLevel").html('Level creation failed!').fadeIn('slow');
}
},
});
}
The result of 'Data' I got on the console is :["LevelNameAddLevel:Admin", "PriviledgeIDAddLevels:|1|2|3|4|5|6|7|"]. How do I convert this to what ajax will pass to my web menthod?
Here is the web method
<WebMethod(EnableSession:=True)>
Public Shared Function CreateUserLevel(userLevel As String, userPriviledges As String) As String
return "true"
end function
I think your Data should look something more like this:
[{"LevelNameAddLevel":"Admin"}, {"PriviledgeIDAddLevels":"|1|2|3|4|5|6|7|"}]
So you have key / value pairs inside of an array. In the request, you should then be able to fetch the data via the keys in the request.
But I'm not quite sure what this is supposed to mean : "|1|2|3|4|5|6|7|"

Ajax Request Loop and Wait Until Complete

Is there a more efficient way to write the following? I need to loop through objList and pass the UnqKey to wfrmPrint. On success of that I then have to loop though the Pages. I am looping through the pages and unqkeys by passing a integer and checking to see if it is less than the length. I tried to use .when.apply taken from http://www.tentonaxe.com/index.cfm/2011/9/22/Using-jQuerywhen-with-a-dynamic-number-of-objects, but it was loading the unqkeys and then the pages.
//sample objList
[
{
"UnqKey": 1,
"Pages": [
"wfrmSet1Page1.aspx",
"wfrmSet1Page2.aspx"
]
},
{
"UnqKey": 2,
"Pages": [
"wfrmSet2Page1.aspx",
"wfrmSet2Page2.aspx",
"wfrmSet3Page2.aspx",
"wfrmSet4Page2.aspx"
]
}
]
function Loop(iListIndex) {
var obj = objList[iListIndex];
if (iListIndex < objList.length) {
jQuery.ajax({
type: "GET",
url: 'wfrmPRINT.aspx?action=LoadSession&UnqKey=' + obj.UnqKey, //load session that is used in wfrmSet1Pages.. or wfrmSet2Pages..
success: function () {
AddPages(obj, iListIndex, 0);
}
})
} else {
alert('Done');
}
}
function AddPages(obj, iListIndex, iPageIndex) {
if (iPageIndex < obj.Pages.length) {
jQuery.ajax({
type: "GET",
url: obj.Pages[iPageIndex] + '?Print=1', //load html
async: true,
success: function (html) {
iPageIndex++
AddPages(obj, iListIndex, iPageIndex);
},
error: function () {
alert('Failed!');
iPageIndex++
AddPages(obj, iListIndex, iPageIndex);
}
});
} else {
iListIndex++
Loop(iListIndex);
}
}
You might be able to do something like this,
function getData(arr,arrindex) {
$.ajax({
type: "GET",
url: 'wfrmPRINT.aspx?action=LoadSession&UnqKey=' + arr[arrindex].UnqKey
}).then(function(data){
var deferredObj = $.Deferred(), defArr = $.map(arr[arrindex].Pages,function(page){
return $.ajax({type: "GET", url: page + '?Print=1'});
});
$.when.apply(null,defArr).done(deferredObj.resolveWith).fail(deferredObj.resolveWith);
return deferredObj.promise();
}).done(function(){
arrindex++;
if (arr[arrindex]) {
getData(arr,arrindex);
}
else {
alert("done!");
}
}).fail(function(){
alert("FAIL!");
});
}
getData(objList,0);
It gets each wfrm sequentially, and when each one finishes, requests all of the pages for that one at once. Somewhat of a combination between your loop and a deferred $.when
Edit: fixed $.map argument order

Categories

Resources