I creating a text box dynamically (based on user selection)using jquery ..is there any way to provide validation for that text box from zend form..?
Yes there is.
most credits go to jeremy kendall see http://www.jeremykendall.net/2009/01/19/dynamically-adding-elements-to-zend-form/
The way i solved it is by doing a jquery/ajax call to a action which adds get a form element something like:
$.ajax({
type : "POST",
url : "/<controller>/addfield/",
success : function(newElements) {
// Insert new element before the submit button
$("#productsNew-submit-element").before(newElements);
}
});
What this does is it call a action that generates a form element and returns the html which you can then add
public function addfieldAction()
{
//use $ajaxContext = $this->_helper->getHelper('AjaxContext'); in the init to make it return html via ajax
$element = new Zend_Form_Element_Text("extraElement_1");
$element->setBelongsTo("yourForm");
$element->setLabel('myElementName');
/*
set other stuff like decorators or so
*/
//now create the html
$elements .= $element->__toString();
$this->view->fields = $elements;
}
After that you will get a new element in your form via ajax
Now when you submit you have to do that again but then pre validation
first check if your form has extraElements if so add them again
fill the add element with the posted value
validate
public function saveAction()
{
function findFields($field) {
// return field names that include 'extraElement_'
if (strpos($field, 'extraElement_') !== false) {
return $field;
}
}
//set all stuff you need especially the form
if($this->getRequest()->isPost()) {
$postValues = $this->getRequest()->getPost();
//step 1
$extraFields = array_filter(array_keys(current($postValues)), 'findFields');
//add the element before validation
if(count($extraFields) !== 0) {
foreach(extraFields as $extraField) {
$this->addFields($postValues[$extraField]); <-- step 2 add the field(s)
}
}
//step 3 validate
if($this->_form->isValid($postValues)) {
//do post validation stuff
} else {
//show errors
}
}
}
Related
I have an editing node form. When user enters new value and clicks on submit to edit the node, I first want to get the old node back, manipulate the value and then just save/update the node.
Below is my solution, but it does not work.
function custom_module_form_node_form_alter(&$form, FormStateInterface $form_state) {
$editing_entity = $form_state->getFormObject()->getEntity();
if (!$editing_entity->isNew()) {
$form['actions']['submit']['#submit'][] = 'custom_module_node_form_submit';
}
}
function custom_module_node_form_submit($form, FormStateInterface $form_state) {
$editing_entity = $form_state->getFormObject()->getEntity();
$entity = Drupal::entityTypeManager()->getStorage('node')->load($editing_entity->id());
}
In the form_submit hook, I tried to get the old node back but it is already too late and the node is already updated/saved. How can I get the old node back and manipulate the value before updating/saving the node in Drupal 8?
Try using hook_entity_presave():
/**
* Implements hook_entity_presave().
*/
function YOUR_MODULE_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
switch ($entity->bundle()) {
// Here you modify only your day content type
case 'day':
// Setting the title with the value of field_date.
$entity->setTitle($entity->get('field_date')->value);
break;
}
}
Solution taken from here: https://drupal.stackexchange.com/questions/194456/how-to-use-presave-hook-to-save-a-field-value-as-node-title
Also you can get old value like: $entity->original. Check it out here:
https://drupal.stackexchange.com/questions/219559/how-to-get-the-original-entity-on-hook-entity-presave
I decide to manipulate the values in the form validate hook as following.
function custom_module_form_node_form_alter(&$form, FormStateInterface $form_state) {
$editing_entity = $form_state->getFormObject()->getEntity();
if (!$editing_entity->isNew()) {
$form['#validate'][] = 'custom_module_node_form_validate';
}
}
function custom_module_node_form_validate(array &$form, FormStateInterface $form_state) {
$old_entity = $form_state->getFormObject()->getEntity();
$old_values = $old_entity->get('field_name')->getValue()
$new_values = $form_state->getValue('field_name');
// Manipulate and store desired values to be save here.
$to_save_value = ['a', 'b', 'c'];
$form_state->setValue('field_name', $to_save_value);
}
Use hook_ENTITY_TYPE_presave, like so:
function yourmodulename_node_presave(Drupal\node\NodeInterface $entity) {
if ($entity->getType() == 'your_content_type') {
$entity->setTitle('Hello');
$entity->set('body', 'this is body');
}
}
This is the best solution, because with hook_form_alter like MilanG you will be changing the value only when the node is saved from the particular form you are altering! If the node is saved programmatically from within the code or by some other method your hook_form_alter will not kick in.
I've create a form like:
function create_custom_form($form, &$form_state) {
$form['#action'] = "#";
....
}
function create_custom_form_validate($form, &$form_state) {
....
}
function create_custom_form_submit($form, &$form_state) {
....
if(..)
drupal_goto('abc');
else
drupal_goto('xxx');
}
when i submit this form drupal before go to action and after read my function... how I can bypass the action-form and read only a _submit function?
Do not use drupal_goto as there may be more "submit" callbacks to execute. The drupal_goto function will interrupt these.
Instead, use the $form_state['redirect'] = ...
http://api.drupal.org/api/drupal/includes!form.inc/function/drupal_redirect_form/7
function create_custom_form_submit($form, &$form_state) {
....
if(..)
$form_state['redirect'] = 'abc';
else
$form_state['redirect'] = 'xxx';
}
As this function has the same form ID (create_custom_form) - with the word "_submit" appended then this function will be executed automatically and so there is no need to add any submit callbacks into the form.
If you want an additional function to execute on submit then you should do as Hamza has suggested, only your additional function will have a different name. e.g.
function create_custom_form($form, &$form_state) {
$form['#action'] = "#";
....
// Add any additional callbacks to call before any redirects happen
$form['#submit'][] = 'create_custom_form_additional_submit_callback';
$form['#submit'][] = ...
}
function create_custom_form_additional_submit_callback($form, &$form_state) {
// Do something before redirect
...
}
In the above example:
create_custom_form_additional_submit_callback
AND
create_custom_form_submit (because its got the same name with '_submit' appended)
will execute and only when they have both finished will the redirect be executed.
I want to disable certain validators if another field in the form is not checked. Example:
$fe = new FormElement(FormElement::FIELD_checkBox, 'alternative_billing_address', $this);
$fe->setLabel(Yii::t('checkout','Pick a different billing address'));
$this->addElement($fe);
$fe = new FormElement(FormElement::FIELD_textField, 'billing_first_name', $this);
$fe->setLabel(Yii::t('checkout','First name'))->addValidator('required');
$this->addElement($fe);
In this case, I want to disable the validator of the second form element if the first element (checkbox) has not been checked.
Unfortunately this does not work together with the Javascript-Yii-ActiveForm feature, which prevents the submission of the form because it says that the text field must be filled out.
Is there any possibility to solve this without disabling the client validation? Thanks!
I found this question and I had the same issue, so I thought I would post my solution.
I needed to disable clientSide validation on specific fields when a checkbox was checked/unchecked using Yii.
Note my solution uses the $form CActiveForm widget.
So the form code:
<?php
$form=$this->beginWidget('CActiveForm', array(
'id'=>'my-form',
'enableAjaxValidation'=>false,
));
?>
<input type="checkbox" name="YourCheckbox" id="Your-Checkbox" value="1" />
<?php
echo $form->labelEx($yourModel,'FirstName');
echo $form->textField($yourModel,'FirstName');
echo $form->error($yourModel,'FirstName');
echo $form->labelEx($yourModel,'LastName');
echo $form->textField($yourModel,'LastName');
echo $form->error($yourModel,'LastName');
?>
Now we display the javascript functions which will disable the validation for each field you specify:
function enableFieldsValidation(form, model, fieldName) {
// Restore validation for model attributes
$.each(form.data('settings').attributes, function (i, attribute) {
if (attribute.model == model && attribute.id == (model + '_' + fieldName))
{
if (attribute.hasOwnProperty('disabledClientValidation')) {
// Restore validation function
attribute.clientValidation = attribute.disabledClientValidation;
delete attribute.disabledClientValidation;
// Restore sucess css class
attribute.successCssClass = attribute.disabledSuccessCssClass;
delete attribute.disabledSuccessCssClass;
}
}
});
}
function disableFieldsValidation(form, model, fieldName) {
$.each(form.data('settings').attributes, function (i, attribute) {
if (attribute.model == model && attribute.id == (model + '_' + fieldName))
{
if (!attribute.hasOwnProperty('disabledClientValidation')) {
// Remove validation function
attribute.disabledClientValidation = attribute.clientValidation;
delete attribute.clientValidation;
// Reset style of elements
$.fn.yiiactiveform.getInputContainer(attribute, form).removeClass(
attribute.validatingCssClass + ' ' +
attribute.errorCssClass + ' ' +
attribute.successCssClass
);
// Reset validation status
attribute.status = 2;
// Hide error messages
form.find('#' + attribute.errorID).toggle(false);
// Dont make it 'green' when validation is called
attribute.disabledSuccessCssClass = attribute.successCssClass;
attribute.successCssClass = '';
}
}
});
}
Once you have these functions in your JS file you can use jQuery to check if the checkbox has been checked. If it has been checked it will enable validation and if not it will disable it.
$('#YourCheckbox').click(function() {
if ($(this).is(':checked'))
{
enableFieldsValidation($('#my-form'), 'YourModel', 'FirstName');
//enableFieldsValidation($('#my-form'), 'YourModel', 'LastName');
}
else
{
disableFieldsValidation($('#my-form'), 'YourModel', 'FirstName');
//disableFieldsValidation($('#my-form'), 'YourModel', 'LastName');
}
});
I have following action to display a form
public function showformAction() {
$this->view->form = new Form_MyForm();
$this->view->form->setAction( 'submitform' );
}
above action shows a form successfully with only one textarea and submit button.
And I am using following action to submit above form:
public function submitformAction() {
$form = new Form_MyForm();
$request = $this->getRequest();
if ( $request->isPost() ) {
$values = $form->getValues();
print_r($values);die();
} else {
echo 'Invalid Form';
}
}
Above action is showing following output:
Array ( [myfield] => )
It means it is not posting values correctly and always shows empty array or I am not getting posted values correctly. How to post values to submitformAction().
Thanks
I think you must use the isValid() before accessing the values of a submitted form, because it's right there that the values are checked and valorized
public function submitformAction() {
$form = new Form_MyForm();
$request = $this->getRequest();
if ( $request->isPost() ) {
if ($form->isValid( $request->getPost() )) {
$values = $form->getValues();
print_r($values);die();
}
} else {
echo 'Invalid Form';
}
}
In complement to #VAShhh response. With some more details:
You need to do two things, populate your form fields with the POSTed data and applying security filters and validators to that data. Zend_Form provides one simple function which perform both, it's isValid($data).
So you should:
build your form
test you are in a POST request
populate & filter & validate this data
either handle the fact in can be invalid and re-show the form wich is now
decorated with Errors OR retrieve valid data from the form
So you should get:
function submitformAction() {
$form = new Form_MyForm();
$request = $this->getRequest();
if ( $request->isPost() ) {
if (!$form->isValid($request->getPost())) {
$this->view->form = $form;
// here maybe you could connect to the same view script as your first action
// another solution is to use only one action for showform & submitform actions
// and detect the fact it's not a post to do the showform part
} else {
// values are secure if filters are on each form element
// and they are valid if all validators are set
$securizedvalues = $form->getValues();
// temporary debug
print_r($securizedvalues);die();
// here the nice thing to do at the end, after the job is quite
// certainly a REDIRECT with a code 303 (Redirect after POSt)
$redirector = $this->_helper->getHelper('Redirector');
$redirector->setCode(303)
->setExit(true)
->setGotoSimple('newaction','acontroller','amodule');
$redirector->redirectAndExit();
} else {
throw new Zend_Exception('Invalid Method');
}
}
And as said in the code re-showing the form you shoudl really try to use the same function for both showing and handling POST as a lot of steps are really the same:
building the form
showing it in the view in case of errors
By detecting the request is a POST you can detect you are in the POST handling case.
Javascript needed to prevent form submit if any of field is empty. all my form fields start names start with name=add[FieldName] those are the fields that need checking.
PHP, backend check before submiting to database double check to make sure all $POST are not empty
Here's a javascript function you can use. Just call it for each id belonging to the fields in question.
function isEmpty(field_id) {
var empty = false;
if (document.getElementById(field_id).value == null)
empty = true;
if (document.getElementById(field_id).value == "")
empty = true;
return empty;
}
If you have them predictably named, you could call this function in a loop. If, for instance, they were named field1, field2, ..., field23, then you could just have the following in your main code body:
for (i = 0; i < 24; i++) {
var emptyCheck = false;
if(isEmpty("field"+i)) {
emptyCheck = true;
//do whatever you want to do when a value is empty
}
}
I'm not going to write the javascript, but here's some PHP.
$valid = true;
foreach($_POST as $key)
{
if(!isset($key))
{
$valid = false;
}
}
if(!$valid)
{
header("Location: /path/to/form");
}