How to send additional parameters to success function in jquery ajax - javascript

I have the following Jquery code, I'm trying to display information in $('.cbs-List').HTML(divHTML); based on the region value. But in the success function, I can't read the value for the region, it states that
'data is undefined'
What is the correct form of passing parameters or values to the success function in this case?
$(document).ready(function() {
getSearchResultsREST('LA');
});
function getSearchResultsREST(region) {
var querySA = 'ClientSiteType:ClientPortal* contentclass:STS_Site Region=LA';
var queryDR = 'ClientSiteType:ClientPortal* contentclass:STS_Site Region=EM';
if(region == 'LA') {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText='" + querySA + "'";
} else {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText='" + queryDR + "'";
}
$.ajax({
url: searchURL,
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
contentType: "application/json; odata=verbose",
success: SearchResultsOnSuccess(data, region),
error: function(error) {
$('#related-content-results').html(JSON.stringify(error));
}
});
}
function SearchResultsOnSuccess(data, region) {
var results;
var divHTML = '';
if (data.d) {
results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
if(results.length == 0) {
$('#related-content-results').html('There is No data for the requested query on ' + _spPageContextInfo.webAbsoluteUrl);
} else {
for (i=0; i<results.length; i++) {
var item = results[i];
var itemCell = item.Cells;
var itemResults = itemCell.results;
// Get values for item result
var _title = getValueByKey("Title", itemResults);
var _path = getValueByKey("Path", itemResults);
divHTML += '<li><a href=' + _path + '>' + _title + '</li>';
}
// Display information based on region.
$('.cbs-List').html(divHTML);
}
}
}

You have 2 problems, and they're both easy to fix.
There's no need to pass region into SearchResultsOnSuccess at all. you can already use it in there because it's defined at a higher scope.
In the object you're passing to $.ajax, you're not setting SearchResultsOnSuccess as a callback, you're calling it.
Change the lines:
success: SearchResultsOnSuccess(data, region) => success: SearchResultsOnSuccess
function SearchResultsOnSuccess(data, region) { => function SearchResultsOnSuccess(data) {
and it should work fine.
Edit:
Here's a basic example of how you need to set this up
function search(region) {
$.ajax({
url: 'example.com',
method: 'GET',
success: successCallback,
});
function successCallback(data) {
console.log(data, region);
}
}
search('LA');

You have to urlencode the value if it contains = or & or whitespace, or non-ASCII characters.
var querySA = encodeURIComponent('ClientSiteType:ClientPortal* contentclass:STS_Site Region=LA');
var queryDR = encodeURIComponent('ClientSiteType:ClientPortal* contentclass:STS_Site Region=EM');
if(region == 'LA') {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText=" + querySA;
} else {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText=" + queryDR;
}
And normally you don't have to put your values between apostrophes.
I updated the answer, I hope you will understand me better.
Your problem is NOT the parameter passing IMHO but your server response.
You should either:
turn on the developer tools and check the XHR requests on the network tab, look for the /_api/search/query... requests and examine the response
double check the server side logs/study your search service API documentation how to assemble a proper call
use your favourite REST client and play around your service: send there queries and check the responses and check that it matches with your expectation
last but not least, you can replace your ajax caller with this quick-and-great one:
$.ajax({
url: searchURL,
success: function (response) {
$('#post').html(response.responseText);
},
error: function (jqXHR, exception) {
var msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status == 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
$('#post').html(msg);
},
});
(of course you should have a <div id="post"><div> somewhere in your page)
Your success function IMHO would get your region if gets called, but it does not, and I hope using one or more of these techniques will help you to see clear.
If you are really sure that you get what you want, you can go furher with passing your second argument, as described here

Related

How can I pass my JavaScript data up to my Controller in ASP.NET Core?

I have a script function that is getting all the data, but it's the data transfer to the Controller I'm having troubles with. I can't do the #Html.ActionLink, because essentially I need to select one of my game pieces and then click on an empty space to run the controller.
And these empty spaces are divs upon the onclick event would run the getPos function with inputs of their row and column.
In my GameBoard view:
var selected = false;
var row = -1;
var col = -1;
var gamePieceId = null;
var gamePiece = null;
function selectPiece(id, row, col){
gamePieceId = id;
selected = true;
gamePiece = document.getElementById(gamePieceId);
gamePiece.style.backgroundColor("lightblue");
}
function getPos(rowPos, colPos){
row = (50 * (rowPos - 1)) + 5;
col = (50 * (colPos - 1)) + 5;
if(selected){
gamePiece.style.top = row.toString() + "px";
gamePiece.style.left = col.toString() + "px";
selected = false;
addMoveToDB(gamePieceId, rowPos.toString(), colPos.toString());
}
}
function addMoveToDB(id, mrow, mcol)
{
$.ajax({
url: '/GamePiece/GameBoard',
type: 'POST',
async: true,
processData: false,
data: {
id: id,
mrow: mrow,
mcol: mcol},
success: function (data) {alert("success");},
error: function (jqXHR, exception) {
var msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status == 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
$('#post').html(msg);
},
});
}
In my GamePiece Controller:
[HttpPost]
public async Task<ActionResult> GameBoard(string id, string mrow, string mcol)
{
try
{
GameVM gameVM = new GameVM();
GamePiece gamePiece = new GamePiece();
gamePiece = await (GamePieceManager.LoadById(Guid.Parse(id)));
gamePiece.Row = int.Parse(mrow);
gamePiece.Col = int.Parse(mcol);
await GamePieceManager.Update(gamePiece);
gameVM.gamePieces = await GamePieceManager.LoadByGameId(gamePiece.GameId);
return PartialView(gameVM);
}
catch (Exception)
{
throw;
}
}
With the success and error methods in the Ajax part, I realized that the data doesn't even go up to the controller and it throws out error 500
With the success and error methods in the Ajax part, I realized that
the data doesn't even go up to the controller and it throws out the
error right away.
Well, based on your shared code, its pretty obvious that your request will terminate soon after execution as you are using processData: false. If you set set processData: to false it stops jQuery/Javascript processing any of the data. As a result, your request has not submitted at all. You should either remove it or make it true.
Working Solution:
var id = "1";
var mrow = "mrow-Test";
var mcol = "mcol-Test";
$.ajax({
url: "/GamePiece/GameBoard",
type: 'POST',
async: true,
dataType: 'text',
data: {
id: id,
mrow: mrow,
mcol: mcol
},
success: function (data) {
alert("success");
alert(data);
console.log(data);
},
error: function (xhr) {
alert("false");
}
});
Note: I have simply removed processData: false property.
Output:

Wait until unknown number of ajax request done

I'm uploading a list of documents to the server, and for each document I launch an ajax request, but the number of requests is unknown (Depends on the number of document being uploaded). How can I show a message to the user when all the documents are uploaded (All ajax requests are done).
$.each(files,function(idx,elm){
let formData = new FormData();
let ID = '_' + Math.random().toString(36).substr(2, 9);
formData.append('document_id', ID);
formData.append('file-doc', elm);
$.ajax({
url: "http://127.0.0.1:5000/add_multiple_docs",
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function (xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
},
success: function (data) {
alert(data);
},
failure: function (request) {
console.log(request);
},
error: function (jqXHR, exception) {
console.log("error add document");
let msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status === 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status === 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
console.log(msg)
}
});
});
}
First of all, you know how many files are uploaded, so you know how many ajax request you are doing. (1 Request per file)
So before your $.each() fires you get the size of files
let count = $(files).size();
$.each(files,function(idx,elm){
/*your code with requests*/
}
Now, after each ajax request hast fired, decrement count. Decrement inside your success and failure methods, because it doesn't mattet if it succeeded or not. And check if count === 0. If it's 0 than you know all ajax are done.
$.ajax({
/*your other settings*/
success: function (data) {
alert(data);
count--;
doSomething(count);
},
failure: function (request) {
console.log(request);
count--;
doSomething(count);
},
});
function doSomething(count){
if(count === 0){
/*stuff you wannna do after all ajax requests are done*/
}
}
I haven't done that many ajax for now, so I'm not quite sure if failure is also fired on error, but if not maybe add count-- and the if on error as well.
To achieve what you need you can place all the jqXHR objects returned from $.ajax() in an array which you can apply() to $.when(). Then you can execute whatever logic you require after all of those promises have been resolved. Try this:
var promises = files.map(function(elm) {
// setup formData...
return $.ajax({
url: "http://127.0.0.1:5000/add_multiple_docs",
// ajax settings...
});
});
$.when.apply($, promises).done(function() {
console.log('all requests complete, do something here...');
});
However, it's definitely worth noting that sending AJAX requests in a loop is not a scalable pattern to use. It would be a much better idea to aggregate all the file and related data in a single AJAX request and handle that once on the server.
A very interesting question.
I had a similar issue when trying to get data from the youtube API which only returned a max result set of 50 items.
To solve this problem I used a recursive function that accepted a callback, on base case (in my case when there was no nextPageToken) I called the callback function.
The recursion was triggered in the success handler of the $.ajax request.
function fetchVideos(nextPageToken, callback) {
if (nextPageToken === null || nextPageToken === undefined) {
callback(null);
return;
}
$.ajax(requestURI + `&pageToken=${nextPageToken}`, {
success: (data) => {
// use data somehow?
fetchVideos(data.nextPageToken, callback);
},
error: (err) => {
callback(err);
}
})
}
fetchVideos("", (err) => {
if (err) {
console.log(err.responseJSON);
return;
}
updateUI();
})
When there was no longer a nextPageToken in the response it would trigger the if statement. I think it works kind of sync? Because I need the nextPageToken to perform the next request.
I know this is not the best case for you situation, but I answered based on the title which is how I came to this page :)

ajax sometimes returns #document, sometimes Object{d:Object}

When I check console in Chrome, the Sharepoint page behaves as it is supposed to when data is Object {d: Object} and d is an Array of the items of want.
When data is #document, the page does not load as I append html based on data.
I understand #document appears because of jQuery's Intelligent Guess, but am not sure why it is getting returned.
function getItems() {
var url = hostWebURL + "_api/web/lists('" + guid + "')/items/";
var items;
$.ajax({
url: url,
type: "GET",
headers: { "Accept": "application/json;odata=verbose "}, // return data format
success: function (data) {
//items is iterable ListItemCollection
console.log(data);
items = data.d.results;
...
},
error: function (error) {
var errorMsg = "";
if (error.status == "403" || error.status == "401") {
errorMsg = "You do not have Authorization to see Site Permissions - ErrorCode(" + error.status + ") Error Details: " + error.statusText;
}
else {
var errorMsg = "Failed - ErrorCode(" + error.status + ") Error Details: " + error.statusText;
}
reportError(errorMsg);
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("Accept", "application/json; odata=verbose");
Added this parameter to the call and it's working!
Taken from: http://ratsubsharewall.blogspot.com/2017/02/rest-call-returns-xml-instead-of-json.html

Java code from javascript

How I write java code from javascript that will complete in server. Please help me.
I have long been trying to remake it
It is query to server to will be logged.
this.login = function(options) {
//It is query to server to will be logged.
if (typeof (options.success) == "function" && typeof (options.error) == "function" && options.params != null) {
var successCallback = options.success;
var errorCallback = options.error;
} else {
AV.console.error(LP + 'Invalid number of arguments (min req = 3), Please read API Documentation.');
return;
}
$.ajax({
type: 'POST',
url: _sURL + '/csportal/v1/login',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(options.params),
success: function(response) {
AV.console.debug(LP + "login::Success: " + JSON.stringify(response));
if (response && response.success == true) {
_userLoggedIn = 'true';
_userReturned = 'false';
_userInfo = response.data;
successCallback({"message": response.message,"data": response.data});
} else {
_userLoggedIn = 'false';
errorCallback({message: response.message});
}
},
error: function(e) {
AV.console.warn(LP + "login:: error: " + e.message);
errorCallback({message: e.responseText});
}
});
};
You have two options here.
Option 1 - Corresponding to your _sURL + '/csportal/v1/login, you need to create a class extending HttpServlet class, override the post method and return required response. Or if you are using any frameworks (like Spring MVC or Struts), you just need to override corresponding Action classes.
Option 2 - Corresponding to your _sURL + '/csportal/v1/login, you create a REST api (using Jersey), and write a POST method handling JSON request and return required RESPONSE.
If you don't have server side experience, consider catching a server side engineer from your team for help.

Uncaught ReferenceError: error is not defined in Ajax Callback

In my App, I get a list of Events from a Sharepoint Calendar List. That part works perfectly.
However after I get the collection of results, for each item I need to get the Display Form Url, which is another REST Call with the ListItem ID.
However I get the error below, but I still dont know what the problem might be
Uncaught ReferenceError: error is not defined App.js:87(anonymous function) App.js:87$.ajax.error App.js:40c jquery-1.9.1.min.js:22p.fireWith jquery-1.9.1.min.js:22k jquery-1.9.1.min.js:24send.r
I based my code on this answer:
https://sharepoint.stackexchange.com/questions/119236/how-to-get-the-display-form-url-using-rest
My adapted code is like this:
var SPHostUrl;
var SPAppWebUrl;
var ready = false;
// this function is executed when the page has finished loading. It performs two tasks:
// 1. It extracts the parameters from the url
// 2. It loads the request executor script from the host web
$(document).ready(function () {
var params = document.URL.split("?")[1].split("&");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
switch (param[0]) {
case "SPAppWebUrl":
SPAppWebUrl = decodeURIComponent(param[1]);
break;
case "SPHostUrl":
SPHostUrl = decodeURIComponent(param[1]);
break;
}
}
// load the executor script, once completed set the ready variable to true so that
// we can easily identify if the script has been loaded
$.getScript(SPHostUrl + "/_Layouts/15/SP.RequestExecutor.js", function (data) {
ready = true;
getItems();
});
});
function getListItemFormUrl(webUrl, listName, listItemId, formTypeId, complete, failure) {
$.ajax({
url: webUrl + "/_api/web/lists/GetByTitle('" + listName + "')/Forms?$select=ServerRelativeUrl&$filter=FormType eq " + formTypeId,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var url = data.d.results[0].ServerRelativeUrl + '?ID=' + listItemId
complete(url);
},
error: function (data) {
failure(data);
}
});
}
// this function retrieves the items within a list which is contained within the parent web
function getItems() {
// only execute this function if the script has been loaded
if (ready) {
// the name of the list to interact with
var listName = "Events";
// the url to use for the REST call.
var url = SPAppWebUrl + "/_api/SP.AppContextSite(#target)" +
// this is the location of the item in the parent web. This is the line
// you would need to change to add filters, query the site etc
// "/web/lists/getbytitle('" + listName + "')/items?" +
"/web/lists/getbytitle('" + listName + "')/items?$select=Title,Category,EventDate,Description,EncodedAbsUrl,ID" +
"&#target='" + SPHostUrl + "'";
// create new executor passing it the url created previously
var executor = new SP.RequestExecutor(SPAppWebUrl);
// execute the request, this is similar although not the same as a standard AJAX request
executor.executeAsync(
{
url: url,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
// parse the results into an object that you can use within javascript
var results = JSON.parse(data.body);
var events = [];
$.each(results.d.results, function (i, obj) {
//Usage
getListItemFormUrl(SPAppWebUrl, 'Calendar', obj.ID, 4,
function (url) {
console.log('Display from url for list item: ' + url);
},
function (sender, args) {
console.log(JSON.stringify(error));
})
//use obj.id and obj.name here, for example:
var event = {
date: Date.parse(obj.EventDate).toString(),
type: obj.Category,
title: obj.Title,
description: obj.Description,
url: obj.EncodedAbsUrl + 'DispForm.aspx?ID=' + obj.ID
}
events.push(event);
});
var myJsonString = JSON.stringify(events);
$("#eventCalendarInline").eventCalendar({
jsonData: events,
openEventInNewWindow: true,
showDescription: true,
txt_GoToEventUrl: "Go to event"
});
Communica.Part.init();
},
error: function (data) {
// an error occured, the details can be found in the data object.
alert("Ooops an error occured");
}
});
}
}
Under //Usage:
function (sender, args) {
console.log(JSON.stringify(error));
})
error does not seem to be defined

Categories