Woocommerce modify required fields with ajax - php

I added Woocommerce Billing Adress a fields like 'field_x" as required from child theme's function.php. And then added radio buttons with two option 'A and B' same page. I want to do that:
if user select radio option A, my custom fields will be invisible and 'not required'
if user select radio option B, my custom fields will be visible and 'required'
My sample code:
<?
// Adding fields and radios
add_filter('woocommerce_billing_fields', 'some_woocommerce_billing_fields', 10, 1);
function some_woocommerce_billing_fields($fields) {
$fields['radio_select'] = array(
'label' => __('Please select', 'woocommerce'),
'required' => true,
'clear' => false,
'type' => 'radio',
'options' => array(
'op_a' => __('op A', 'woocommerce'),
'op_b' => __('op B', 'woocommerce')));
$fields['field_x'] = array(
'label' => __('Field X', 'woocommerce'),
'placeholder' => _x('Field X', 'placeholder', 'woocommerce'),
'required' => true,
'clear' => false);
return $fields;
}
// PHP functions for Ajax calls
add_action('wp_enqueue_scripts', 'majax_enqueue_scripts');
add_action('wp_ajax_f_remove_req', 'f_remove_req');
add_action('wp_ajax_nopriv_f_remove_req', 'f_remove_req');
function majax_enqueue_scripts() {
$nonce = wp_create_nonce("nonce_t");
wp_enqueue_script('url', true);
wp_localize_script('url', 'urlm', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => $nonce));
}
// Adding filter to remove require
function f_remove_req() {
if (!wp_verify_nonce($_POST['nonce'], 'nonce_t'))
die();
add_filter('woocommerce_process_myaccount_field_field_x', 'remove_reqs', 10, 1);
die();
}
// Removing require
function remove_reqs($field) {
$field['field_x']['required'] = false;
return $field;
}
// Add Ajax function
add_action('woocommerce_after_edit_account_address_form', 'address_script');
function address_script() {
?>
< script >
jQuery(document).ready(function () {
jQuery('#radio_select_op_a').change(function () {
jQuery('#field_x_field').hide();
jQuery.post(urlm.ajax_url, {
'action' : 'f_remove_req',
'nonce' : urlm.nonce
},
function (response) {
console.log(response);
});
});
jQuery('#radio_select_op_b').change(function () {
jQuery('#field_x_field').show();
jQuery.post(urlm.ajax_url, {
'action' : 'f_add_req',
'nonce' : urlm.nonce
},
function (response) {
console.log(response);
});
});
});
</ script>
<?
}
?>
i can add fields and ajax function is working.
But when i click "Save", php always sends filed_x->require option as true.
What is wrong? How can i do this?
Thank you.

Related

Issue with Rendering Custom module Terms and Conditions field

I would like to move the jQuery code to a separate file like you can see in the second code but if I do this the functionality of the code does not display on the page. The first code works properly and the second code does not work?
I turned off the caching plugin and still nothing.
There are other modules in this custom-woocommerce.js file and those work fine only code from this example shows some problems.
First Code
add_action('woocommerce_review_order_before_submit', 'cart_privacy_policy_checkbox', 5);
function cart_privacy_policy_checkbox()
{
woocommerce_form_field('privacy_policy', array(
'type' => 'checkbox',
'class' => array('form-row privacy'),
'label_class' => array('woocommerce-form__label woocommerce-form__label-for-checkbox checkbox'),
'input_class' => array('woocommerce-form__input woocommerce-form__input-checkbox input-checkbox'),
'required' => true,
'label' => sprintf(
__('<span class="woocommerce-terms-and-conditions-checkbox-text">Przeczytałem/am i akceptuję <strong>Regulamin</strong></span>'),
),
));
if (is_checkout()) {
wp_enqueue_script('sweetalert2', 'https://cdn.jsdelivr.net/npm/sweetalert2#11.6.15/dist/sweetalert2.all.min.js', array(), '11.6.15', false);
wp_enqueue_script('promise-polyfill', 'https://cdnjs.cloudflare.com/ajax/libs/promise-polyfill/8.2.3/polyfill.min.js', array(), '8.2.3', false);
?>
<script type="text/javascript">
jQuery(function($) {
var a = '#place_order',
b = '#privacy_policy',
c = '<?php echo wc_get_checkout_url(); ?>',
d = 'disabled';
// Set disable button state
$(a).addClass(d).prop('href', '#');
// On button click event
$('body').on('click', a, function(e) {
if (!$(b).prop('checked')) {
// Disable "Proceed to checkout" button
e.preventDefault();
// disabling button state
if (!$(a).hasClass(d)) {
$(a).addClass(d).prop('href', '#');
}
// Sweet alert 2
Swal.fire({
background: '#fff',
toast: false,
width: 'auto',
icon: 'error',
position: 'center',
title: 'Wystąpił błąd',
html: '<strong>Zaakceptowanie regulaminu jest wymagane,</strong> ' +
'aby kontynuować składanie zamówienia',
// text: ' ',
timer: 5000,
timerProgressBar: true,
showConfirmButton: false
});
}
});
// On checkbox change event
$(b).change(function() {
if ($(this).prop('checked')) {
if ($(a).hasClass(d)) {
$(a).removeClass(d).prop('href', c);
}
} else {
if (!$(a).hasClass(d)) {
$(a).addClass(d).prop('href', '#');
}
}
});
$('#privacy_policy').click(function() {
if ($(this).is(":checked")) {
$('.custom-download-info').fadeIn('300');
} else {
$('.custom-download-info').fadeOut('300');
}
})
});
</script>
<?php
}
}
Second code
add_action('woocommerce_review_order_before_submit', 'cart_privacy_policy_checkbox', 5);
function cart_privacy_policy_checkbox()
{
woocommerce_form_field('privacy_policy', array(
'type' => 'checkbox',
'class' => array('form-row privacy'),
'label_class' => array('woocommerce-form__label woocommerce-form__label-for-checkbox checkbox'),
'input_class' => array('woocommerce-form__input woocommerce-form__input-checkbox input-checkbox'),
'required' => true,
'label' => sprintf(
__('<span class="woocommerce-terms-and-conditions-checkbox-text">Przeczytałem/am i akceptuję <strong>Regulamin</strong></span>'),
),
));
if (is_checkout()) {
wp_enqueue_script('sweetalert2', 'https://cdn.jsdelivr.net/npm/sweetalert2#11.6.15/dist/sweetalert2.all.min.js', array(), '11.6.15', false);
wp_enqueue_script('promise-polyfill', 'https://cdnjs.cloudflare.com/ajax/libs/promise-polyfill/8.2.3/polyfill.min.js', array(), '8.2.3', false);
wp_enqueue_script('custom-woocommerce', '/path/to/custom-woocommerce.js', array(), '1.0.0.' . time(), false);
}
}

Symfony - Override field options (required = false to required = true)

I want to accomplish the following:
FormType -> If my checkbox is checked, hide a normally required field and make it required = false, so I can submit my Form.
So I need to override a specific form field if my checkbox is checked. Example...
Form:
$builder->add(
'checkbox',
CheckboxType::class,
[
'label' => 'checkbox',
'required' => false,
'mapped' => false,
'attr' => [
'class' => 'checkbox',
]
]
);
index:
$('.checkbox').change(function () {
if ($('.checkbox').is(':checked')) {
$(".end-date").hide();
} else {
$(".end-date").show();
}
});
how do i continue?
i tried something like this (somehow it's not working):
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$form = $event->getForm();
$config = $form->get('what_ever_field')->getConfig();
$options = $config->getOptions();
$form->add(
'what_ever_field',
get_class($config->getType()->getInnerType()),
array_replace(
$options,
[
'required' => false,
]
)
);
});
But it makes no sense because the checkbox and the listener have no relation.
I think it would be much easier to dynamically change the field's required attribute via JS after it's rendered on the page. You're half way there:
JS
$('.checkbox').change(function() {
if ($('.checkbox').is(':checked')) {
$(".end-date").removeAttr("required");
$(".end-date").hide();
} else {
$(".end-date").attr("required","required");
$(".end-date").show();
}
});
This JQuery code can be optimized, but that's about it. Hope it helped.

Arguments from Controller passed to View was not fetched in php

Im Using
PHP language , yii-1.1.13 framework and MySQL DB.
Views code of Main Page.
<?php
/**
* The view for the trip schedules page.
* #uses ManageTripSchedulesForm $model
* #uses VoyageServiceClassInfo $voyageServiceClassInfo
* #uses LocationInfo $locationInfo
* #uses PierInfo $pierInfo
* #uses VesselInfo $vesselInfo
* #uses ServiceClassInfo $serviceClassInfo
* #uses FareSetInfo $fareSetInfo
* #uses SearchTripsForm $searchTripsForm
* #uses FerryOperatorInfo $ferryOperatorInfo
* #uses ManageTripSchedulesFilterForm $filterForm
*/
$this->setPageTitle(SystemConstants::SITE_NAME . ' - Trip Schedules');
$baseUrl = Yii::app()->getBaseUrl();
$cs = Yii::app()->getClientScript();
// --- POS_HEAD
// a plug-in used in manageTripSchedules.js
$cs->registerScriptFile($baseUrl . '/js/jquery.blockUI.js', CClientScript::POS_HEAD);
// for this view
$cs->registerCssFile($baseUrl . '/css/manageTripSchedules.css');
$cs->registerScriptFile($baseUrl . '/js/manageTripSchedules.js', CClientScript::POS_HEAD);
$this->endWidget('zii.widgets.jui.CJuiDialog');
/**
* Maintenance Dialog widget
*/
$this->beginWidget('zii.widgets.jui.CJuiDialog',array(
'id'=>'dialog',
'options' => array(
'title' => 'Trip Schedules',
'autoOpen' => false,
'modal' => true,
'resizable' => false,
'width' => 600,
'dialogClass' => 'tripschedules-dialog-class',
'show'=>array(
'effect'=>'drop',
'duration'=>500,
),
'hide'=>array(
'effect'=>'drop',
'duration'=>500,
),
),
));
/**
* Render the maintenance dialog view.
*/
echo $this->renderPartial('manageTripSchedulesDialog', array(
'model' => $model,
'ferryOperatorInfo' => $ferryOperatorInfo,
'locationInfo' => $locationInfo,
'pierInfo' => $pierInfo,
'vesselInfo' => $vesselInfo,
'serviceClassInfo' => $serviceClassInfo,
'fareSetInfo' => $fareSetInfo
));
$this->endWidget('zii.widgets.jui.CJuiDialog');
<div id="grid-container" class="grid-div">
<?php
$pageSize = 10;
$helper = new TripSchedulesGridHelper($this);
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'tripschedules-grid',
'dataProvider' => $voyageServiceClassInfo->searchTripSchedules(Yii::app()->user->ferry_operator_id, $filterForm, $pageSize),
'emptyText' => 'No data found.',
'selectableRows' => 0,
'template' => '{items}{pager}', // to remove summary header
'pager' => array(
'header' => '', // to remove 'Go to page:'
),
'cssFile' => $baseUrl . '/css/manageTripSchedulesGrid.css',
'columns' => array(
array(
'name' => 'id',
'value' => '$data->voyage_service_class_id',
'headerHtmlOptions' => array('style' => 'display:none'),
'htmlOptions' => array('style' => 'display:none'),
),
'voyage.ferry_operator.name::Operator',
array(
'name' => 'Origin',
'value' => array($helper, 'formatOriginTerminal'),
),
array(
'name' => 'Destination',
'value' => array($helper, 'formatDestinationTerminal'),
),
array(
'name' => 'DepartureTime',
'header' => 'Departure',
'value' => array($helper, 'formatDepartureDate'),
),
array(
'name' => 'ArrivalTime',
'header' => 'Arrival',
'value' => array($helper, 'formatArrivalDate'),
),
array(
'name' => 'TripHrs',
'header' => 'Trip Hrs',
'value' => array($helper, 'formatTripDuration'),
),
'voyage.vessel.name::Vessel',
'service_class.name::Service Class',
'fare_set.fare_type::Fare Set',
array(
'class' => 'CButtonColumn',
'template'=>'{update}{delete1}',
'buttons'=>array(
'update' => array(
'label'=>'Edit',
'imageUrl'=>Yii::app()->baseUrl.'/images/gridview/update.png',
'url'=>'"#"',
'click'=>'function(){updateTripScheduleJs($(this).parent().parent().children(":nth-child(1)").text());}',
),
'delete1' => array(
'label'=>'Delete',
'imageUrl'=>Yii::app()->baseUrl.'/images/gridview/delete.png',
'url'=>'"#"',
'click'=>'function(){deleteTripScheduleJs($(this).parent().parent().children(":nth-child(1)").text());}',
),
),
),
),
));
?>
</div>
Views code of Add/Edit Dialog.
<?php
echo $form->dropDownList($model, 'service_class_id',
$serviceClassInfo->getAllServiceClassesForSelection2($model->ferry_operator_id,
$this->_ferryOperatorId , true, 'Select class'),
array(
'id' => 'service_class_id',
'class' => 'selectbox',
'ajax' => array(
'type'=>'POST',
'url'=>CController::createUrl('loadFareSet'),
'update'=>'#fare_set_id',
'data'=>array('service_class_id'=>'js:this.value'),
))
);
?>
In my Controller, below is my code.
<?php
class SiteController extends Controller
{
public $_ferryOperatorId;
public function actionRetrieveTripSchedule() {
$voyageServiceClassInfo = new VoyageServiceClassInfo;
if (isset($_POST['id']))
{
if (Yii::app()->request->isAjaxRequest)
{
$voyageServiceClassInfo = VoyageServiceClassInfo::model()->with('voyage')->findByPk($_POST['id']);
if ($voyageServiceClassInfo != null)
{
$this->_ferryOperatorId = '3';
$_json = array(
array('name'=>'voyage_service_class_id', 'value'=>$voyageServiceClassInfo->voyage_service_class_id),
array('name'=>'ferry_operator_id', 'value'=>$voyageServiceClassInfo->voyage->ferry_operator_id),
array('name'=>'origin_location_id', 'value'=>$voyageServiceClassInfo->voyage->origin_location_id),
array('name'=>'origin_pier_id', 'value'=>$voyageServiceClassInfo->voyage->origin_pier_id),
array('name'=>'destination_location_id', 'value'=>$voyageServiceClassInfo->voyage->destination_location_id),
array('name'=>'destination_pier_id', 'value'=>$voyageServiceClassInfo->voyage->destination_pier_id),
array('name'=>'departure_date', 'value'=>$voyageServiceClassInfo->voyage->departure_date),
array('name'=>'departure_time', 'value'=>$voyageServiceClassInfo->voyage->departure_time),
array('name'=>'arrival_date', 'value'=>$voyageServiceClassInfo->voyage->arrival_date),
array('name'=>'arrival_time', 'value'=>$voyageServiceClassInfo->voyage->arrival_time),
array('name'=>'vessel_id', 'value'=>$voyageServiceClassInfo->voyage->vessel_id),
array('name'=>'service_class_id', 'value'=>$voyageServiceClassInfo->service_class_id),
array('name'=>'fare_set_id', 'value'=>$voyageServiceClassInfo->fare_set_id),
);
echo CJSON::encode(array(
'status'=>'success',
'messages'=>"Target data is retrieved normally.",
'val'=>$_json,
));
}
else
{
echo CJSON::encode(array(
'status'=>'failure',
'messages'=>"Target data can not be retrieved from server.",
'val'=>$_json,
));
}
}
}
}
}
Models code of Service class drop down lists.
public function getAllServiceClassesForSelection2(
$operatorId = null, $operatorIdEdit = null, $addInstructionRow = false, $instruction = null)
{
$serviceClassArray = array();
if ($addInstructionRow) {
if ($instruction == null) {
$instruction = 'Select a ServiceClass';
}
$serviceClassArray += array('' => $instruction);
}
$criteria = new CDbCriteria;
$criteria->select = 'service_class_id, name';
if ($operatorId != null || $operatorId != '')
{
$criteria->condition = 'ferry_operator_id = ' . $operatorId;
}
if ($operatorIdEdit != null || $operatorIdEdit != '' && $model->operation_mode == AdminGeneralHelper::OPERATION_MODE_UPDATE)
{
$criteria->condition = 'ferry_operator_id = ' . $operatorIdEdit;
}
$criteria->order = 'name';
$servceClassInfos = $this->findAll($criteria);
foreach ($servceClassInfos as $servceClassInfo) {
$serviceClassArray += array(
$servceClassInfo->service_class_id => $servceClassInfo->name,
);
}
return $serviceClassArray;
}
In my JS file, below is my code.
function updateTripScheduleJs(id) {
// Get target data via controller and set values to fields of dialog.
$.blockUI({
message: "Loading data...",
});
$("#dialog-msg").html(""); // clear the message area of dialog
// Ajax request
$.ajax({
url: 'retrieveTripSchedule',
type: 'POST',
datatype: 'json',
data: $.parseJSON('{"id": '+id+'}'),
timeout: 20000,
beforeSend: function(){
},
success: function(data){
$.unblockUI();
var res = eval('(' + data + ')');
if (res.status == 'success'){
for (var idx in res.val){
if (res.val[idx].name == 'departure_time' || res.val[idx].name == 'arrival_time'){
$('#'+res.val[idx].name).attr('value',formatAMPM(res.val[idx].value));
} else {
$('#'+res.val[idx].name).attr('value',res.val[idx].value);
}
}
$("#operation_mode").attr('value','U'); // Set update mode
$(".submit-button").attr('value','Update Trip Schedule'); // Set submit button label
$(".update-only-div").css('display','block'); // Show columns for update
$(".create-only-div").css('display','none'); // Hide columns for update
$("#dialog").dialog("open");
} else {
alert("Trip Schedule does not exist. It may be deleted by other user");
$.fn.yiiGridView.update('tripschedules-grid'); // Refresh the list of service class.
}
},
error: function(){
$.unblockUI();
alert("Ajax Communication Error. Please contact system administrator.");
}
}
);
}
Below is the scenario:
I clicked the pencil icon, dialog will show. It will load all the
details depend on the selected row. This is correct.
It will load all the details. This is correct.
No. of values in Drop down lists for service class is wrong.
My expected output of service class is only 4 (based on DB) but in actual, all service class was displayed.
I found out that $this->_ferryOperatorId = '3' from controller that was used in views
($serviceClassInfo->getAllServiceClassesForSelection2($model->ferry_operator_id,
$this->_ferryOperatorId , true, 'Select class'))
has no value.
In my models code, if the ferryOperatorId = null, it will display all the
service class.
My question is what is the correct code for me to get the value of $this->_ferryOperatorId from controller
then used the value in views.
:(
Please help me to solve this.

Display Zend Form Validation error in Ajax

There is a Zend Registration Form. Having as input username, email, password and confirm password. Validator for email is following:
$this->add(array(
'name' => 'email_reg',
'required' => true,
'filters' => array(
array(
'name' => 'StripTags',
),
array(
'name' => 'StringTrim',
),
),
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'domain' => true,
'messages' => array(
\Zend\Validator\EmailAddress::INVALID_FORMAT => 'Email address format is invalid'
),
),
),
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => 'user',
'field' => 'email',
'adapter' => $sm->get ( 'Zend\Db\Adapter\Adapter' ),
'messages' => array(
NoRecordExists::ERROR_RECORD_FOUND => 'E-mail address already exists'
),
),
),
),
));
There are 4 validators: Required Type, e-amil format and if there is someone with following e-mail in database.
Error messages will be:
- E-mail is required
- Email address format is invalid
- E-mail address already exists
Problem Trying to catch error messages and output using ajax. In RegisterController having following function:
public function ajaxAction()
{
if (!$this->request->isPost()) {
return $this->redirect()->toRoute(NULL,
array( 'controller' => 'index'
)
);
}
$form = $this->getServiceLocator()->get('RegisterForm');
$form->setInputFilter(new RegisterFilter($this->getServiceLocator()));
$post = $this->request->getPost();
$form->setData($post);
$response = $this->getResponse();
$hello = 1;
if (!$form->isValid()){
// email is invalid; print the reasons
$json= $form->getMessages();
$response->setContent(\Zend\Json\Json::encode($json));
}
return $response;
}
And jQuery file:
$( document ).ready(function() {
var urlform = "register/ajax";
$("#btnRegister").click( function() {
$("#Register").submit( function() {
return false;
});
$.ajax({
url: urlform,
type: 'POST',
dataType: 'json',
async: true,
data: $(".form-signin").serialize(),
success: function (data) {
$("#rCheck").text(data);
console.log(data);
},
error: function (data) {
$("#rCheck").text(data);
console.log(data);
}
});
});
});
In Console i got something like this https://imagizer.imageshack.us/v2/558x205q90/661/uC09Da.png and in div with id #rCheck getting [Object][Object].
From the image you provided the error messages are correctly returned. The error is that you are trying to write directly an Object into your div.
You should have seached how to read an object with JavaScript. Try with this code :
success: function (data) {
data.forEach(function(datum) {
Object.keys(datum).forEach(function (key) {
$('<p>'+obj[key]+'</p>').appendTo('#rCheck');
});
});
console.log(data);
},
Or you may also do that within your ajaxAction :
$messages = array();
$errors = $form->getMessages();
foreach($errors as $key=>$row)
{
if (!empty($row) && $key != 'submit') {
foreach($row as $keyer => $rower)
{
$messages[$key][] = $rower;
}
}
}
if (!empty($messages)){
$response->setContent(\Zend\Json\Json::encode($messages));
}
return $response;
Here's is a good post on how to use Zend\Form with Ajax validation.

How to display confirm box before submitting an AJAX form in Drupal 7?

Using Drupal 7 form API, How can I prompt javascript confirm box before submitting an AJAX form? I have tried different possible ways to do this but no success. Here is the code:
function create_list_form($form, &$form_state) {
$form['list_name'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => 'List Name'
'#attributes' => array()
);
$form['list_desc'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => 'List Desc'
'#attributes' => array()
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#attributes' => array('class' => array('use-ajax-submit')),
'#value' => 'Create List'
);
return $form;
}
Here is the Javascript code:
Drupal.behaviors.module = {
attach: function() {
jQuery('#edit-submit').click(function(){
if(!confirm('Are you sure?'))
return false;
});
}
}
I have found the solution. We can do it by overriding beforeSerialize() function:
Drupal.behaviors.module = {
attach: function() {
Drupal.ajax['edit-submit'].beforeSerialize = function () {
if(confirm('Are you sure?'))
return true;
else
return false;
}
}
}
Did you try to add an eventlistener on your button?
function show_confirmation() {
if (confirm("Do you want to submit?")){
// here you can do something before it gets submitted
} else {
// return false prevents the form from submitting
return false;
}
}
var button = document.getElementById('button_name');
button.addEventListener('click', show_confirmation);
Edit: You can use this one if you want to make your function re-usable:
function your_callback_func() {
// This could be any code for example your AJAX code etc
}
function show_confirmation(your_callback_func) {
if (confirm("Do you want to submit?")){
your_callback_func()
} else {
// return false prevents the form from submitting
return false;
}
}
var button = $('#button_name');
button.click(function() {
show_confirmation(your_callback_func);
});

Categories