How to limit a JS Object to be posted via ajax - javascript

I have an application that sends a message through JSON via ajax. This is the JS object:
var message = {
"message_by": colmn[0].innerHTML,
"message_date": new Date(),
"message_recipients": [
{
"phone_number": colmn[1].innerHTML,
"recipient_name": colmn[2].innerHTML
}
],
"message_text": colmn[3].innerHTML,
"subscriber_name": "John Doe"
};
Which is then posted like so:
var url = "http://url/api/sendMessage";
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(message),
contentType: "application/json; charset=utf-8",
dataType: "json",
processData: true,
success: function (data, status, jqXHR) {
console.log(data);
console.log(status);
console.log(jqXHR);
//alert("success..." + data);
alert("Success. Message sent.");
},
error: function (xhr) {
//alert(xhr.responseText);
alert("Error. Try again.");
}
});
The stringified message could look like this for example:
var message = {
"message_by": "Brian",
"message_date": new Date(),
"message_recipients": [{
"phone_number": "0700111222",
"recipient_name": "Timothy"
}, {
"phone_number": "0800222111",
"recipient_name": "Winnie"
}],
"message_text": "Hello! You are invited for a cocktail at our auditorium. ",
"subscriber_name": "John Doe"
}
Now to the problem. The messages are posted to the api just fine but recently noticed some messages failing and discovered the failed messages had 100 message recipients or more. It works fine up to 99. I asked a colleague and he said there weren't any limit restrictions set on the api.
Is there a way I could limit the object size to 99 and push the remainder to a new object but still have it as part of the same ajax post? Is there any other creative way around this?

There is no such limit.
If you want to restrict your message recipients to 99 you can do as follows
validateMessege(message){
var length = message.length;
var messegeRep = message.message_recipients.slice()
for(var i = 0; i < length; i+=99){
message.message_recipients = messageRep.slice(i, i+99)
// Your post request here
}
}

Related

Ajax sends two empty arrays and one filled, PHP receives only the full one

I'm completely new to PHP. Working with ajax, php and WordPress I'm sending an object with ajax:
let import_data = {
action: 'import_data',
data: {
first_array: [], // this one is empty
second_array: [], // this one too
third_array: [1,2,3] // this one is full
}
};
I've checked the import_data object many times right before it was sent. The php, however, always receives:
import_data = {
action: 'import_data',
data: {
third_array: [1,2,3]
}
}
The question is why is that happening and how can I achieve receiving all arrays, whether they are empty or not, i.e.
import_data = {
action: 'import_data',
data: {
first_array: [],
second_array: [],
third_array: [1,2,3]
}
}
I need to refactor a lot of code now due to this issue so I'm trying to solve it as easy as possible, but if there is a common known right way to deal with it I'll use it. Thanks in advance!
P.S. In case you wondering, yes, if all arrays being sent are full, php will receive all of them.
UPD In the comments I got I might've wanted to add contentType or json.strngify my data. It didn't help, but I might do it wrong, so I'll try to partly show my code below:
var import_data = {
action: 'start_import',
sliced_batch: {
rows_to_add: [],
rows_to_delete: [],
rows_to_update: [1,2,3,4,5,...]
}
};
function ajax_call(import_data) {
// ... processes
jQuery.ajax({
url: start_import_ajax.url, // url from php file
type: 'POST',
contentType: "text; charset=utf-8", // sending string with cyrillic (ukrainian lng)
dataType: 'application/json', // want to recieve json
data: JSON.stringify(import_data),
success: function(response) {
// ... processes import_data ...
if(it is the end of data) return;
else ajax_call(import_data);
},
error: function(e) {
// here is where I end up
}
}
PHP side is now pretty shy, as I just made a pause and wanted to see my data in console:
function start_import_callback() {
echo json_decode($_POST);
echo $_POST;
echo json_decode($_POST['sliced_batch']);
echo $_POST['sliced_batch'];
wp_die();
}
I've tried all echo's one by one, but always saw:
{
"readyState": 4,
"responseText": "0",
"status": 400,
"statusText": "error"
}
When NOT stringifying and NOT specifying contentType/dataType it returns:
{
action: 'import_data',
sliced_batch: {
rows_to_update:
{
"ID": "00000006125",
"CatalogueNumber": "bla, bla",
"Category": "bla, bla",
"Manufacturer": "bla",
"Nomenclature": "blablablablabla",
"NomenclatureUkrainian": "bla",
"StockStatus": "instock",
"Price": "2 315",
"Parent": "blabla",
"Sorting": "99"
},
{},...
]
}
}
So, rows_to_delete: [] and rows_to_add: [] are missing...
You are using jQuery dataType options wrong!
The dataType: value should be 'json' not 'application/json' because your value will request with HTTP accept: */* but if you use 'json' it will be accept: application/json.
Option 1
Use content type application/json.
The contentType: should be 'application/json' or 'application/json;charset=utf-8'.
By this content type you will be now able to receive POST data in JSON but you cannot access them with $_POST because the data is not valid application/x-www-form-urlencoded.
Full code for client side:
var import_data = {
action: 'start_import',
sliced_batch: {
rows_to_add: [],
rows_to_delete: [],
rows_to_update: [1,2,3,4,5]
}
};
function ajax_call(import_data) {
// ... processes
jQuery.ajax({
url: 'test.php', // url from php file
type: 'POST',
contentType: "application/json;charset=utf-8", // sending string with cyrillic (ukrainian lng)
dataType: 'json', // want to recieve json
data: JSON.stringify(import_data),
success: function(response) {
// ... processes import_data ...
},
error: function(e) {
// here is where I end up
}
});
}
Code for PHP:
$data = json_decode(file_get_contents('php://input'), true);
// use $data['sliced_batch'] to access `rows_to_add`, `rows_to_delete` etc.
Option 2
Use content type application/x-www-form-urlencoded.
With this content type, you will be able to access $_POST properly.
However, to use this request content type in header, the jQuery itself will be modify the value if it is empty jQuery will be just delete it!! So, you need to JSON string only sliced_batch property.
Here is the JS code:
var import_data = {
action: 'start_import',
sliced_batch: {
rows_to_add: [],
rows_to_delete: [],
rows_to_update: [1,2,3,4,5]
}
};
function ajax_call(import_data) {
// ... processes
// modify `sliced_batch` property to be JSON string to prevent jQuery remove empty properties.
import_data.sliced_batch = JSON.stringify(import_data.sliced_batch);
jQuery.ajax({
url: 'test.php', // url from php file
type: 'POST',
// just remove contentType option. It is no need.
//contentType: "application/json;charset=utf-8", // sending string with cyrillic (ukrainian lng)
dataType: 'json', // want to recieve json
data: import_data,
success: function(response) {
// ... processes import_data ...
},
error: function(e) {
// here is where I end up
}
});
}
PHP:
$sliced_batch = ($_POST['sliced_batch'] ?? '');
$sliced_batch = json_decode($sliced_batch, true);
// you can now access $sliced_batch['rows_to_add'], etc...
So, thanks once again to #vee for his explanation, but here's one more thing I'd like to share as it was crucial to get everything to work.
First, for json_decode method the JS object keys should be double-quoted, i.e. NOT
$bad_json = '{ bar: "baz" }';
json_decode($bad_json); // null
or
$bad_json = '{ 'bar': "baz" }';
json_decode($bad_json); // null
BUT
$bad_json = '{ "bar": "baz" }';
json_decode($bad_json); // array("bar" => "baz")
Second and most important!
When dealing with WordPress it sets its own rules and shows focuses!
Depending on what answer you'd like to get, you may want to use function wp_unslash(). Looking at the stringified data in console I saw somth like this:
"\u0421\u0435\u0440\u0432\u0435\u0440: \u0424\u0430\u0439\u043b\u0456\u0432 av_imp_p_WEB.csv \u0456 av_imp_p_WEB_previous.csv \u043d\u0435 \u0431\u0443\u043b\u043e \u0432\u0438\u044f\u0432\u043b\u0435\u043d\u043e. \u041f\u043e\u0447\u0438\u043d\u0430\u044e \u0456\u043c\u043f\u043e\u0440\u0442 \u0432\u0441\u044c\u043e\u0433\u043e
// it is more common for contentType: "application/x-www-form-urlencoded"
It is the dirty work of WooCommerce (as I read from another's people opinion) and it hinders parsing it the right way, so my full code is:
JS
var import_data = {
"action": "start_import",
"sliced_batch": {
"rows_to_add": my_data1,
"rows_to_delete": my_data2,
"rows_to_update": my_data3
}
};
function ajax_call(import_data) {
// ... processes
jQuery.ajax({ // ajax to php to save the file to uploads and move it to the plugin's folder
url: start_import_ajax.url, // url from php file
type: 'POST',
//contentType: "application/json;charset=utf-8", // what you send
dataType: 'JSON', // what you would like as a response
data: {
"action": import_data.action,
"sliced_batch": JSON.stringify(import_data.sliced_batch)
},
success: function(response) {
//response = JSON.parse(response); // if you'd like to console.log what you've sent
console.log(response);
}
....
PHP
$sliced_batch = wp_unslash($_POST['sliced_batch']);
$sliced_batch = json_decode($sliced_batch, true);
$result = start_import($sliced_batch);
if($result == 0) {
echo json_encode(["status" => 0]);
} else echo json_encode(["status" => 1]);

Is there a solution to set user birthday to null, empty or default value?

I have set a birthday to a user.
I need to remove this birthday, but i'm unable.
I have tried PATCH method in the documentation but field cannot be null.
Then i have tried multiple calls with PATCH / PUT / DELETE but i always have an error.
In Delve when we delete the birthday, it becomes '0001-01-01T00:00:00Z'.
I have tried to PATCH the birthday with this value, but i get Unknow Error :
{
"error": {
"code": "-1, Microsoft.SharePoint.Client.UnknownError",
"message": "Unknown Error",
"innerError": {
"request-id": "678fbda6-5fb9-4bc0-91c3-7af2238c1673",
"date": "2018-05-28T09:16:20"
}
}
}
We can use the SharePoint REST API below to set the birthday of the user profile.
/_api/SP.UserProfiles.PeopleManager/SetSingleValueProfileProperty
Example code:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
var requestHeaders = {
'X-RequestDigest': $("#__REQUESTDIGEST").val(),
"accept": "application/json; odata=nometadata",
"content-type": "application/json;odata=nometadata"
};
var userData = {
'accountName': "i:0#.f|membership|user#lz.onmicrosoft.com",
'propertyName': 'SPS-Birthday', //can also be used to set custom single value profile properties
'propertyValue': ''//set empty value
}
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/SP.UserProfiles.PeopleManager/SetSingleValueProfileProperty",
type: "POST",
headers: requestHeaders,
data: JSON.stringify(userData),
success: function (data) {
console.log(data)
},
error: function (jqxr, errorCode, errorThrown) {
console.log(jqxr.responseText);
}
});
});
</script>
Note: Modify the 'accountName' in the code above and add the code into a script editor web part in the SharePoint page.

Make a jquery ajax POST inside a loop

I have a bunch of data inside a loop I'd like to POST to the server via jQuery.
My code is similar to the following:
var patients = [] // contains an array of patient objects I want to POST to server
var post = function(theUrl, theData, callback){
$.ajax({
type: "POST",
url: theUrl,
data: theData,
success: callback,
contentType: "application/json"
});
}
var createdPatient = function(patient){
//patient was created
}
$('#saveAll').click(function(event) {
for (var i = 0;i < patients.length;i++) {
var json = JSON.stringify(patients[i]);
post("/openmrs/ws/rest/v1/patient", json, createdPatient);
}
});
When I run the code only the last patient has been saved to the server. How may I correct this erroneous outcome?
Taking advantage of the promise returned by jQuery.ajax(), you can write something more like this (see comments for detail) :
var patients = [...] // contains an array of patient objects to be POSTed to the server
$('#saveAll').click(function(event) {
// first, map the `patients` array to an array of jqXHR promises as returned by $.ajax().
var promises = patients.map(function(patient) {
return $.ajax({
type: 'POST',
url: '/openmrs/ws/rest/v1/patient',
data: patient, // jQuery.jax will handle js plain objects here. You may need to stringify here if patient is not a plain object.
contentType: "application/json"
}).then(function(data, textStatus, jqXHR) {
return textStatus; // report successes in the form of the "textStatus" message (or anything you like).
}, function(jqXHR, textStatus, errorThrown) {
return $.when(textStatus || errorThrown); // report error on the success path, otherwise `$.when()` will bail out at the first error.
});
});
// Now aggregate the `promises` array with `$.when()`
$.when.apply(null, promises).then(function(results) {
console.log(results);
}, function(error) {
// due to error handling above, you should never get here.
console.log(error);
});
});
For more detail, see jQuery.ajax() and jQuery.when()

HttpClient PostAsync equivalent in JQuery with FormURLEncodedContent instead of JSON

I wrote a JQuery script to do a user login POST (tried to do what I have done with C# in the additional information section, see below).
After firing a POST with the JQuery code from my html page, I found the following problems:
1 - I debugged into the server side code, and I know that the POST is received by the server (in ValidateClientAuthentication() function, but not in GrantResourceOwnerCredentials() function).
2 - Also, on the server side, I could not find any sign of the username and password, that should have been posted with postdata. Whereas, with the user-side C# code, when I debugged into the server-side C# code, I could see those values in the context variable. I think, this is the whole source of problems.
3 - The JQuery code calls function getFail().
? - I would like to know, what is this JQuery code doing differently than the C# user side code below, and how do I fix it, so they do the same job?
(My guess: is that JSON.stringify and FormURLEncodedContent do something different)
JQuery/Javascript code:
function logIn() {
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
success: getSuccess,
error: getFail
});
} catch (e) {
alert('Error in logIn');
alert(e);
}
function getSuccess(data, textStatus, jqXHR) {
alert('getSuccess in logIn');
alert(data.Response);
};
function getFail(jqXHR, textStatus, errorThrown) {
alert('getFail in logIn');
alert(jqXHR.status); // prints 0
alert(textStatus); // prints error
alert(errorThrown); // prints empty
};
};
Server-side handling POST (C#):
public override async Task ValidateClientAuthentication(
OAuthValidateClientAuthenticationContext context)
{
// after this line, GrantResourceOwnerCredentials should be called, but it is not.
await Task.FromResult(context.Validated());
}
public override async Task GrantResourceOwnerCredentials(
OAuthGrantResourceOwnerCredentialsContext context)
{
var manager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await manager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError(
"invalid_grant", "The user name or password is incorrect.");
context.Rejected();
return;
}
// Add claims associated with this user to the ClaimsIdentity object:
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
foreach (var userClaim in user.Claims)
{
identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
}
context.Validated(identity);
}
Additional information: In a C# client-side test application for my C# Owin web server, I have the following code to do the POST (works correctly):
User-side POST (C#):
//...
HttpResponseMessage response;
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>( "grant_type", "password"),
new KeyValuePair<string, string>( "username", userName ),
new KeyValuePair<string, string> ( "password", password )
};
var content = new FormUrlEncodedContent(pairs);
using (var client = new HttpClient())
{
var tokenEndpoint = new Uri(new Uri(_hostUri), "Token"); //_hostUri = http://localhost:8080/Token
response = await client.PostAsync(tokenEndpoint, content);
}
//...
Unfortunately, dataType controls what jQuery expects the returned data to be, not what data is. To set the content type of the request data (data), you use contentType: "json" instead. (More in the documentation.)
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
contentType: "json", // <=== Added
success: getSuccess,
error: getFail
});
If you weren't trying to send JSON, but instead wanted to send the usual URI-encoded form data, you wouldn't use JSON.stringify at all and would just give the object to jQuery's ajax directly; jQuery will then create the URI-encoded form.
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: {
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
},
dataType: "json",
success: getSuccess,
error: getFail
});
// ...
To add to T.J.'s answer just a bit, another reason that sending JSON to the /token endpoint didn't work is simply that it does not support JSON.
Even if you set $.ajax's contentType option to application/json, like you would to send JSON data to MVC or Web API, /token won't accept that payload. It only supports form URLencoded pairs (e.g. username=dave&password=hunter2). $.ajax does that encoding for you automatically if you pass an object to its data option, like your postdata variable if it hadn't been JSON stringified.
Also, you must remember to include the grant_type=password parameter along with your request (as your PostAsync() code does). The /token endpoint will respond with an "invalid grant type" error otherwise, even if the username and password are actually correct.
You should use jquery's $.param to urlencode the data when sending the form data . AngularJs' $http method currently does not do this.
Like
var loginData = {
grant_type: 'password',
username: $scope.loginForm.email,
password: $scope.loginForm.password
};
$auth.submitLogin($.param(loginData))
.then(function (resp) {
alert("Login Success"); // handle success response
})
.catch(function (resp) {
alert("Login Failed"); // handle error response
});
Since angularjs 1.4 this is pretty trivial with the $httpParamSerializerJQLike:
.controller('myCtrl', function($http, $httpParamSerializerJQLike) {
$http({
method: 'POST',
url: baseUrl,
data: $httpParamSerializerJQLike({
"user":{
"email":"wahxxx#gmail.com",
"password":"123456"
}
}),
headers:
'Content-Type': 'application/x-www-form-urlencoded'
})
})

Not able to access JSON data in ajax jquery

I have a Jquery AJAX POST method.Which call a web method of asp.net.
The ajax method get a json data.
The data format is :
[
{
"Title": "Test2",
"Name" : "AMIT",
"IsRoot": "True"
},
{
"Title": "Test3",
"Name" : "AMIT1",
"IsRoot": "False"
},
{
"Title": "Test4",
"Name" : "AMIT2",
"IsRoot": "True"
}
]
I validate the dataformat in "http://jsonlint.com/" site and it's telling that dataformat is correct.
I want to loop through the data and access each of the attribute.But I am not able to get that.
I try to find the total array length which should be 3.But it's giving me 9(means each attribute )
I try
alert(data.d.length); // giving 9 (should give 3)
var jsondata = data.d;
alert(jsondata[1].Title); //undefined (should give Test3)
alert(jsondata[2].Title); //undefined (should give Test4)
alert(jsondata[1].Name); //undreined (should give AMIT1)
var key, count = 0;
for (key in data.d) {
if (data.d.hasOwnProperty(key)) {
count++;
}
}
alert(count); // giving 9 (should give 3)
any help is highly accepted.
My ajax calling method is
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "WebForm1.aspx/GetRootData",
dataType: "json",
success: function (data, textStatus) {
var jsondata = data.d;
alert(jsondata[1].Title);
alert(jsondata[2].Title);
alert(jsondata[1].MimeType);
var key, count = 0;
for (key in data.d) {
if (data.d.hasOwnProperty(key)) {
count++;
}
}
alert(count);
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(xhr.responseText);
alert(thrownError);
}
});
and don't know why debugger also not working.. :(
Thanks everyone.Finally I solved the problem.
the solution is
var jsonObject = eval(data.d);
Now it's returning all the data fine..
alert(jsonObject.length); //Now it's returning 2
alert(jsonObject[1].Title); // it's returning Test3 now.
Thanks..

Categories