cellUpdate from jqgrid custom formatter - javascript

I'm using jqgrid and am trying to request data from a webservice, parse it, and update a grid cell with the value. I expected to be able to do this with a custom formatter but I haven't been able to connect the dots on the asynchronous part of this function.
I've also ready that it may be wiser to use the gridLoaded { } call for this type of feature but in my mind the code I have below should work...
The formatter function gets called, make the async query which when completed fires the callback function which in turn updates the grid cell.
Any suggestions on what I may be missing would be greatly appreciated!
Thanks!
function recentPostsFormatter(cellValue, options, jsonVal) {
var encodedUrl = jsonVal.urlId;
var globalHTML = "";
var wsquery = 'webservice query goes here';
$.getJSON(wsquery, function (result) {
var html = "";
for (var i = 0; i < result.response.docs.length; i++) {
html += "<b>" + result.response.docs[i].title + "</b><br>" + result.response.docs[i].blogLink + ", " + result.response.docs[i].author + "<br>";
}
$("#blogListTable").jqGrid('setCell', object.rowId, 'recentPosts', html);
});
}

Related

Select2 local pagination/infinite scrolling

I'm using select2 version 4 and have a list with about 16,000 items. Predictably this is quite slow (take over 5 seconds to open sometimes) so I'm trying to find a way to speed this up.
Currently my data is being retrieved as an array using an ajax request and then inserted into the select2/dom using a for loop/appending.
$('#select').select2({
placeholder: "Select"
});
$.ajax("/Example/Data", {
type: 'GET'
})
.success(function (data, status, xhr) {
var option = '<option></option>';
for (var i = 0; i < data.length; i++) {
var curId = data[i].district_id;
var curDist = data[i].district_name;
var curState = data[i].state_short;
option += '<option value="' + curId + '">' + curDist + '('+ curState + ')' + ' - ' + curId + '</option>';
}
$('#select').append(option);
});
I've been trying to find a way to simply retrieve the data using the ajax request as I am doing now and then paginate/infinite scroll with the local but have been unable to do so
I've tried implementing this exactly: http://embed.plnkr.co/sUt9zi but I can't get it to work (maybe because it's using select2 v3.4.5) so if we could get that or something like it to work with v4 that would be great.
To prevent the 'slowness' you will need to mitigate creating and appending all 16k option elements at once. In order to do this the select2 library documents pagination using AJAX here: https://select2.org/data-sources/ajax#pagination
However, using the example you mentioned we can use a local dataset by doing something similar to:
var testData = [];
var dataSize = 1000;
// Instead of doing this use the AJAX call to poulate the data.
for (var i=0; i < dataSize; i++) {
testData.push({ text: `Data: ${i}`});
}
/*
Because you are sourcing your data via AJAX, this will
go in the success callback
*/
$("#testSelect").select2({
data: testData,
query: function(q) {
var pageLength = 50;
// Get a page sized slice of data from the results of filtering the data set.
var paged = this.data.slice((q.page - 1) * pageLength, q.page * pageLength);
q.callback({
results: paged,
more: this.data.length >= q.page * pageLength
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/select2/3.4.5/select2.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/select2/3.4.5/select2.min.js"></script>
<input type="text" id="testSelect" style="width: 200px"/>
Consider using server side to reduce the data instead
You are already using a remote data source, but you will need to pass some parameters to indicate which set of data is now necessary. The documentation shows doing this like:
$('#mySelect2').select2({
ajax: {
url: 'https://api.github.com/search/repositories',
data: function (params) {
var query = {
search: params.term,
page: params.page || 1
}
// Query parameters will be ?search=[term]&page=[page]
return query;
}
}
});
The query properties is important to pass the current page. This allows you to set an OFFSET in your sql query. Assuming you are using mysql your endpoint would be making a query similar to:
function getPageOfData(pageNum) {
var pageLength = 50;
var pageStart = (pageNum - 1) * pageLength;
var pageEnd = pageStart + pageLength;
var query = 'SELECT * FROM tbl LIMIT ' + pageStart + ',' + pageEnd;
}
Server side pagination is a bit complicated to set up as it requires the client to pass these parameters and the server to reply with a limited data set, but it will be the best option for handling large-ish datasets like yours.

Javascript - Ajax Request in SharePoint - Avoid to overwrite variable

Actually I have an issue with javascript. I find no solution for this problem yet.
Maybe someone of you could give me a hint.
I have a created a function, which is called by a button click.in SharePoint 2010.
The function should collect all selected / checked documents from a document library and write them into a separate box, I created. To get all selected documents works fine. But in SharePoint I have to load each element individually for details with an asynchronous request. Here comes my problem:
If I select more than one document, the variable "item" will be overwritten because of the "for" loop. In my asynchronous request success function, I use now the variable "item" again to get the details of it. So I always get the data of the last item of my selection.
Is there a way to avoid this?
Thanks for any help.
Here is my code:
function ApproveDocuments() {
var ClientContext = SP.ClientContext.get_current();
var LibraryID = SP.ListOperation.Selection.getSelectedList();
var Library = ClientContext.get_web().get_lists().getById(LibraryID); //Gets the current Library
var SelectedDocuments = SP.ListOperation.Selection.getSelectedItems(ClientContext);
for (var currentItem in SelectedDocuments) {
var item = Library.getItemById(SelectedDocuments[currentItem].id);
ClientContext.load(item, 'FileLeafRef');
ClientContext.executeQueryAsync(Function.createDelegate(this, function () {
var newElementHtml = '<div style="float:left;padding:3px;width:50px;"></div>';
newElementHtml += '<div style="float:left;padding:3px;">' + item.get_item('FileLeafRef') + '</div>';
newElementHtml += '<div style="clear:both;"></div>';
jQuery("#grol1855InfoDivData").append(newElementHtml);
}), Function.createDelegate(this, this.onLoadItemFailure));
}}
I would refactor this a bit so that you don't make an http request every time you iterate through the loop, which should also solve your over-write problem. I also declared the variables outside of the loops and make it point to the new version each iteration.
function ApproveDocuments() {
var ClientContext = SP.ClientContext.get_current();
var LibraryID = SP.ListOperation.Selection.getSelectedList();
var Library = ClientContext.get_web().get_lists().getByID(LibraryID); //Gets the current Library
var SelectedDocuments = SP.ListOperation.Selection.getSelectedItems(ClientContext);
var fileItems = [], item;
for (var currentItem in SelectedDocuments) {
item = Library.getItemById(SelectedDocuments[currentItem].id);
fileItems.push(item);
ClientContext.load(item, 'FileLeafRef');
}
ClientContext.executeQueryAsync(Function.createDelegate(this, function() {
var newElementHtml;
for (var i = 0; i < fileItems.length; i++) {
newElementHtml = '<div style="float:left;padding:3px;width:50px;"></div>';
newElementHtml += '<div style="float:left;padding:3px;">' + fileItems[i].get_item('FileLeafRef') + '</div>';
newElementHtml += '<div style="clear:both;"></div>';
jQuery("#grol1855InfoDivData").append(newElementHtml);
}
}), Function.createDelegate(this, this.onLoadItemFailure));
}
I would also really advise against writing new solutions that call any of the SOAP services or anything in _vti_bin for that matter; it's just a matter of time before those go away and your stuff won't work.
I have also tried ClientContext.executeQueryAsync in a loop but have never gotten it to work for similar reasons. I've worked around this before by using Ajax to call the SharePoint lists.asmx web service. For example:
var targetUrl = "/_vti_bin/lists.asmx";
var listName = "Shared Documents";
for (var currentItem in SelectedDocuments) {
var currentItemId = SelectedDocuments[currentItem].id;
var soapEnvArray = [];
soapEnvArray.push("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
soapEnvArray.push("<soap:Envelope ");
soapEnvArray.push("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">");
soapEnvArray.push("<soap:Body><GetListItems xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\"><listName>" + listName + "</listName>");
soapEnvArray.push("<viewName></viewName>");
soapEnvArray.push("<query>");
soapEnvArray.push("<Where>");
soapEnvArray.push("<Eq>");
soapEnvArray.push("<FieldRef Name=\"ID\"></FieldRef>");
soapEnvArray.push("<Value Type=\"Counter\">" + currentItemId + "</Value>");
soapEnvArray.push("</Eq>");
soapEnvArray.push("</Where>");
soapEnvArray.push("</query>");
soapEnvArray.push("<viewFields>");
soapEnvArray.push("</viewFields>");
soapEnvArray.push("<rowLimit>2000</rowLimit><queryOptions><QueryOptions xmlns=\"\">");
soapEnvArray.push("<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>");
soapEnvArray.push("<ViewAttributes Scope = \"RecursiveAll\"/>");
soapEnvArray.push("</QueryOptions></queryOptions>");
soapEnvArray.push("</GetListItems></soap:Body></soap:Envelope>");
var soapEnv = soapEnvArray.join("");
$.ajax({
cache: false,
url: targetUrl,
type: "POST",
dataType: "xml",
data: soapEnv,
contentType: "text/xml; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetListItems");
},
complete: function (msg) {
if (msg.status == 200) {
var totalTaskCount = $(msg.responseXML).find("z\\:row, row").length;
$(msg.responseXML).find("z\\:row, row").each(function () {
console.log(currentItemId + ": " + $(this).attr("ows_Title"));
});
} else {
//Failure
var errorCode = $(msg.responseXML).find("errorcode").text();
var errorString = $(msg.responseXML).find("errorstring").text();
if (errorString.length === 0) {
errorString = $(msg.responseXML).find("faultstring").text();
}
errorString = errorString.replace(/(\r\n|\n|\r)/gm, "");
}
}
});
}
To make SharePoint Ajax requests easier, I would recommend picking up a copy of SharePoint CAML Query Helper for 2007, 2010, and 2013. Also, although I have never used it, you may want to consider trying the SPServices jQuery Library for SharePoint to simplify the task.

Cache each JSON search query with localStorage

THE PROMPT: We have a search that connects to an JSON API url. The search query is inside the url, and the API generates a new JSON file for every search term. We also cannot rely on the browser to cache for us, and we can't use PHP or server side caching; we need to use HTML5 LocalStorage (and we don't care that IE7 can't use it)
We need to cache every new JSON file for every new search. We want to cut down on requests per minute, so we want to use a cached version of the JSON file for repeated search terms.
WHERE I'M STUCK: What has made this difficult is caching a JSON file for each new/different search term. I have been able to cache the first search, but then all subsequent searches use the same cached JSON.
We need help rewriting this so each time a new search is made, it checks to see if the term was searched for previously and if so, grabs the corresponding JSON file. Then of course if the search term is new then cache a new JSON file for that specific search term.
WHAT I'VE TRIED: In my research I've seen a lot of very complicated solutions and I can't seem to get my head completely around all of it, some of these solutions almost worked, I think I just need a better explanation for this specific case.
I think this is the answer but I don't know how to apply it to my situation: jQuery deferred ajax cache
This is crazy and it almost works, it writes into the console when it recognizes that I've searched the same thing again, and it does stop a new request, but unfortunately the cached JSON isn't there, it returns no results.
Caching a jquery ajax response in javascript/browser
WHAT I HAVE SO FAR:
MY PSUEDO CODE:
var searchTerm = WHATEVER IS TYPED INTO THE SEARCHBOX
// The JSON file
var url = 'https://api.example.com/fake/json/path/{'+searchTerm+'}';
// Local Storage Caching Promise
var cachedData = localStorage.getItem("cachedData"),
def = $.Deferred();
if (!cachedData) {
def = $.getJSON(url, function(data) {
cachedData = data;
localStorage.setItem("cachedData", JSON.stringify(cachedData));
});
}
else{
cachedData = JSON.parse(cachedData);
def.resolve();
}
def.done(function() {
var resultHTML = '';
for(var i = 0; i < Object.keys(cachedData.things).length; i++){
$.each(cachedData, function(index, node){
resultHTML += '<li>'
resultHTML += '<h1>' + node[i].name + '</h1>';
resultHTML += '</li>';
});
}
$('div#results').html(resultHTML);
});
EXAMPLE JSON:
{
"things": [
{
"type": "thing",
"username": "randoguy",
"name": "name001",
},
{
"type": "thing2",
"username": "randoguy2",
"name": "name002",
},
...
Thank you #Ian for providing the hints to my answer!
var searchTerm = WHATEVER IS TYPED INTO THE SEARCHBOX;
// The JSON file
var url = 'https://api.example.com/fake/json/path/{'+searchTerm+'}';
// BABAM! Right here, SearchTerm + "-cachedData" gets unique cached data
var cachedData = localStorage.getItem(searchTerm + "-cachedData"),
def = $.Deferred();
if (!cachedData) {
def = $.getJSON(url, function(data) {
cachedData = data;
// BABAM! And here is where the unique cachedData is set! SearchTerm + "-cachedData"
localStorage.setItem(searchTerm + "-cachedData", JSON.stringify(cachedData));
});
}
else{
cachedData = JSON.parse(cachedData);
def.resolve(cachedData);
}
def.done(function(data) {
var resultHTML = '';
for(var i = 0; i < Object.keys(data.repositories).length; i++){
$.each(data, function(index, node){
resultHTML += '<li>'
resultHTML += '<h1>' + node[i].name + '</h1>';
resultHTML += '<p>' + node[i].owner + '</p>';
resultHTML += '</li>';
});
}
$('div#results').html(resultHTML);
});
Where would I be without StackOverflow. Thank you all!

Nested JSON fetch using jQuery

I am trying to create an RSS Feed kind of Message display from Yammer.
<script type="text/javascript">
var cleanit = null;
$(document).ready(function(){ cleanit = setInterval('callYammer()', 50);});
function callYammer(){
clearInterval(cleanit);
$.getJSON("./yammer.feed?request=messages",function(json) {
var objYammer = $("#yammerFeed");
objYammer.html('');
$.each(json.messages, function(i, m) {
if(!m.replied_to_id && m.body.plain){
var data = "<li>" + m.body.plain;
$.getJSON("./yammer.feed?request=users&userid="+m.sender_id,function(jsonUser) {
//alert(jsonUser.full_name);
data = data + " - "+jsonUser.full_name;
});
data = data + "</li>";
objYammer.append(data);
}
});
});
return false;
}
</script>
I want to display Message along with it's Username.
But in the end, from firebug debugger, what I see is the inner JSON data is not getting appended as I expected.
Though the calls are hitting and data is coming from the call, the
data = " - "+jsonUser.full_name;
is getting executed after all JSON calls for Users.
How do I append Username from inner JSON call to main JSON data?
You call the lines
data = data + "</li>";
objYammer.append(data);
in the code following your inner getJSON AJAX call, but that probably results in these lines being executed before the AJAX request has finished. Put the code INTO the inner AJAX success function to make sure it is fired only after the result is available.
function callYammer(){
clearInterval(cleanit);
$.getJSON("./yammer.feed?request=messages",function(json) {
var objYammer = $("#yammerFeed");
objYammer.html('');
$.each(json.messages, function(i, m) {
if(!m.replied_to_id && m.body.plain){
var data = "<li>" + m.body.plain;
$.getJSON("./yammer.feed?request=users&userid="+m.sender_id,function(jsonUser) {
console.log('1:'+jsonUser.full_name);
data += " - "+jsonUser.full_name + "</li>";
objYammer.append(data);
console.log('2:'+data);
});
}
});
});
Edit:
Just added the console.log() statements. What do they return?

jquery control execution of the callback functions

Function socialbookmarksTableData(data) is called by another function to generate the content of a table -- data is a JSON object. Inside the function i call 2 other functions that use getJSON and POST (with json as a return object) to get some data. The problem is: though the functions execute correctly i get undefined value for the 2 variables (bookmarkingSites, bookmarkCategories). Help with a solution please.
function socialbookmarksGetBookmarkCategories(bookmarkID)
{
var toReturn = '';
$.post("php/socialbookmark-get-bookmark-categories.php",{
bookmarkID: bookmarkID
},function(data){
$.each(data,function(i,categID){
toReturn += '<option value ="' + data[i].categID + '">' + data[i].categName + '</option>';
})
return toReturn;
},"JSON");
}
function socialbookmarksGetBookmarkSites()
{
var bookmarkingSites = '';
$.getJSON("php/socialbookmark-get-bookmarking-sites.php",function(bookmarks){
for(var i = 0; i < bookmarks.length; i++){
//alert( bookmarks[i].id);
bookmarkingSites += '<option value = "' + bookmarks[i].id + '">' + bookmarks[i].title + '</option>';
}
return bookmarkingSites;
});
}
function socialbookmarksTableData(data)
{
var toAppend = '';
var bookmarkingSites = socialbookmarksGetBookmarkSites();
$.each(data.results, function(i, id){
var bookmarkCategories = socialbookmarksGetBookmarkCategories(data.results[i].bookmarkID);
//rest of the code is not important
});
$("#searchTable tbody").append(toAppend);
}
You return the variables from the callback functions, not the functions that you actually call. After the callback functions are called control is returned to the functions which have no return statements, so they 'return' undefined by default. You need to return values from socialbookmarksGetBookmarkCategories and socialbookmarksGetBookmarkSites not just from callback functions within them.
You need to execute the code in your socialbookmarksTableData function as a response to the $.getJSON call. The problem is that you are returning right away, but the JSON callback hasn't yet fired.

Categories

Resources