I've been able to save canvas image data using .ajax() and php but not in cake. The way I've done it is like the following. I have a javascript that runs when a user clicks "submit" button in a form after making a canvas drawing:
var formdata = $("form").serialize();
var data = document.getElementById("canvasElement").toDataURL();
formdata += "&img=" + data;
$.ajax({
type: "POST",
url: "process.php",
data: formdata,
success: function() {
$('body').prepend('<div class="alert">Your bit of data was successfully saved.</div');
$('.alert').delay(2000).slideUp('slow');
},
error:function (xhr, ajaxOptions, thrownError){
alert("Error Status: " + xhr.status + " Thrown Errors: "+thrownError);
}
Then process.php handles the image data and saves it to a file. Here's the salient part:
$img = $_POST['img'];
// remove header information that's sent with the encoded data
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = "images/" . uniqid() . '.png';
This all works as I hoped. How can I do this in a cakephp framework? I've read that in place of a regular cake form submit, you can use the Js helper for an ajax submit like this:
echo $this->Js->submit('Save');
Are there arguments I could pass into the submit function that would let me save the image data? Is there a better way?
I've gotten it to work, but I'm not completely sure I understand why and I'd like to understand the best way to do this in cake. I added a command for the Js helper to put scripts in the head with this: echo $this->Js->writeBuffer(array('cache'=>TRUE));
Other than that, I don't think I changed anything. However, my redirect in my save function in the controller doesn't do anything. I'm only able to achieve a redirect by putting it in the javascript as below.
<?php
// This is my form for saving the drawing
echo $this->Form->create('Drawing');
echo $this->Js->submit('Save', array(
'before'=>$this->Js->get('#sending')->effect('fadeIn')
));
echo $this->Form->end();
?>
public function save() {
// This is my save function in the controller
if ($this->request->is('post')) {
$img = $this->request->data['img'];
// remove header information that's sent with the encoded data
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = uniqid() . '.png';
$filepath = 'drawings/';
$success = file_put_contents($filepath . $file, $data);
print $success ? $file : 'Unable to save the file.';
$arr = array( 'Drawing' => array ( 'filename' => $file, 'filepath' => '/images'));
if ($this->Drawing->save($arr)) {
$this->Session->setFlash('Your drawing has been saved!');
// this redirect doesn't work (and I do have an index page and function)
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Unable to add your post.');
}
}
}
Javascript is here:
var data = document.getElementById("canvasElement").toDataURL();
formdata = "img=" + data;
$.ajax({
type: "POST",
url: "save",
data: formdata,
success: function() {
window.location.replace("index"); // This redirect works
},
error:function (xhr, ajaxOptions, thrownError){
alert('error in: ' + settings.url + ' \\n'+'error:\\n' + exception);
}
});
}
Related
I´m trying to upload my img with ajax, and generate one PDF with barryPDF but my problem it´s i have two different img.
for to do this, i´m sendning in my ajax and form_data one parameter and so i distint my img:
function ajaxDNI2(){
data = new FormData();
let token = $("meta[name='csrf-token']").attr("content");
data.append('file', $("#dni2_cliente")[0].files[0]);
data.append('_token', token);
data.append('dni_atras', 'dni_atras');
$(".dni2").addClass('borderClass');
$.ajax({
url: document.location.origin+'/admin/precontratos/precontratos/dataClientImages',
method: 'POST',
processData: false,
contentType: false,
data: data,
success: function(response){
progressDni2();
$("#imageDniClient").attr('src', response);
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
in my controller i have my function:
if($request->hasFile('file')){
if($request->get('dni_delante') == "dni_delante"){
$image = $request->file('file');
$name = time().'.'.$image->getClientOriginalExtension();
$destinationPath = public_path('storage/datosCliente');
$image->move($destinationPath, $name);
}
if($request->get('dni_atras') == "dni_atras"){
$image2 = $request->file('file');
$name2 = time().'.'.$image2->getClientOriginalExtension();
$destinationPath2 = public_path('storage/datosCliente');
$image2->move($destinationPath2, $name2);
$pdfName = "documentacion.pdf";
$pathSavePdf = public_path('storage/datosCliente');
$pdf = PDF::loadView('pdf.dni', ['image' => $name, 'image2' => $name2])
->setPaper('a4')
->setOrientation('Portrait')
//->setOption('zoom', 1.2)
->setOption('footer-center', 'EDICIONES GRUPO DELUXE 2013 S.L.U está Inscripta en el Registro Mercantil de Granada al Tomo 1548 Folio 42 Hoja GR46323 Inscrip. 1ª')
->setOption('footer-font-size', 5);
$pdfCreado = $pdf->save($pathSavePdf, true);
}
}
this function upload my img ok, but in my PDF loadView i´m sending my two img. But my problem it´s that return 500 error not defined $name
[2022-04-20 10:53:02] local.ERROR: Undefined variable: name {"userId":60,"exception":"[object] (ErrorException(code: 0): Undefined variable: name at
all my imgs it´s uploaded ok.
Thanks for readme and sorry for my bad english
I'm trying to put all of the pieces of this puzzle together. I've been reading all of the questions and answers on this subject for the past 3 days. So the general blueprint that i'm following is as follows:
On single product page, first checking whether the type of product is "simple" or "variable".
If product is "variable" then i'm using woocommerce_variable_add_to_cart(); function to output the proper html.
Then trying to generate new and custom html (i.e "radio buttons") using the defualt html (i.e "dropdown menu") and woocommerce hooks.
Then trying to give functionality to the new and custom html (i.e "radio buttons") using javascript.
Then hiding the default dropdown menu using css.
Then trying to send an ajax request to the wordpress.
Then trying to process that ajax request on the backend and add the product to the cart.
Here is my code for each section:
Checking whether the type of product is "variable" on the single product page:
global $post;
$product = wc_get_product($post->ID);
$product_type = $product->get_type();
If the product type is "variable" then output the proper html:
if($product_type == 'variable'):
woocommerce_variable_add_to_cart();
endif;
Generating new and custom html (radio buttons) using php and woocommerce hooks:
add_filter('woocommerce_dropdown_variation_attribute_options_html', 'my_theme_variation_radio_buttons', 20, 2);
function my_theme_variation_radio_buttons($html, $args)
{
$args = wp_parse_args(apply_filters('woocommerce_dropdown_variation_attribute_options_args', $args), array(
'options' => false,
'attribute' => false,
'product' => false,
'selected' => false,
'name' => '',
'id' => '',
'class' => '',
'show_option_none' => __('Choose an option', 'woocommerce'),
));
if (false === $args['selected'] && $args['attribute'] && $args['product'] instanceof WC_Product) {
$selected_key = 'attribute_' . sanitize_title($args['attribute']);
$args['selected'] = isset($_REQUEST[$selected_key]) ? wc_clean(wp_unslash($_REQUEST[$selected_key])) : $args['product']->get_variation_default_attribute($args['attribute']);
}
$options = $args['options'];
$product = $args['product'];
$attribute = $args['attribute'];
$name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title($attribute);
$id = $args['id'] ? $args['id'] : sanitize_title($attribute);
$class = $args['class'];
$show_option_none = (bool)$args['show_option_none'];
$show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __('Choose an option', 'woocommerce');
if (empty($options) && !empty($product) && !empty($attribute)) {
$attributes = $product->get_variation_attributes();
$options = $attributes[$attribute];
}
$radios = '<div class="variation-radios">';
if (!empty($options)) {
if ($product && taxonomy_exists($attribute)) {
$terms = wc_get_product_terms($product->get_id(), $attribute, array(
'fields' => 'all',
));
foreach ($terms as $term) {
if (in_array($term->slug, $options, true)) {
$id = $name . '-' . $term->slug;
$radios .= '<input type="radio" data-checked="no" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr($term->slug) . '" ' . checked(sanitize_title($args['selected']), $term->slug, false) . '><label for="' . esc_attr($id) . '">' . esc_html(apply_filters('woocommerce_variation_option_name', $term->name)) . '</label>';
}
}
} else {
foreach ($options as $option) {
$id = $name . '-' . $option;
$checked = sanitize_title($args['selected']) === $args['selected'] ? checked($args['selected'], sanitize_title($option), false) : checked($args['selected'], $option, false);
$radios .= '<input type="radio" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr($option) . '" id="' . sanitize_title($option) . '" ' . $checked . '><label for="' . esc_attr($id) . '">' . esc_html(apply_filters('woocommerce_variation_option_name', $option)) . '</label>';
}
}
}
$radios .= '</div>';
return $html . $radios;
}
add_filter('woocommerce_variation_is_active', 'my_theme_variation_check', 10, 2);
function my_theme_variation_check($active, $variation)
{
if (!$variation->is_in_stock() && !$variation->backorders_allowed()) {
return false;
}
return $active;
}
Giving functionality to "radio buttons" using javascript:
jQuery(document).ready($ => {
$(document).on('change', '.variation-radio input', function () {
$('.variation-radio input:checked').each(function (index, element) {
var radioElement = $(element);
var radioName = radioElement.attr('name');
var radioValue = radioElement.attr('value');
$('select[name="' + radioName + '"]').val(radioValue).trigger('change');
});
});
$(document).on('woocommerce_update_variation_values', function () {
$('.variation-radio input').each(function (index, element) {
var radioElement = $(element);
var radioName = radioElement.attr('name');
var radioValue = radioElement.attr('value');
radioElement.removeAttr('disabled');
if ($('select[name="' + radioName + '"] option[value="' + radioValue + '"]').is(':disabled')) {
radioElement.prop('disabled', true);
}
});
});
$("a.reset_variations").click(function () {
$('input:radio[name="attribute_size"]').prop('checked', false); $(this).css('display', 'none');
});
})
Hiding the default dropdown menu using css:
table.variations select{
display: none;
}
Sending an ajax request to the wordpress:
jQuery(document).ready($ => {
$("button.single_add_to_cart_button").on('click', function (e) {
e.preventDefault();
var myBtn = $(this),
$form = myBtn.closest('form.variations_form'),
product_qty = $form.find('input[name=quantity]').val() || 1,
product_id = $form.find('input[name=product_id]').val(),
variation_id = $form.find('input[name=variation_id]').val() || 0,
variation = {},
keys = [],
values = [];
// Looping through the attributes names and save them as the keys array
$('table tr td.label label').each(function (index, element) {
let radioElement = $(element);
keys[index] = radioElement.text();
});
// Looping through the attributes values and save them as the values array
$('.variation-radios input:checked').each(function (index, element) {
let radioElement = $(element);
values[index] = radioElement.val();
});
// Looping through the variation object and save keys and values in that object
$.each(keys, function (index, element) {
variation[element] = values[index]
})
console.log(variation);
var data = {
action: 'woocommerce_add_variation_to_cart',
product_id: product_id,
quantity: product_qty,
variation_id: variation_id,
var: variation
};
$(document.body).trigger('adding_to_cart', [myBtn, data]);
$.ajax({
type: 'post',
url: wc_add_to_cart_params.ajax_url,
data: data,
beforeSend: function (response) {
myBtn.removeClass('added').addClass('loading');
},
complete: function (response) {
myBtn.addClass('added').removeClass('loading');
},
success: function (response) {
console.log(response);
if (response.error && response.product_url) {
window.location = response.product_url;
return;
} else {
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, myBtn]);
}
},
});
return false;
});
})
Processing the ajax request on the backend and add the product to the cart:
add_action('wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'my_theme_testing_add_to_cart_variable');
add_action('wp_ajax_woocommerce_add_variation_to_cart', 'my_theme_testing_add_to_cart_variable');
function my_theme_testing_add_to_cart_variable()
{
if (isset($_POST['product_id']) && $_POST['product_id'] > 0) {
$product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($_POST['product_id']));
$quantity = empty($_POST['quantity']) ? 1 : wc_stock_amount($_POST['quantity']);
$variation_id = isset($_POST['variation_id']) ? absint($_POST['variation_id']) : '';
$attributes = explode(',', $_POST['var']);
$variation = array();
foreach ($attributes as $values) {
$values = explode(':', $values);
$variation['attributes_' . $values[0]] = $values[1];
}
$passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity);
if ($passed_validation && WC()->cart->add_to_cart($product_id, $quantity, $variation_id, $variation)) {
do_action('woocommerce_ajax_added_to_cart', $product_id);
if (get_option('woocommerce_cart_redirect_after_add') == 'yes') {
wc_add_to_cart_message($product_id);
}
WC_AJAX::get_refreshed_fragments();
} else {
$data = array(
'error' => true,
'product_url' => apply_filters('woocommerce_cart_redirect_after_error', get_permalink($product_id), $product_id)
);
wp_send_json($data);
}
die();
}
}
PROBLEM
Everything works until step 7 with no error but when i run the whole thing, the single product page refreshes and variable product doesn't get added to the cart. And the wordpress error says "{your attribute field} is a required field"!
I think the bug could be somewhere in the ajax call when i'm trying to send variation object to the backend.
Although, i get the data absolutely fine on the backend but it doesn't add it to the cart.
Things that i've tried to debug it
I've tried to send the data in the ajax call as an array but didn't work either.
I also tried to explode the variation data using both = and : but none has worked!
Hooof! It's been a long week so far :\ full of debugging, headaches and frustrations. Now when i try to run the whole shebang, i can't get it to work and i've been reading all of the Qs and As on SO but can't find the bug! I think i've been overthinking it for a couple of days and also there are lots of pieces to it.
So i think i need some extra pairs of eyes to hopefully detect the bug.
Thank you, i appreciate any insight(s)!
In addition, huge shout out to these fellows whom i've learned a lot from:
LoicTheAztec for this great answer and this and this and many more.
cfx for this great answer
Anthony Grist for this answer
helgatheviking for this answer
AND OTHERS
EDIT
The code works fine, bug wasn't in the code, it was in the data that i was provided with. I'll leave the code here just in case somebody needs it in the future.
Short ansewer
The code works fine, i'll leave it here just in case somebody needs it in the future. Bug wasn't in the code, it was in the data that i was provided with.
Detailed Explanation
The code works fine. The data that i was provided with was manipulated for some reasons by my client so that each variable product wasn't a real variable product but at the same time the labels were typed in as variable products (yea i know it's confusing and not a standard practice), that's why whenever i tried to add them to cart, it would give the error saying {your-attribute} is a required field.
So we deleted each product data and add it back as a real and true variable product, then the code worked without us changing anything in it.
Take-away
So remember, whenever developing your app, there are always two sides to this coin! One side is your code and the other side is the data you're working on.
So, always always always, make sure the data you're working with is the way/format it's supposed to be. Also if you can't find any bug in your code, remember to check/debug the other side which is the data.
If you don't check the data first or at any debugging stage, then it'll be hard to track down the issue down the road!
This bug created a long delay in the project (about 2 weeks until we tracked down the bug in the data). So make sure to always check the both sides of the coin:
First, the data you're working with
Second, the code you wrote.
I'm creating one plugin to get data from custom table using datatable server side scripting.
In query i'm getting right response but in ajax function call getting 400 bad request
Request URL: http://localhost/Project_name/wp-admin/admin-ajax.php
Request Method: POST
Status Code: 400 Bad Request
Remote Address: [::1]:80
my ajax js file
$(document).ready(function() {
var dataTable = $('#employee-grid').DataTable( {
"processing": true,
"serverSide": true,
dataType: "json",
contentType: "application/json",
"ajax":{
"url" : 'admin-ajax.php',
"type": "POST",
"data": {action: 'my_action'},
error: function(){ // error handling
$(".employee-grid-error").html("");
$("#employee-grid").append('<tbody class="employee-grid-error"><tr><th colspan="3">No data found in the server</th></tr></tbody>');
$("#employee-grid_processing").css("display","none");},
success: function(data){
alert(data);
}
},
"columns": [
{"data": "employee_name"},
{"data": "employee_salary"},
{"data": "employee_age"}
], "columnDefs": [
//{"orderable": false, "targets": 12}
]
} );
} );
in ajax file also adding wp_ajax_my_action and wp_ajax_nopriv_my_action action.
ajaxfile function file
add_action( 'wp_ajax_my_action', 'my_action' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action' );
function my_action() {
global $wpdb;
## Read value
$draw = $_POST['draw'];
$row = $_POST['start'];
$rowperpage = $_POST['length']; // Rows display per page
$columnIndex = $_POST['order'][0]['column']; // Column index
$columnName = $_POST['columns'][$columnIndex]['data']; // Column name
$columnSortOrder = $_POST['order'][0]['dir']; // asc or desc
$searchValue = $_POST['search']['value']; // Search value
## Search
$searchQuery = " ";
if($searchValue != ''){
$searchQuery = " and (reportNo like '%".$searchValue."%' or ) ";
}
$totalRecordwithFilter = $records['allcount'];
## Total number of records without filtering
$sel = $wpdb->get_results('SELECT * FROM ' . $wpdb->prefix . 'employee');
$totalRecords = count($sel);
## Total number of records with filtering
/* $sel = mysqli_query($con,"select count(*) as allcount from employee WHERE 1 ".$searchQuery);
$records = mysqli_fetch_assoc($sel); */
$resultCount = $wpdb->get_results('SELECT * FROM ' . $wpdb->prefix . 'employee where '.$searchQuery);
$totalRecordwithFilter = count($resultCount);
## Fetch records
//$empQuery = "select * from employee WHERE 1 ".$searchQuery." order by ".$columnName." ".$columnSortOrder." limit ".$row.",".$rowperpage;
$empRecords = $wpdb->get_results('SELECT * FROM ' . $wpdb->prefix . 'employee where '.$searchQuery.' order by ' . $columnName . ' ' . $columnSortOrder . ' limit ' . $row . ',' . $rowperpage);
$empRecords = mysqli_query($con, $empQuery);
$data = array();
foreach ($sel as $row) {
$data[] = array(
"emp_name"=>$row->employee_name,
"salary"=>$row->employee_salary,
"age"=>$row->employee_age
);
}
## Response
$response = array(
"draw" => intval($draw),
"iTotalRecords" => $totalRecords,
"iTotalDisplayRecords" => $totalRecordwithFilter,
"aaData" => $data
);
echo json_encode($response);
exit();
}
UPDATE
As I checked you use parameters that don't exist in your POST method, you need to add them and also check that they are exist
you should pass you POST parameters with your ajax function like this
data: {
action: 'search_enrollment_by_scode',
draw : 'draw',
row : 'start',
rowperpage : 'length',
columnIndex : 'order',
columnName : 'columns',
columnSortOrder : 'order',
searchValue : 'search',
}
NOTE: you should add your valid data or variable
Your PHP file
<?php
add_action( 'wp_ajax_my_action', 'my_action' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action' );
function my_action() {
global $wpdb;
## Read value
// you need to check that you have this data or not
// you just add action data not any of bellow list
if ($_POST['draw']) {
$draw = $_POST['draw'];
.
.
.
.
.
.
.
echo json_encode($response);
}
else
{
echo json_encode('Data is invalid or not complete');
}
exit();
}
?>
Try this and then replace the ajaxurl variable in your "url" : 'admin-ajax.php',
<script type="text/javascript">
var ajaxurl = "<?php echo admin_url('admin-ajax.php'); ?>";
</script>
As is described in the Wordpress AJAX documentation, you have two different hooks - wp_ajax_(action), and wp_ajax_nopriv_(action). The difference between these is:
wp_ajax_(action): This is fired if the ajax call is made from inside the admin panel.
wp_ajax_nopriv_(action): This is fired if the ajax call is made from the front end of the website.
I am trying to get subcategories according to categories by ajax.So I have sent data in controller by ajax get method like bellow code in add.ctp
$('document').ready(function(){
$( "#division" ).change(function() {
var value=$('#division').val();
$.get("<?php echo Router::url(array('controller'=>'userStoreSelections','action'=>'add'));?>",{list:value},function(data){
$('.districts').html(data);
alert(data);
});
});
});
In controller in find methods when I am writing bellow code It's working fine.
$madDistricts = $this->UserStoreSelection->MadDistricts->find('list',array(
'conditions'=>array('mad_divisions_id'=>3)
));
But when I give the value that I have sent by ajax it's not working.I have written like this
$madDistricts = $this->UserStoreSelection->MadDistricts->find('list',array(
'conditions'=>array('mad_divisions_id'=>"$list")
));
It showing the query like this
SELECT `MadDistricts`.`id`, `MadDistricts`.`name` FROM `store`.`mad_districts` AS `MadDistricts` WHERE `mad_divisions_id` IS NULL
After select categories nothing change in query.I have tested ajax code there is no problem to send value.
For more specific this is the add action code
public function add() {
if(isset($this->request->query['list'])){
$search = $this->request->query['list'];
echo $search;
}
else{
$search = '';
}
if ($this->request->is('post')) {
$this->UserStoreSelection->create();
if ($this->UserStoreSelection->save($this->request->data)) {
$this->Session->setFlash(__('The user store selection has been saved.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user store selection could not be saved. Please, try again.'));
}
}
$madDivisions = $this->UserStoreSelection->MadDivisions->find('list');
$madDistricts = $this->UserStoreSelection->MadDistricts->find('list',array(
'conditions'=>array('mad_divisions_id'=>"$list")
));
$madAreas = $this->UserStoreSelection->MadAreas->find('list');
$users = $this->UserStoreSelection->Users->find('list',array('fields' => array('id','username')));
$madStores = $this->UserStoreSelection->MadStores->find('list',array('fields' => array('id','store_name')));
$this->set(compact('madDivisions', 'madDistricts', 'madAreas', 'users','madStores'));
}
You need to change your add.ctp file code like as :
$('document').ready(function () {
$("#division").change(function () {
var value = $(this).val();
$.ajax({
url: '<?php echo Router::url(' / ',true);?>userStoreSelections/subcategories',
type: "POST",
dataType: 'json',
data: 'category=' + id,
success: function (res) {
var html = '<option>Sub Category</option>';
if (res.flage == true) {
html = res.data;
}
$('.districts').html(html);
}
});
});
});
Than create a function in your userStoreSelections for get sub categories as
public function subcategories() {
$response = array('flage' => false);
$madDistricts = $this->UserStoreSelection->MadDistricts->find('list', array(
'conditions' => array('mad_divisions_id' => $this->request->data['category'])
));
$options = "<option>Subcategories</option>";
if ($states) {
$response['flage'] = true;
foreach ($madDistricts as $id => $name) {
$options .= "<option value='" . $id . "'>" . $name . "</option>";
}
$response['data'] = $options;
}
echo json_encode($response);
exit;
}
i am trying to get a response from codeigniter when I send my ajax request from sencha touch/ Ext with
Ext.Ajax.request({//
url: formBase.url, //something like 'http://path.to/mobile/Login/ajax_validateLogin',
success: function(response, opts) {
console.log('Login success!');
console.log('data: ' + response.responseText);
},
failure: function(result){
console.log('Login Error! ');
},
method: 'POST',
params: form.getValues()
});
form = new Ext.form.FormPanel(formBase);
//...
and in codeigniter something like
function ajax_validateLogin() {
$username = $this->input->post('username');
$password = $this->input->post('password');
$data['username'] = 'Arschkarte'; //$username;
if($username == "f"){
$data["success"] = true;
} else {
$data["success"] = false;
$data["errors"]["reason"] = "Login failed. Try again.";
}
$this->load->view('mobile/loginMobile', $data);
}
and the view
<?php
echo 'username: '.$username;
?>
i allways get the Error "Login Failed" and the response of the POST is allways empty (while parameters are send correctly)
any ideas?
THNX!!!