I'm working on a zend framework project and I needed the user to select school and then it goes to the next form then select the grade.
Eg User select ABC High School and then select "Grade 8"
Both School and Grade dropdown menu is soft coded fetching the data from the database.
My problem is that when the user selected a school and then on the next grade form if they don't select any values and click onto "submit" it return a validation error "Value is required and can't be empty" which is correct but the dropdown menu then goes empty.
I wanted to know how to repopulate the values back to the grade dropdown menu if the form doesn't validate.
Thanks so much
Here is my code
Here is the function i generate the grade values (Fetching from the database)
public function processSchoolSelectionAction()
{
$form = $this->getSchoolSelectionForm();
if ($form->isValid($_POST))
{
// getting the values
$schoolId = $form->getValue('school');
$schoolYear = new Application_Model_DbTable_SchoolYear();
$schoolYearValues = $schoolYear->getYearValues($schoolId);
array_unshift($schoolYearValues, array ('key' =>'' , 'value' =>'Please Specify'));
$form = $this->getYearSelectionForm();
$form->year->addMultiOptions($schoolYearValues);
$form->schoolId->setValue($schoolId);
$this->view->form = $form;
}
else
{
$data = $form->getValues();
$form->populate($data);
$this->view->form = $form;
}
}
Code processing the year selection form
public function processYearSelectionAction()
{
$form = $this->getYearSelectionForm();
if ($form->isValid($_POST))
{
// getting the values
$schoolId = $form->getValue('schoolId');
$yearId = $form->getValue('year');
$textbookList = new Application_Model_DbTable_TextbookList();
if ($textbookList->checkTextbookExist($schoolId, $yearId))
{ // check if textbookExist
}
else
{
$this->view->message = "Sorry, But the list you requested is currently not available for ordering online.";
}
}
else
{
$data = $form->getValues();
$form->populate($data);
$this->view->form = $form;
}
}
School selection form
<?php
class Application_Form_SchoolSelection extends ZendX_JQuery_Form
{
public function init()
{
$this->setName('schoolSelection');
$school = new Application_Model_DbTable_School;
$schoolValues = $school->getSchoolValues();
array_unshift($schoolValues, array ('key' =>'' , 'value' =>'Please Specify'));
$schoolElement = new Zend_Form_Element_Select('school');
$schoolElement->addMultiOptions($schoolValues);
$schoolElement->setLabel('School');
$schoolElement->setRequired(true);
$schoolElement->setRegisterInArrayValidator(false);
$submitElement = new Zend_Form_Element_Submit('submit');
$submitElement->setLabel("Next");
$this->addElements(array(
$schoolElement,
$submitElement
));
}
}
?>
Grade (Year) selection form
<?php
class Application_Form_YearSelection extends ZendX_JQuery_Form
{
public function init()
{
$this->setName('yearSelection');
$yearElement = new Zend_Form_Element_Select('year');
$yearElement->setLabel('Year');
$yearElement->setRequired(true);
$yearElement->setRegisterInArrayValidator(false);
$schoolIdElement = new Zend_Form_Element_Hidden('schoolId');
$submitElement = new Zend_Form_Element_Submit('submit');
$submitElement->setLabel("Next");
$this->addElements(array(
$yearElement,
$schoolIdElement,
$submitElement
));
}
}
?>
This is how I done that:
In Controller when form is creating, pass data from request:
$some_selected_data = $this->_getParam('param_from_request'); // you need to validate this
$form = new Application_Form_SchoolSelection( array('some_data' => $some_selected_data) );
Then, in Form Class get that value like this:
$data = $this->getAttrib('some_data'); // the key value of array above
and just ask
if($data) {
// get value from DB and
//SET VALUE TO Zend_Form_Element
}
Obviously, you need to repopulate the options of your Select field.
In your processYearSelectionAction, on the validation failure part just grab the schoolId you stored in the hidden field and use it the same way as you did in your processSchoolSelectionAction to populate your field options.
Related
I have created a custom module in Magento 2. In which i want to show some banners, Countdown timer and extra details on product page, also label or text on category page. for this i extended the catalog sales rule module. Added some extra field according to my requirements. Now i want to show get all those products ids on which sale rule has applied with all other details like Top Banner, Countdown timer according to sale etc.
my Block Code is
<?php
namespace Custom\Sales\Block;
class Flash extends \Magento\Framework\View\Element\Template
{
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\CatalogRule\Model\ResourceModel\Rule\CollectionFactory $ruleFactory,
array $data = []
) {
$this->_ruleFactory = $ruleFactory;
parent::__construct($context, $data);
}
public function getCatalogeRuleId()
{
$catalogRuleCollection = $this->_ruleFactory->create()
->addFieldToFilter('is_active',1);
// return $catalogRuleCollection;
$resultProductIds = [];
foreach ($catalogRuleCollection as $catalogRule) {
$productIdsAccToRule = $catalogRule->getMatchingProductIds();
// echo json_encode($productIdsAccToRule); exit;
$websiteId = $this->_storeManager->getStore()->getWebsiteId();
foreach ($productIdsAccToRule as $productId => $ruleProductArray) {
if (!empty($ruleProductArray[$websiteId])) {
$resultProductIds[$productId] = $catalogRule->getData();
}
}
return $resultProductIds;
}
}
}
Now when i print my array i get only one sale rule data , however i have created 3 different sales
Hi im new with zend and this question probably be ridiculous but i have a trouble getting values from the following:
$country = new Zend_Form_Element_Select('_country');
$country->setLabel('Country:');
$country->addMultiOptions(array('0'=>'United States',
'1'=>'Bolivia',
'2'=>'Argentina',
'3'=>'Afganistan'));
$country->setRequired(true);
But im not sure how i can get the values, i tried like this on my controller:
if ($this->_request->getPost()) {
$formData = $this->_request->getPost();
$form = new App_Form_CustomerForm();
if ($form->isValid($formData)) {
$customer = $customerDao->getById($id);
$customer->setCountry($formData[0]['_country']);
$customerDao->save($customer);
$this->_helper->redirector('index');
return;
Im thinking of use only html code to do this select but i want to know how get these values .
you can get the values from zend element using the getValue() method
Populating and Retrieving Values
The code would be
if ($form->isValid($formData)) {
$customer = $customerDao->getById($id);
$customer->setCountry($form->getValue('_country'));
$customerDao->save($customer);
$this->_helper->redirector('index');
return;
}
I'm a bit lost using Zend_Form with Ajax. I have a form in a class extending Zend_Form called from my controller, that way :
GoodAddGroup.php
class Default_Form_GoodAddGroup extends Zend_Form {
(...)
public function init()
{
$this->setMethod('post');
$this->setAction("process-add-group");
$this->setName("addgroupgood");
// Load Elements class
require "Form/Elements.php";
$magElements = new Elements();
// Category
$categoryElement = $magElements->getCategorySelectField();
$categoryElement->setDecorators($this->elementDecorators);
// Barcode
$barcodeElement = $magElements->getGoodBarcodeTextField();
$barcodeElement->setDecorators($this->elementDecorators);
(...)
// Add elements to the form
$this->addElements(array(
$categoryElement,
//$codeElement,
$barcodeElement,
$serialElement,
$warehouseElement,
$submitButtonElement
));
$this->setDecorators($this->formDecorators);
}
}
In GoodsController.php
private function getAddGroupForm()
{
return new Default_Form_GoodAddGroup();
}
public function addGroupAction()
{
// Initialize the form for the view.
$this->view->form = $this->getAddGroupForm();
}
public function processAddGroupAction()
{
$form = $this->getAddGroupForm();
(...)
if ($_POST)
{
if ($form->isValid($_POST))
{
// Do things
} else {
$this->view->form = $form;
}
}
}
Basically, the form has a category select field, when selecting a category, a second "code" selector is added filled with the items related to this category. When the page with the form is displayed (http://myapp/goods/add-group), everything works fine, the ajax call does its job, the second select field is added and well fed, but as you can see, the form processing is done with the processAddGroupAction(), this method get the instance of the form to get its values and to re-display it in case of problem. But that way, my "new" select field doesn't exist anymore, so i can never validate the form.
It's my first attempt using ajax/json with Zend, i think i need help at this poind.
Thank you.
EDIT : added the view code as requested
<script>
$(function(){
$("#cats").change(function(){
getSelectBox(this);
});
$("#code").parent().parent().css('display', 'none');
getSelectBox($("#cats"));
});
function getSelectBox(element)
{
if($(element).val() != '')
{
$("#code").parent().parent().css('display', 'block');
if ($('#code').length <= 0) {
$("#cats").after('<select name="code" id="code" style="margin-left:10px"></select>');
}
$.getJSON("/goods/json-get-codes-from-category", {id: $(element).val(), ajax: "true"}, function(j){
console.log(j);
var options = "";
jQuery.each(j, function(i, val) {
options += '<option value="' + i + '">' + i + val + '</option>';
});
$("#code").html(options);
});
}
}
</script>
<?php echo $this->form; ?>
You can add the select element 'code' in the form, but don't display it in the view (it will be created from the js). So when the form is posted the 'code' will also be validated since it is in the $_POST.
After post you have to display the select box without $("#cats").change({..}). You can accomplish it by spiting the js code into functions
<script>
$(function(){
$("#cats").change(function(){
getSelectBox(this);
});
getSelectBox($("#cats"));
});
function getSelectBox(element)
{
if($(element).val() != '')
{
if ($('#code').length <= 0) {
$("#cats").after('<select name="code" id="code" style="margin-left:10px"></select>');
}
$.getJSON("/goods/json-get-codes-from-category", {id: $(element).val(), ajax: "true"}, function(j){
console.log(j);
var options = "";
jQuery.each(j, function(i, val) {
options += '<option value="' + i + '">' + i + val + '</option>';
});
$("#code").html(options);
});
}
}
</script>
Hope this helps
Ok, i found the solution! I post it in case it can be useful for other people.
I knew what was the problem, but unable to know how to achieve it.
At form processing time, the new select element does not exist for the action as it has been added in the view with javascript. To fix this, we need to inform the action about the new field, to do so, we first need to override the method “isValid” of Zend_Form in the form class :
public function isValid($values)
{
$values = $this->_modifyElements($values);
return parent::isValid($values);
}
Then create a method "_modifyElements" that will modify the form by adding the new element :
protected function _modifyElements($values)
{
// Search for codes
$dbu = new DbUtils();
$codes = $dbu->getCodesFromCategory($values['cats']);
// Remove the current code element
$this->removeElement('code');
// Create a new element
$codeElement = new Zend_Form_Element_Select('code', array());
$codeElement->setLabel(_('Code :'));
$codeElement->setRequired(true);
$codeElement->addMultiOptions($codes);
$codeElement->setValue($values['code']);
$codeElement->setDecorators($this->elementDecorators);
$this->addElement($codeElement);
return $values;
}
We have to override the method "populate" too :
public function populate(array $values)
{
$values = $this->_modifyElements($values);
return parent::populate($values);
}
And voilà. It works for me ;>
All the credits about this go to Mohamed : http://jamandcheese-on-phptoast.com/2009/12/13/on-fly-elements-in-zend_form/
I have two dropdown in a form for selecting department and designation.
$model = new Application_Model_DbTable_Department();
$departments = $model->fetchAll();
$department = $this->createElement('select','department');
$department->setLabel('Department');
$department->setAttrib('class', 'department');
foreach($departments as $d)
$department->addMultiOption($d->id, $d->depname);
$model = new Application_Model_DbTable_Designation();
$designations = $model->fetchAll('depid=1');
$designation = $this->createElement('select','designation');
$designation->setLabel('Designation');
$designation->setAttrib('class', 'designation');
$designation->setRegisterInArrayValidator(false);
foreach($designations as $ds)
$designation->addMultiOption($ds->id, $ds->designation);
I have jquery function to for designation lookup when onchange of department. My problem is when submitting the form if the form has validation error , I need to display the selected designation.
In cases like this, It is best to do the form population after the form has been instantiated. Reason: it is next to impossible to get the values of the form elements on initialization because they do not exist yet (That is, in the init() method of the Zend_Form). You could do this:
$form = new Your_Zend_Form();
$designation = $form->getElement('designation');
$departmentId = null;
$request = $this->getRequest();
if($request->isPost()){
$departmentId = $request->getPost('department');
}
$desigantionOptions = $this->_getDesignationOptions($departmentId);
$designation->addMultiOptions($desigantionOptions);
This would be in your controller action or something... But in essence, your designation options would take values from the current department if available from the post or else it would fall to the default selection. The method signature of $this->_getDesignationOptions($departmentId) will be as follows:
protected function _getDesignationOptions($departmentId = null);
And this would return an array of value/option pair.
I have a many to many relation between Product and Properties. I'm using embedRelation() in my Product form to edit a Product and it's Properties. Properties includes images which causes my issue. Every time I save the form the updated_at column is updated for file properties even when no file is uploaded.
Therefore, I want to exclude empty properties when saving my form.
I'm using Symfony 1.4 and Doctrine 1.2.
I'm thinking something like this in my ProductForm.class.php, but I need some input on how to make this work.
Thanks
class ProductForm extends BaseProductForm
{
public function configure()
{
unset($this['created_at'], $this['updated_at'], $this['id'], $this['slug']);
$this->embedRelation('ProductProperties');
}
public function saveEmbeddedForms($con = null, $forms = null)
{
if (null === $forms)
{
$properties = $this->getValue('ProductProperties');
$forms = $this->embeddedForms;
foreach($properties as $p)
{
// If property value is empty, unset from $forms['ProductProperties']
}
}
}
}
I ended up avoiding Symfony's forms and saving models instead of saving forms. It can be easier when playing with embedded forms. http://arialdomartini.wordpress.com/2011/04/01/how-to-kill-symfony%E2%80%99s-forms-and-live-well/
Solved it by checking if posted value is a file, and if both filename and value_delete is null I unset from the array. It might not be best practice, but it works for now.
Solution based on http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms
class ProductPropertyValidatorSchema extends sfValidatorSchema
{
protected function configure($options = array(), $messages = array())
{
// N0thing to configure
}
protected function doClean($values)
{
$errorSchema = new sfValidatorErrorSchema($this);
foreach($values as $key => $value)
{
$errorSchemaLocal = new sfValidatorErrorSchema($this);
if(array_key_exists('value_delete', $values))
{
if(!$value && !$values['value_delete'])
{
unset($values[$key]);
}
}
// Some error for this embedded-form
if (count($errorSchemaLocal))
{
$errorSchema->addError($errorSchemaLocal, (string) $key);
}
}
// Throws the error for the main form
if (count($errorSchema))
{
throw new sfValidatorErrorSchema($this, $errorSchema);
}
return $values;
}
}