I have a form that contains fields of an associative array:
<label for="my_array[][system]">System</label>
<input id="my_array[][system]" type="text" value="" name="my_array[0][system]">
<label for="my_array[][name]">Name</label>
<input id="my_array[][name]" type="text" value="" name="my_array[0][name]">
I'm trying to get this form posted to PHP using Ajax. I've attempted this:
$.ajax({
type: "POST",
dataType: "json",
url: ajaxurl,
data: {
action: "update_postmeta",
post_id: post_id,
nonce: nonce,
my_array: $('input:text[name="my_array*"]')
.each(function() { values[this.name] = $(this).val() })
},
success: function (response) {
alert(response);
},
error: function ( jqXHR, textStatus, errorThrown) {
alert("Error: " + textStatus + '\r\n\r\n' + errorThrown);
}
})
The problem is on this line of code:
my_array: $('input:text[name="my_array*"]')
.each(function() { values[this.name] = $(this).val() })
.each() is not a function... I'm not sure how to get my_array populated with the form's data in the same structure it would be using a regular form submission (without Ajax).
How do I post a form's data when it is created with an associative array?
Change your my_array function() to auto-invoke the function and return an array of key: value objects:
{
...,
my_array: (function() {
var my_array = [];
$('input:text[name="my_array*"]')
.each(function() {
my_obj = {};
my_obj[this.name] = $(this).val();
my_array.push(my_obj);
});
return my_array;
})()
}
Also, you may need to use the attributeStartsWith selector syntax:
jQuery( "[attribute^='value']" )
For completeness, here is an example with using an object instead of an array to directly control the key: value pairs for my_array. Also, I'm using the startsWith syntax.
{
...,
my_array: (function() {
var my_array = {};
$('input:text[name^="my_array"]')
.each(function() {
// Directly sets the key/value data in the POST.
// You could modify the key names if desired.
my_array[this.name] = $(this).val();
});
return my_array;
})()
}
Related
I have jQuery Ajax sending form data to a WordPress function.
The PHP function gets the data as a string, like "navn=A&navn2=B", and I use the explode() function to access individual form elements.
I think there is a better way where I can access the form data as an array of JSON objects directly. But I can't figure that out.
How can I fix it?
This is my HTML/jQuery:
<form id='minForm' method="post" action="">
<input type="text" name="navn" value="A">
<input type="text" name="navn2" value="B">
<button>Send</button>
</form>
<script>
jQuery(document).ready(function($) {
var form = $('#minForm');
$(form).submit(function(event) {
event.preventDefault();
var formData = $(form).serialize();
$.ajax({
type: "POST",
url: '/wp-admin/admin-ajax.php',
data: {
action : 'my_ajax_action',
formData : formData,
},
success:function(data) {
console.log(data);
},
});
});
});
</script>
This is my PHP:
add_action('wp_ajax_my_ajax_action', 'my_ajax_action_callback');
function my_ajax_action_callback() {
$form_data = $_POST['formData'];
$form_data_array = explode('&', $form_data);
foreach ($form_data_array as $i) {
echo explode('=', $i)[1] . '<BR>';
}
wp_die(); // Required. to end Ajax request.
}
Serialize your form as an array. Then pass it in the Ajax request.
In the client side:
jQuery(document).ready(function($) {
var form = $('#minForm');
$(form).submit(function(event) {
event.preventDefault();
var formData = $(form).serializeArray();
$.ajax({
type: "POST",
url: '/wp-admin/admin-ajax.php',
dataType: 'json',
data: {
action : 'my_ajax_action',
formData : formData,
},
success:function(data) {
console.log(data);
},
});
});
});
On the server side:
add_action('wp_ajax_my_ajax_action', 'my_ajax_action_callback');
function my_ajax_action_callback() {
$response = ["success" => true];
$form_data = json_decode($_POST['formData']);
error_log(print_r($form_data, 1)); // Log to see the array properties.
if (empty($form_data) {
$response["success"] = false;
}
echo json_encode($response);
//wp_die(); // required. to end AJAX request.
}
Note: The $(form).serializeArray() will give you the form as an array of objects, and it might not be what you expect in the server side to extract data. You can handle the form array before sending to the server by convert it to a simple object:
var formData = $(form).serializeArray().reduce(function(obj,item){
obj[item.key] = item.value;
return obj;
}, {});
I'm trying to upload files through Ajax call and jQuery. Each input[type="file"] is handled dynamically as you will see on the code below and are created on the change event for the Select2 element.
var tipoRecaudo = $('#tipoRecaudo'),
tipo_recaudo = tipoRecaudo.val(),
selectedIdsTipoRecaudo = [];
tipoRecaudo.select2({
ajax: {
dataType: 'json',
url: function () {
return Routing.generate('obtenerRecaudosTramite');
},
data: function (tipo_recaudo) {
return {
filtro: tipo_recaudo
}
},
results: function (data) {
var myResults = [];
$.each(data.entities, function (index, item) {
if (selectedIdsTipoRecaudo.indexOf(item.id.toString()) === -1) {
myResults.push({
'id': item.id,
'text': item.nombre
});
}
});
return {
results: myResults
};
}
},
formatAjaxError: function () {
return Translator.trans('mensajes.msgNoConexionServidor', {}, 'AppBundle');
}
}).change(function () {
var id = $(this).val(),
selectedData = tipoRecaudo.select2("data"),
htmlTpl = '<table class="table"><caption>'+ selectedData.text + '</caption><tbody><tr><td>';
htmlTpl += '<input type="hidden" name="tipoRecaudos[]" id="tipoRecaudo ' + id + '" value="' + selectedData.id + '" /><div class="row"><div class="col-xs-6"><div class="form-group"><input type="file" id="recaudosNombreArchivo' + id + '" name="recaudos[nombre_archivo][]" multiple="multiple" class="form-control" /></div></div></div></div>';
htmlTpl += '</td></tr></tbody></table>';
selectedIdsTipoRecaudo.push(id);
$('#recaudoContainer').append(htmlTpl);
});
$('#recaudoContainer').on('change', 'input[type=file]', function (event) {
$("input:file").filestyle({
buttonText: "Seleccionar archivo",
iconName: "fa fa-upload",
buttonName: "btn-primary"
});
});
$('#btnGuardarPasoSieteAgregarProducto').on("click", function (event) {
event.stopPropagation(); // Stop stuff happening
event.preventDefault(); // Totally stop stuff happening
// Create a formdata object and add the files
var formData = $('#formRecaudosTramites').serialize();
$.each($('#formRecaudosTramites')[0].files, function (key, value) {
formData = formData + '&recaudos[]=' + value;
});
$.ajax({
url: Routing.generate('rpniSubirRecaudos'),
type: 'POST',
data: formData,
cache: false,
dataType: 'json',
contentType: 'multipart/form-data',
processData: false, // Don't process the files
//contentType: false // Set content type to false as jQuery will tell the server its a query string request
}).done(function (data, textStatus, jqXHR) {
if (typeof data.error === 'undefined') {
console.log('SUCCESS: ' + data.success);
} else {
// do something with error
}
}).fail(function (jqXHR, textStatus, errorThrown) {
// do something with fail callback
// STOP LOADING SPINNER
});
});
What is happening is: no filenames exists on query string, no files are upload or send through the Ajax call, instead it's sending a [object Object], what I'm doing wrong? Can any give me some working code for this stuff?
EDIT:
After reads the post referenced by user I change my code as the one before and now the error turns on:
TypeError: a is undefined
...rCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e...
What is wrong there?
Note: Yes, I know there are tons of plugins for handle this like jQuery File Upload from Blueimp, Dropzone and some others but I leave them out since I start using jQuery File Uploader from inside OneupUploaderBundle on my Symfony2 project and spent 4 days without success so I move to the other side: made things by myself so I can learn something else and improve my knowledge
i think this will help you,
var fd = new FormData();
//name is the key on the page of php to access the file
fd.append('name', $('#aob_file')[0].files[0]);
pass this fd object to your data field in ajax,
I'm having a problem when I click my generate cards button multiple times(it generates a new set of cards randomly on every click) and then I click on any of my buttons that sort it will run multiple ajax calls instead of just the latest generated array. It will pass in every array of cards that has been generated not just the most recent one, sort of like it's keeping a queue.
console log will output, "sending color sort", "sending color sort", "sending color sort", etc. *For as many times as i've clicked my generate_cards* button
How can I have it so the sort function only runs once.
<input type="button" value="Generate Cards" id="generate_cards"> </input>
<input type="button" class="sorter" value="Color Sort" id="color_sort"> </input>
<input type="button" class="sorter" value="Shape Sort" id="shape_sort"> </input>
Generate Cards:
$('#generate_cards').click(function() {
$.ajax({
url: ''+set,
async: false,
type: 'POST',
dataType: 'html',
success: function(data) {
var obj = JSON.parse(data);
//sent array to sorting function :
sorting(obj);
var tmpl = $("#formInfo_tmpl").html();
var html = Mustache.to_html(tmpl, obj);
pool_window.html(html);
initilizejs();
},
error:function(jqXHR, textStatus, errorThrown){
alert("Error type" + textStatus + "occured, with value " + errorThrown);
}
});
card sort function
function sorting(cards) {
$('.sorter').on("click", function() {
var cards_window = $("#sealed_pool");
var sort_type = $(this).attr('id');
//just give me the first word:
sort_type = sort_type.replace(/(\w+).*/,"$1");
console.log('sending'+sort_type);
$.ajax({
url: '',
async: false,
type: 'POST',
data: ({'cards':cards, 'sort_type':sort_type}),
dataType: 'html',
success: function(data) {
var obj = JSON.parse(data);
if(sort_type =='color_sort')
{
var tmpl = $("#color_sort_tmpl").html();
}
if(sort_type =='shape_sort')
{
var tmpl = $("#formInfo_tmpl").html();
}
var html = Mustache.to_html(tmpl, obj);
cards_window.html(html);
initilizejs();
},
error:function(jqXHR, textStatus, errorThrown){
alert("Error type" + textStatus + "occured, with value " + errorThrown);
}
});
});
}
remove the previous click-listener before you add a new:
$('.sorter')
.off("click")
.on("click", function() {
//code
});
You need to use setInterval within the document ready function, like this:
$(document).ready(function() {setInterval(doAjax, 5000);});
Thanks, I am passing in the array via json now and setting datatype to json, per your example as:
{"car_make_id":"3","car_engine_type":"Non-Turbo Petrol"}{"car_make_id":"3","car_engine_type":"Non-Turbo Diesel"}
But my script still refuses to append the select options and values?:
$("select#make").change(function(){
$('#engine').find('option').remove().end(); //clear the engine ddl
var make = $(this).find("option:selected").val(); //Need the value not the text - .Text()
//alert(make);
//do the ajax call
$.ajax({
url:'get-engine.php',
type:'GET',
data:{engine:make},
dataType:'json',
cache:false,
success:function(data){
//var parsedjson = data=JSON.parse(data); //no need if data:type json
$.each(data, function(index, item) {
$("<option/>", {
value: item.car_make_id,
text: item.car_engine_type
}).appendTo("#engine");
});
}
});
});
Can't seem to find why it will not parse the array?
The JSON structure is horrible so the real problem is to fix your JSON to be logical. Anyways
here's what you can try with the current one:
$.ajax({
url: 'grabdata.php',
type: 'GET',
data: {
type: make
},
dataType: "json",
cache: false,
success: function (data) {
$.each(data, function (index, item) {
for( var key in item ) {}
$("<option/>", {
value: key,
text: item[key]
}).appendTo("#engine");
});
},
error: function (jxhr) {
alert(jxhr.responseText);
}
});
jsfiddle: http://jsfiddle.net/DBg2L/1/
I don't fully understand your question, especially the part about "So need the ID value as "1" and list options as the names." But the following will populate the select element with option elements that take value of each property in parsedjson (v) as the value and the name of each property (i) as the value visible to the user:
$.each(parsedjson, function(i, v){
$('select#engine').append('<option value="' + v + '">' + i + '</option>');
});
I need an example of how to code a jQuery autocomplete to populate product_id while showing the product_name calling an ajax page "remote.php"
<input name="product_name" id="product_name" type="text" value="" />
<input name="product_id" id="product_id" type="hidden" value="" />
remote.php:
$partial = addslashes($_POST['partial_search']);
$myDataRows = array();
$result = mysql_query ("SELECT product_id, product_name FROM products
WHERE product_name like "%$partial%");
while ($row = mysql_fetch_row($result)) {
array_push($myDataRows, $row);
}
$ret = json_encode ($myDataRows);
echo $ret;
I'm not sure how to code the jQuery autocomplete and if I need to change remote.php
thanks
ADDED LATER:
I worked out another solution:
<script type="text/javascript">
function nqi_search (type, id_name, text_name)
{
$( "#"+text_name ).autocomplete({
source: "remote.php?&t="+type,
minLength: 1,
select: function( event, ui ) {
$( "#"+id_name ).val(ui.item.id );
}
});
}
</script>
<script type="text/javascript">
jQuery(document).ready(function() {
nqi_search ("product_search", "product_id", "product_name");
// also you can have many on one page with:
nqi_search ("vendor_search", "vendor_id", "vendor_name");
});
</script>
There's one problem. it doesn't seem to work if the nqi_search function is put into a .js file. I have no idea why?
This is how I do it:
Note, I've coded a special feature where the json can flag an item as a message instead and in this way you can put messages in the list (eg I put a "Addition X items not shown" for long lists). To use the message feature, but the text in the label field and a true boolean for the message field.
To use this on the page I just have
setupAutocomplete(<id of textbox>,<path to service>);
$.ajaxSetup({
type: "POST",
contentType: "application/json; charset=utf-8",
data: "{}",
dataFilter: function(data) {
var msg;
if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function')
msg = JSON.parse(data);
else
msg = eval('(' + data + ')');
if (msg.hasOwnProperty('d'))
return msg.d;
else
return msg;
},
error: function(msg) {
$('#error').html(msg.responseText)
}
});
// remove this to get rid of custom message handling
$.widget("custom.redcomplete", $.ui.autocomplete, {
_renderMenu: function(ul, items) {
var self = this;
$.each(items, function(index, item) {
if (item.message)
ul.append("<li class='ui-menu-item special-red'> " + item.label + "</li>");
else
self._renderItem(ul, item)
});
}
function setupAutocomplete(inID, inURL) {
var myTB = $("[id$='_" + inID + "']");
// change redcomplete to autocomplete to get rid of message handling
myTB.redcomplete({
source: function(request, response) {
$.ajax({
url: inURL,
data: "{'filter': '" + request.term + "'}",
success: function(data) {
response($.map(data, function(item) {
return {
label: item.text,
value: item.id,
// remove this line and the , above to get rid of message handling
message: item.message
};
}));
}
})
},
delay: 500,
minLength: 3,
focus: function(event, ui) {
myTB.val(ui.item.label);
return false;
},
select: function(event, ui) {
// action for the select here.
return false;
},
open: function() {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function() {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
}
});