Convert jQuery.ajax code to accept pagination - javascript

I'm trying to take code which I found on a website's blog regarding using javascript and REST to create charts in SharePoint. The original article can be found here for reference -- http://www.cardinalsolutions.com/blog/2013/05/building_charts_ins -- I've already tried reaching out to the writer asking for help but I haven't gotten a response.
"use strict";
var EngagementChartBuilder = window.EngagementChartBuilder || {};
//The module for executing a REST query
EngagementChartBuilder.RESTQuery = function (listTitle, query) {
var execute = function (listTitle, query) {
var restUrl = _spPageContextInfo.webServerRelativeUrl +
"/_api/web/lists/getByTitle('" + listTitle + "')/items";
if (query != "") {
restUrl = restUrl + "?" + query;
}
var deferred = $.ajax({
url: restUrl,
type: "GET",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
}
});
return deferred.promise()
};
return {
execute: execute
}
}();
When this code executes, though, it only returns the first 100 results due to SharePoint's pagination. I found articles/posts which points me in the direction of using the data.d.__next into the URL and re-run the AJAX query, but trying to understand this JavaScript code is really making my head spin.
I thought I could do a do-while loop but I'm really not making any progress.
Any help would be immensely appreciated. Thanks in advance.

You can add $top and $skip parameters to your endpoint URL (in your case, the restUrl string) to specify how many items to retrieve and how many items to skip respectively.
Use the $skip=n parameter to skip the first n entries according to the $orderby parameter
Use the $top=n parameter to return the top n entries according to the $orderby and $skip parameters.
To page through results, you just need to update the $skip token and requery.
The following example gets items in batches of 1000:
var endpointUrl = "/_api/lists('guid')/items";
$.getJSON(
endpointUrl + "?$orderby=Id&$top=1000",
function(data){
processData(data); // you can do something with the results here
var count = data.d.results.length;
getNextBatch(count, processData, onComplete); // fetch next page
}
);
function getNextBatch(totalSoFar, processResults, onCompleteCallback){
$.getJSON(
endpointUrl + "?$orderby=Id&$skip="+totalSoFar+"&$top=1000",
function(data){
var count = data.d.results.length;
if(count > 0){
processResults(data); // do something with results
getNextBatch(totalSoFar+count, callback); // fetch next page
}else{
onCompleteCallback();
}
}
);
}
Integrating that concept with jQuery deferreds is another matter.
I recommend you either:
take some time to learn about the functionality encapsulated in jQuery deferreds so that you can use them effectively, or
abandon deferreds entirely and just use your own asynchronous functions with callbacks, as in the documentation example

$skip does not work in SharePoint 2013/ SharePoint line OData REST.
There is a property in the SharePoint REST API response named "__next" that you can use to implement pagination.
This link contains "$skiptoken", that is useful for pagination.
I think you should try to implement the following way :
Use $filter -->
/_api/web/Lists/GetByTitle(ListTitle)/items?$filter=Id gt {valueSkipFrom}&$top={ValueTop}
Use "__next" link. This can be accessed as "response.d.__next"
If it has a value, it contains the url that will return the next set of items. If it's null, you've hit the end of the result set
Please refer this link that will be guide you : https://sharepoint.stackexchange.com/questions/74777/list-api-get-all-items-limited-to-100-rows

Related

jquery ajax: process typeahead events in correct order?

I'm doing a webapp with html+jquery and a java rest-service backend.
I have a textfield, with typeahead suggestions, so every character the user types in the field
will trigger a server-round trip and update the list of typeahead suggestions.
Essential parts of the code:
var showTypeaheadSuggestions = function(data) {
// update ui-element ...
}
var displayFailure = function() {
// update ui-element ...
}
var searchText = $("#searchText");
var searchTextKeyup = function() {
var txt = searchText.val();
$.ajax({
url : typeaheadUrl(txt),
type : 'GET',
dataType : 'json',
}).done(showTypeaheadSuggestions).fail(displayFailure);
}
searchText.on('keyup', searchTextKeyup);
It's basically working.
But I was thinking abt what happens if you type, for example, 2 letters "ab" (that will trigger first a request for "a" and then a request for "ab")...
Then, what happens if the "a" response takes a bit longer to process, and arrives after the "ab" response?
Do I need to detect this in my code, to throw away the "a" response?
In http://api.jquery.com/jquery.ajax/ it does says:
Promise callbacks ā€” .done(), .fail(), .always(), and .then() ā€” are
invoked, in the order they are registered.
What does that mean exactly?
I was hoping this means $.ajax() would automatically handle the above scenario correct.
But when I do a small test (on the server-side I simply injected a 2 secs sleep-delay, only when the search-string is exactly "a"),
it turns out it does not behave as I expected.
The typeahead list will first get updated with the "ab" response, and then when the "a" response
arrives, it also updates, so the typeahead list gets the wrong suggestions.
What is the established way to handle this correctly?
There's another approach if you want to keep the server side code without changes. You can actually wrap the return functions inside a class and create instances for each request, then store the latest instance in a global scoped variable and check if the owner of the invoked method does match the latest instance:
var lastRequest;
var searchText = $("#searchText");
function requestClass()
{
var that = this;
this.showTypeaheadSuggestions = function(data) {
//Update ui-element
if (lastRequest == that)
console.log('suggestions retrieved: ' + data);
else
console.log('this response (' + data + ') is ignored');
};
this.displayFailure = function() {
//Update ui-element
console.log('failure');
};
}
var searchTextKeyup = function() {
var request = new requestClass();
lastRequest = request;
var txt = searchText.val();
$.ajax({
url : typeaheadUrl(txt),
type : 'GET',
dataType : 'json',
}).done(request.showTypeaheadSuggestions).fail(request.displayFailure);
}
searchText.on('keyup', searchTextKeyup);
I have tested this with the small-test you proposed in the question (adding a 2 seconds delay when the search string does match the 'a' character) and the result is the following:
suggestions retrieved: ab
this response (a) is ignored
One of the ways I approached this problem was to assign an ID for each time you call it, and pass it as an ID to server side. When your server is done processing it, it then sends the result back along with it's id.
Then, every time the client side code runs, the ID will increment. For example:
var callback_id = 0;
var searchText = $("#searchText");
var searchTextKeyup = function() {
callback_id ++;
var txt = searchText.val();
$.ajax({
url : typeaheadUrl(txt),
data : callback_id,
type : 'GET',
dataType : 'json',
}).done(showTypeaheadSuggestions).fail(displayFailure);
}
searchText.on('keyup', searchTextKeyup);
Then, when you receive the response back, you check if the id is the current one. In the event that the user fires two events at once, your ajax event will be triggered twice, once with callback_id = 0, and one with callback_id = 1.
The last thing you have to then do is an if statement only updating your TypeaheadSuggestions if the callback_id is the most current one by comparing the id sent back from your server response.
You must compare new input text with text you sent, and if it what user wants to find - you will show it, otherwise do nothing with response.
For example :
var searchText = $("input").val()
$.ajax({
....
data: {searchText : searchText}
success: funtion(){
if($("input").val()==searchText){
//SHOW RESULTS
}
}
})
The Promises interface returns to you a "Promise object" immediately so that you can use a different syntax for the callback.
Instead of:
asyncCall(callback);
You can use:
asyncCall()
.then(callback);
And you can chain these:
authorizeAccount()
.then(getNames)
.then(processNames);
The callbacks will be executed in the order you register them -- processNames will wait for getNames to resolve first.
The "established" way to handle this "correctly" is probably to add some client-side debouncing so that only the whole request ('query' instead of 'q', 'qu' 'que'...) is processed when you are typing the word:
http://underscorejs.org/#debounce with a timeout that expires a response if it takes too long to come back.

HTTP request with javascript and formatting the parameter and values after length

I'm having a slight issue here.
I'm trying to make a function that is supposed to send a HTTP request in Javascript which will then return data that I will be using on the website.
Anyways the issue I'm having here is that the parameters and values will not always be the same.
function getresults(values){
if(values != ''){
var exploded = values.split("&");
var getarr = exploded.split("=");
var array = new Array();
exploded.forEach(function(entry) {
var newexplode = entry.replace("=", ":");
array[newexplode[0]] = newexplode[1];
});
$.get(
"results.php",
{param : "value"},
function(data) {
alert(data);
}
);
}
};
So, what I need to do is to input all of the contents of the array into the the curlybrackets, where I've done an example of how params and values and sent.
getresults("search=general&searchterm=asd&wildcardend=no&wildcardbegin=no&page=1")
Here's an example of the call of an input.
The amount of parameters can vary and it'll be impossible to know how many I will have and so on.
I either need a new way of doing a HTTP request that is cross-browser compatible or I need some way of inputting this into the param:value curlybrackets.
Once again, read this carefully, I can't know how many params I will be recieving in beforehand as it may vary, and I will not be able to know in what order they are 100% either.
[EDIT] I made a dumb bypass which works, but I'm still interested if there are any alternate solutions.
Instead of constructing array you probably should be constructing a JSON Object
var paramObj = {};
for ( var entry in exploded){
paramObj[entry] = entry.split('=')[1];
}
$.get(
"results.php",
{param : paramObj},
function(data) {
alert(data);
}
);

storing AJAX response into variable for use later in script?

here is the gist of my code: https://gist.github.com/tconroy/e52e0e7402face8f048e
Basically, my program is broken down into several steps:
retrieve user input from N number of inputs (user can add/remove)
perform AJAX query on each input, retrieving JSON formatted weather data for each.
on successful AJAX, pass the data to dataReady() function.
dataReady() function stores the data into a global Array[]
The problem is the AJAX data is not storing in the global array. how can I save the JSON response for use later in the program? I need to store all my weather data in one array, so I can iterate through it to create my graph later in the program.
The part causing issues in particular:
function getWeatherData(){
// set up query strings.
var queryBase = "http://api.worldweatheronline.com/free/v1/weather.ashx?q=",
queryEnd = "&format=json&num_of_days=5&key="+weatherAPIKey;
// iterate through each address input
$('.inp').each(function(){
// setup query
var inp = this;
var addr = encodeURIComponent( inp.value );
var query = queryBase + addr + queryEnd;
// perform query
$.ajax({
url: query,
async: false,
dataType: 'jsonp',
success: function(json){
// format our response data into object, push it into container array.
var objName = String(decodeURIComponent(addr));
var objVals = json.data.weather;
dataReady(objName, objVals);
},
error: function(){
alert(errMsg);
}
});
}); // end $('.inp').each();
// setup the graph
setupGraph();
} // end getWeatherData();
function dataReady(objName, objVals) {
console.log('dataReady() called.');
responseValues[objName] = objVals;
}
From what I understand (see comments) you are dealing with a typical problem with asynchronous calls. You call AJAX, then you call setupGraph() but the ajax response will arrive after that call, because it is asynchronous.
First of all, doing async: false is bad, wrong and the source of all evil. Don't use it never ever. In your case it won't even work, because you can't force JSONP to be synchronous. But even if you could let me repeat my self, because this is important: don't ever use async: false.
Now back to your problem. What you should is to use deferred callbacks instead:
var reqs = [];
$('.inp').each(function(){
// some code
reqs.push(
$.ajax({
// some settings
})
);
});
$.when.apply($, reqs).then(function() {
setupGraph();
});
Read more about $.when here: https://api.jquery.com/jQuery.when/

Rendering mongodb database results from POST request in .ajax jquery wrapper in node js

I am creating a basic piece of functionality to allow users to send their location to a server which then queries a database and returns locations near to them. I am using the below jQuery .ajax wrapper to POST data to the server. This takes the form of a latlon point which is then used as the basis for a geosearch in MongoDB using nodejs and express on the backend. The results of the search are then intended to be returned to the client and rendered by the createMapListings function.
The /find page is initially rendered through a GET request to the database via mongodb separate from the below code. However subsequent to initial rendering, I then want to return results dependent on the location provided.
The POST method works fine and the location is posted to the server, with the search results being returned as I can print contents out through the console log.
However, I then want to render the results on the client-side. As mentioned, the results of the search render in the console, but when I attempt to pass through to the client, I can render the data itself (in the form of an array of objects) in the #output div, but the createMapListings function does not seem to catch the data.
In fact, the below function appears to be called but prints out over a thousand rows with the data that should be caught described as 'undefined'. I have tried to use res.render and res.redirect, but in the first case, the view renders in the div (which I suppose is expected) and the redirect fails.
The createMapListings function works fine when a simple GET request is made to the server, for example, for all objects in a collection, using ejs template. However, I think the issue here may be a combination of a POST request and then wanting to pass the results back to the AJAX request using the complete callback.
I apologise if the below code is somewhat obtuse. Iā€™m definitely what you would call a beginner. I appreciate the above functionality may not possible so if there is a better way, I would of course be open to it (res.direct perhaps).
Here is the relevant client side script:
$(document).ready(function(){
$("#geolocate").click(function(){
navigator.geolocation.getCurrentPosition(geolocate, function(){
});
});
});
function geolocate(pos){
var latlonpt = [];
var x = pos.coords.latitude;
var y = pos.coords.longitude;
latlonpt.push(x);
latlonpt.push(y);
var obj = {
userlocation: latitudelongitudept
};
$.ajax({
url: "/find",
type: "POST",
contentType: "application/json",
processData: false,
data: JSON.stringify(obj),
complete: function (data) {
$('#output').html(data.responseText);
$('#infooutput').children().remove();
createMapListings(data.responseText);
}
});
};
function createMapListings(maps) {
for (var i = 0; i < maps.length; i++) {
var url = maps[i]._id;
var fullurl = "<a href='/show?id=" + url + "'>Route</a></div>";
var title = "<div>" + maps[i].title + " - " + fullurl +"";
$('#infooutput').append(title);
};
};
</script>
Here is the relevant route used in a basic express app to handle the post request made by the above .ajax wrapper.
exports.findbylocation = function(req, res) {
console.log(req.body.userlocation);
var userlocation = req.body.userlocation;
Map.ensureIndexes;
Map.find({loc :{ $near : userlocation }}, function(err, maps) {
if (err) {
console.log(err)
}
else {
var jmaps = JSON.stringify(maps);
console.log(jmaps);
res.send(jmaps);
}
});
};
By convention, the data variable name in an $.ajax callback signature refers to the parsed HTTP response body. Since your callback is on complete, we're actually passed the XMLHttpRequest used, by convention called xhr. You rightly grab the responseText property, but this needs parsing to be useful. So long as we take care over our Content-Type's and don't explicitly disable processData, jQuery will do the encoding/unencoding for us - we just deal with objects. This is a good thing, since the transport format isn't usually of any particular importance to the application logic. If we use res.json(maps) in place of res.send(jmaps), we can write our call more simply:
$.ajax({
url: '/find',
type: 'POST',
data: obj,
success: function(data) {},
error: function(xhr, text, err) {}
});
Here data is a Javascript object already parsed and ready to use. We also use a default application/x-www-form-urlencoded request rather than explicitly setting a contentType. This is the same as far as express is concerned: it will just be parsed by urlencoded instead of json.
Assuming you solved your client-sie problem.
As you are using express there is no need for JSON.stringfy,
you can use res.json(maps).

How to pass data from one HTML page to another HTML page using JQuery?

I have two HTML pages that work in a parent-child relationship in this way:
The first one has a button which does two things: First it requests data from the database via an AJAX call. Second it directs the user to the next page with the requested data, which will be handled by JavaScript to populate the second page.
I can already obtain the data via an ajax call and put it in a JSON array:
$.ajax({
type: "POST",
url: get_data_from_database_url,
async:false,
data: params,
success: function(json)
{
json_send_my_data(json);
}
});
function json_send_my_data(json)
{
//pass the json object to the other page and load it
}
I assume that on the second page, a "document ready" JavaScript function can easily handle the capture of the passed JSON object with all the data. The best way to test that it works is for me to use alert("My data: " + json.my_data.first_name); within the document ready function to see if the JSON object has been properly passed.
I simply don't know a trusted true way to do this. I have read the forums and I know the basics of using window.location.url to load the second page, but passing the data is another story altogether.
session cookie may solve your problem.
On the second page you can print directly within the cookies with Server-Script tag or site document.cookie
And in the following section converting Cookies in Json again
How about?
Warning: This will only work for single-page-templates, where each pseudo-page has it's own HTML document.
You can pass data between pages by using the $.mobile.changePage() function manually instead of letting jQuery Mobile call it for your links:
$(document).delegate('.ui-page', 'pageinit', function () {
$(this).find('a').bind('click', function () {
$.mobile.changePage(this.href, {
reloadPage : true,
type : 'post',
data : { myKey : 'myVal' }
});
return false;
});
});
Here is the documentation for this: http://jquerymobile.com/demos/1.1.1/docs/api/methods.html
You can simply store your data in a variable for the next page as well. This is possible because jQuery Mobile pages exist in the same DOM since they are brought into the DOM via AJAX. Here is an answer I posted about this not too long ago: jQuery Moblie: passing parameters and dynamically load the content of a page
Disclaimer: This is terrible, but here goes:
First, you will need this function (I coded this a while back). Details here: http://refactor.blog.com/2012/07/13/porting-javas-getparametermap-functionality-to-pure-javascript/
It converts request parameters to a json representation.
function getParameterMap () {
if (window.location.href.indexOf('?') === (-1)) {
return {};
}
var qparts = window.location.href.split('?')[1].split('&'),
qmap = {};
qparts.map(function (part) {
var kvPair = part.split('='),
key = decodeURIComponent(kvPair[0]),
value = kvPair[1];
//handle params that lack a value: e.g. &delayed=
qmap[key] = (!value) ? '' : decodeURIComponent(value);
});
return qmap;
}
Next, inside your success handler function:
success: function(json) {
//please really convert the server response to a json
//I don't see you instructing jQuery to do that yet!
//handleAs: 'json'
var qstring = '?';
for(key in json) {
qstring += '&' + key + '=' + json[key];
qstring = qstring.substr(1); //removing the first redundant &
}
var urlTarget = 'abc.html';
var urlTargetWithParams = urlTarget + qstring;
//will go to abc.html?key1=value1&key2=value2&key2=value2...
window.location.href = urlTargetWithParams;
}
On the next page, call getParameterMap.
var jsonRebuilt = getParameterMap();
//use jsonRebuilt
Hope this helps (some extra statements are there to make things very obvious). (And remember, this is most likely a wrong way of doing it, as people have pointed out).
Here is my post about communicating between two html pages, it is pure javascript and it uses cookies:
Javascript communication between browser tabs/windows
you could reuse the code there to send messages from one page to another.
The code uses polling to get the data, you could set the polling time for your needs.
You have two options I think.
1) Use cookies - But they have size limitations.
2) Use HTML5 web storage.
The next most secure, reliable and feasible way is to use server side code.

Categories

Resources