Prevent InvalidArgumentException on dynamic form field creation - javascript

I'm following Symfony cookbook on dynamic form fields creation.
Basically, in my case, I have a Product, a ProductVersion and a Quantity field in my form.
On new forms, ProductVersion is hidden (only with a class attribute, It's still an EntityType).
On Product change (via select menu), I make an AJAX request to see if some ProductVersion exists for this product. If so, I populate the ProductVersion with available versions and show it to the user.
It's working fine with new forms. But when editing the same form, I have an InvalidArgumentException response on my AJAX request that tells me that the Quantity field is null :
Expected argument of type "int", "null" given at property path
"quantity".
I understand that indeed, I don't provide the quantity on my form submission through the AJAX request but that's the purpose of this method isn't it ? To only submit the field that makes a dynamic field change.
How can I do to avoid this Exception ?
Here is the ItemType :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', EntityType::class, [
'label' => 'item.product',
'class' => Product::class,
'placeholder' => 'item.product',
]);
$formModifier = function (FormInterface $form, Product $product = null) {
if (null !== $product) {
$productVersions = $product->getVersions();
if (count($productVersions) > 0) {
$form->add('productVersion', EntityType::class, [
'class' => 'App\Entity\ProductVersion',
'placeholder' => 'item.product_version',
'choices' => $productVersions,
'label' => 'item.product_version'
]);
} else {
$form->add('productVersion', EntityType::class, [
'class' => 'App\Entity\ProductVersion',
'placeholder' => 'item.product_version',
'choices' => [],
'label' => 'item.product_version',
'disabled' => true,
'row_attr' => [
//'class' => 'd-none'
]
]);
}
} else {
$form->add('productVersion', EntityType::class, [
'class' => 'App\Entity\ProductVersion',
'placeholder' => 'item.product_version',
'choices' => [],
'label' => 'item.product_version',
'disabled' => true,
'row_attr' => [
//'class' => 'd-none'
]
]);
}
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$form = $event->getForm();
$data = $event->getData();
$options = $event->getForm()->getConfig()->getOptions();
//add custom product version according product selected
$formModifier($event->getForm(), $data->getProduct());
$form
->add('quantity', IntegerType::class, [
'label' => 'item.quantity',
]);
if ($data->getId()) {
$form
->add('save', SubmitType::class, [
'label' => $options['submit_btn_label'],
]);
} else {
$form
->add('save', SubmitType::class, [
'label' => $options['submit_btn_label'],
]);
}
}
);
$builder->get('product')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$product = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $product);
}
);
}
And here is the Javascript part :
$(document).ready(function () {
var $product = $('#item_product');
// When product gets selected ...
$product.on('change', function () {
console.log("product has changed")
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected product value.
var data = {};
data[$product.attr('name')] = $product.val();
// Submit data via AJAX to the form's action path.
console.log(data);
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) {
// Replace current position field ...
$('#item_productVersion').closest('.form-group').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#item_productVersion').closest('.form-group')
);
// Position field now displays the appropriate positions.
}
});
});
})

As #Jakumi suggested, adding an empty_data option to the quantity field solved the problem. Nevertheless, It gives an error on the quantity on the form received via the AJAX request and that's normal.
I found that this is not a "clean" method (you have to tweak form fields, you load the entire page on each AJAX request, etc..) so I decided to create a special route dedicated to form submissions that are meant to add/remove/edit fields.
This route creates a new form with preset fields (in my case the product selected by the user).
Then I can populate the other field (in my case the 'ProductVersion') with a regular PRE_SET_DATA Form Event.
This way :
- I don't have to worry about any other required field
- I can serialize the entire form in my AJAX request (no need to find the field, everything is done in the form builder)
- The AJAX request only output the form (I guess this improves performance a bit)
The form builder doesn't change (you still need to listen to PRE_SET_DATA and POST_SUBMIT. If you don't listen to the POST_SUBMIT, the form will not know about the choices you added dynamically and It will give you an error).
Here is the JS part :
$product.on('change', function() {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// serialize the entire form
var data = $form.serializeArray();
// Submit data via AJAX to the form's action path.
console.log(data);
$.ajax({
url : '/project/item/partial-edit', //custom route
type: $form.attr('method'),
data : data,
success: function(html) {
// Replace current position field ...
$('#item_productVersion').closest('.form-group').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#item_productVersion').closest('.form-group')
);
}
});
});
Here is the special route :
/**
* #Route("/item/partial-edit", name="edit_item_partial", requirements={"project"="\d+","item"="\d+"})
*/
public function edit_item_partial(Request $request)
{
$item = new Item();
$formOption = $request->get('option') ?? array(
'submit_btn_label' => 'update'
);
$form = $this->createForm(ItemType::class, $item, $formOption);
$form->handleRequest($request);
if ($form->isSubmitted()){
//if form was submitted, create a new form with the $item that has now a Product given
$newForm = $this->createForm(ItemType::class, $item, $formOption);
//here is the custom view only rendering the form
return $this->render('item/new_form-only.html.twig', [
'form' => $newForm->createView(),
]);
}
else {
return new Response('No form was submitted');
}
}

Related

How to submit multiple forms in laravel?

I have a simple form which contains a button to open another form in a pop up modal, the form looks like this
Now as you can see above prebids input plus button, when the user clicks the plus button it opens the modal which contains a form like this below.
Now I want to submit the forms in the following an order
First submit: base form (norma way)
Second submit: form inside a pop up (via ajax)
Here is my store function to submit the forms in a page controller
public function store(Request $request)
{
$page = Page::create([
'title' => $request->get('title'),
'articles' => $request->get('articles'),
'status' => $request->get('status'),
]);
// dd($request);
$page->save();
$bidder = Bidder::create('page_id' -> $page->id);
// save bidders informtion to the database using ajax
if($request->ajax())
{
$rules = array(
'params_name.*' => 'required',
'params_value.*' => 'required',
'bidders_name.*' => 'required',
);
$error = Validator::make($request->all(), $rules);
if($error->fails())
{
return response()->json([
'error' => $error->errors()->all()
]);
}
$params_name = $request->params_name;
$params_value =$request->params_value;
$bidders_name =$request->bidders_name;
for($count = 0; $count < count($params_name); $count++)
{
$data = array(
'params_name' => $params_name[$count],
'params_value' => $params_value[$count],
'bidders_name' => $bidders_name[$count],
);
$insert_data[] = $data;
}
bidder_parameters::insert($insert_data);
return response()->json([
'success' => 'Data Added successfully.'
]);
}
return redirect("/pages")->with("sucess", "data saved");
}
And here is ajax for submitting form inside a pop up
$("#paramsForms").on('submit', function(e) {
e.preventDefault();
$.ajax({
url: '/pages',
type: "POST",
data: $(this).serialize(),
dataType: 'json',
beforeSend:function() {
$("#save").attr('disabled', 'disabled');
},
success:function (data) {
console.log(data);
alert('Data successfull saved');
},
error:function (error) {
console.log(error)
console.log('Data not saved');
}
})
})
Now when I click submit I get the following error
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'title' cannot be null (SQL: insert into `pages` (`title`, `articles`, `status`, `updated_at`, `created_at`) values (?, ?, ?, 2019-11-06 11:29:31, 2019-11-06 11:29:31))"
Note: checking dd($request) for both forms in a store function, I get the following
+request: ParameterBag {#44
#parameters: array:4 [
"_token" => "Wgozk9jnyUnJkL35vPhso9sUr7lbMD8cSgMVuN2s"
"bidders_name" => array:1 [
0 => "Biden"
]
"params_name" => array:1 [
0 => "democratic"
]
"params_value" => array:1 [
0 => "10"
]
]
}
Note: The problem is when I click submit on pop modal it try to send the base form at first
What do I need to change to get what I want?
Note: The problem is when I click submit on pop modal it try to send the base form at first
It means laravel is treating your both form as one and when u try to submit the pop up form it submited the base form. Please make sure you both form are separated.
There might possible that u have not close one of the form tag and the save changes button of pop up form is acting as the base form submit button.

How to send multiple parameters in ajax call using post request in Yii2

I have a view in which I have a detailview and a gridview. In my grid view there are check-boxes against all the columns. The detail view contains the model id. Now the case is simple, I want to select any column from the grid view and then on click of the a link button I want to send the ajax call, which includes the value of selected column and the model id, to my controller. Below is my view
<?= GridView::widget([
'dataProvider' => $dataProvider,
/*'filterModel' => $searchModel,*/
'columns' => [
['class' => 'yii\grid\CheckboxColumn', 'checkboxOptions' => function($d) {
return ['value' => $d['meter_id']];
}],
'Meter_Serial_Number',
'Issued_To',
'Store',
],
]); ?>
Set PDF
Now the javascript and the ajax call
<?php
$url = Url::toRoute(['/ogpheader/viewsetpdf','id'=>$model->id]);
$script = <<< JS
$(document).ready(function () {
$('#myid').on('click',function() {
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!="")
{
strValue = strValue + " , " + this.value;
}
else
strValue = this.value;
});
// alert(strValue);
$.ajax({
url: '$url',
type: 'POST',
data: {
data: strValue,// also tired with {strValue:strValue id:id} but it did not worked for me as well
},
success: function(data) {
alert(data);
},
});
})
});
JS;
$this->registerJs($script, static::POS_END);
?>
Action Controller
public function actionViewsetpdf($id)
{
$model = $this->findModel($id);
print_r($_POST);
$data = "";
if(Yii::$app->request->isAjax)
{
$data = json_decode($_POST['data']);
print_r($data);
}
else{
echo 'no data';
}
exit();
}
The response i always got is Array ( ) no data. I have also looked into Passing two parameters in yii2 ajax request using jquery to a controller and Yii2 extra parameter ajax in controller but both seems to be helpful in my case.
Note:
As per my understanding the id is a get and strValue is post. So I am confused in both of them. May be I am wrong.
Update 1
Image quality is not that good
The response in Xhr is
array(1) {
["data"]=>
array(1) {
["data"]=>
string(26) "99 , 100 , 101 , 102 , 103"
}
}
Any help would be highly appreciated.
Prevent the default click event
$('#myid').on('click',function(e) {
e.preventDefault();

TYPO3 ajax The default controller for extension and plugin can not be determined

I have TYPO3 7.6.18 and I trying ajax on front end and I get error 'The default controller for extension \"fefiles\" and plugin \"piphoto\" can not be determined'.
setup.txt
ajaxCall = PAGE
ajaxCall {
typeNum = 22222
config {
disableAllHeaderCode = 1
xhtml_cleaning = 0
admPanel = 0
additionalHeaders = Content-type: text/plain
no_cache = 1
debug = 0
}
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = fefiles
pluginName = Piphoto
vendorName = Istar
controller = Photo
action = ajaxHandler
}
}
ext_tables.php
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
$_EXTKEY,
'Piphoto',
'Upload Photo'
);
js
jQuery(function($) {
$(".send-photo-comment").click(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: "?id=0&type=22222",
data: {},
success: function(msg){
console.log(msg);
}
});
})
})
ext_localconf
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Istar.' . $_EXTKEY,
'Piphoto',
[
'Photo' => 'list, ajaxHandler, show, new, create, edit, update, delete',
],
// non-cacheable actions
[
'Photo' => 'list, ajaxHandler, show, new, create, edit, update, delete',
]
);
Help me please)
How does your ext_localconf.php look like?
Should include something like:
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Istar.' . $_EXTKEY,
'Piphoto,
array(
'Photo' => 'ajaxhandler'
)
);
This basically means that you need to define a controller in your ext_localconf.php. Usually the first entry is taken as default controller/action. Here's an example:
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'YourVendor.' . $_EXTKEY,
// Plugin name
'Pi1',
// An array of controller-action combinations. The first one found is the default one.
array(
'YourController' => 'index,new,create,edit,update'
),
// An array of non-cachable controller-action-combinations (they must already be enabled)
array(
'YourController' => 'new,create,edit,update'
)
);

want to select user from onchange of dropdown list of department in cakephp?

i have two tables user and department where department has two fields id and name i want to create a view so that when someone selects a department name from the dropdownlist the user's name of all in that department show in another dropdownlist using AJAX and How to call that in controller
<script>
jQuery(document).ready(function ($) {
//jQuery('#searchTable').dataTable();
$('#department_id').change(function () {
jQuery('#user').empty();
var data2 = {};
data2['department_id'] = jQuery(this).val();
var json = JSON.stringify(data2);
jQuery.ajax({
type: "POST",
url: "/AjaxRequests/name",
data: json,
dataType: "json",
success: function (response) {
var app = "<option value>All</option>";
jQuery('#user').append(app);
jQuery.each(response, function (i, text) {
jQuery('#user').append(jQuery('<option></option>').val(i).html(text));
});
}
});
});
</script>
this is the script i am using
and in view the department dropdown is like this
<?php echo $this->Form->input('department_id', array('onChange' => 'showFields(this.value)', 'class' => 'form-control-custom', 'id' => 'department_id', 'type' => 'select', 'label' => true, 'label' => 'department:', 'options' => $departments, 'empty' => 'Select A Department', 'required' => 'false'))
?>
Anyone please help me with this ajax and also the controller
According to your code, can u try to replace 'id' => 'department' with 'id' => 'department_id' . Cause it's seen here you are using department_id as selector but your department_id id as not declared in dropdownlist. Here you declared department as ID. So selector is not found. So Just replace 'id' => 'department' with ''id' => 'department_id'', Hope it can be helpful to you.

Zend 1.12 + Ajax - Submit form

After user clicks on submit form, I need to call Zend validation of that form without refreshing whole page. I also use zend_Layout in my website. I have seen a lot of tutorials here, but still cant make it working.
Index Controller:
class IndexController extends Zend_Controller_Action {
public function init() {
}
public function indexAction() {
$this->view->static_data = "eg. ABCDEFG";
$this->view->form = new Application_Form_Test();
}
public function ajaxAction() {
// probably some code to hande ajax
}
}
View for index/index:
...
<?php
echo date('m/d/Y h:i:s a', time());
echo $this->static_data;
?>
<hr />
<?php echo $this->form ?>
...
Form:
class Application_Form_Test extends Zend_Form
{
public function init()
{
$this->setMethod('post');
$this->setAttrib('class', 'form1');
$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));
$this->addElement('text', 'name', array(
'label' => 'Your name:',
'required' => true,
'validators' => array(
array('validator' => 'StringLength', 'options' => array(3, 20))
)
));
// Add the submit button
$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Send',
));
// And finally add some CSRF protection
$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
}
So how can i validate form without refreshing rest of that page and see Zend Error Messages in case that form is not valid.
You can post the form to your Ajax action where you will instantiate the form and inject data from the request.
$form = new Form();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())) {
//save data
....
}
}
$this->view->form = $form;
You have two options:
Render the form in the view and respond with HTML. Using JavaScript replace current form with HTML returned by the Ajax request.
Get error messages using Zend_Form::getMessages() and respond with JSON.
$this-view->messages = $form->getMessages();

Categories