How can I change the attributes of a input form?
I create with this a input (productform.php):
$this->add(array(
'name' => 'categoryId',
'attributes' => array(
'id' => 'categoryId',
'type' => 'hidden',
'value' => '',
),
));
In a previous page I link to the form and set the special value in the url (....com/form/3).
In the indexcontroller.php I get the form with $form = new ProductForm(); and want edit the value and set the special value from the url.
My idea was the $form->setAttribute('categoryId', 'value'); but that not working.
Thanks.
indexcontroller.php
...
$form = new ProductForm();
$form->setHydrator(new CategoryHydrator());
$form->bind(new Product());
$form->setAttribute('categoryId', 'value');
....
productform.php
...
class ProductForm extends Form
{
public function __construct()
{
parent::__construct('productForm');
$this->setAttribute('action', 'newproduct');
$this->setAttribute('method', 'post');
$this->add(array(
........
$form->get('categoryId')->setValue("value");
Update
So if you just want to fill input, you mean placeholder attribute in html. You can use setAttribute method.
$form->get('categoryId')->setAttribute('placeholder', 'text to show');
The form view helper will not allow arbitrary HTML attributes to be set on the form. This is because it would result in invalid HTML.
If you take a look at Zend\Form\Helper\AbstractHelper there are two properties $validGlobalAttributes and $validTagAttributes which define the allowed tags.
In the case of the form view helper (Zend\Form\View\Helper\Form) The 'valid tag attributes' will be the method, action etc
As you require something custom (for JS possibly?); I would change it to a data- attribute.
$form->setAttribute('data-categoryId', 'value');
The data- is a valid HTML5 attribute which is useful for adding 'domain data' to HTML elements and is really the 'correct' way to do what you require.
Related
i have an ChoiceType::class input field in my form with, now just as an example, two choices:
'choices' => ['type1' => '1', 'type2' => '2']
now when the user select type2 i want to add an exta TextType::class inputfield to the form.
But i dont want to show the input field before and i want it to be required if selected type2 and not if selected type1.
I hope it make sense, i try it to to with javascript and set the attribute to hidden or not, but
then the form is not been send because of the required attribute.
I tried it with form events but did not get it to work in that way.
Thanks
You were on the right way, you have to do it in Javascript. You just need to manage the attr required in Javascript so that the form does not block you with something like this:
Remove the required attribute from a field: document.getElementById("id").required = false;
Make a field required : document.getElementById("id").required = true;
And you can check if the form can be sumitted with : document.getElementById("idForm").reportValidity();.
I using implementation of conditional fields with data-attributes, e.g.:
->add('typeField', EnumType::class, [
'label' => 'Type',
'class' => MyTypeEnum::Class,
])
->add('someField', TextField::class, [
'data-controller' => 'depends-on',
'data-depends-on' => 'my_form_typeField',
'data-depends-value' => MyTypeEnum::OTHER->value,
])
On frontend JS stimulus controller show/hide someField depend on typeField value.
And validation() function in object ('data_class' in formType) make custom validation, e.g.:
/**
* #Assert\Callback
*/
public function validate(ExecutionContextInterface $context)
{
if ($this->typeField !== MyTypeEnum::OTHER) {
$context->buildViolation('message')->atPath('typeField')->addViolation();
}
}
Question: Is it possible to access to the Form class from an added element?
Example case:
Note: This example makes no sense as it is, but that's not exactly what I'm trying to do: It's just to keep things simple
Suppose to have a custom view helper that wraps an element into a div. Something like:
public function render(ElementInterface $element = NULL) {
return '<div class="myclass">'.$this->view->formElement($element).'<div>';
}
I would like to retrive the class 'myclass' from the element itself and add it to the div only if the form has been submitted. Something like:
public function render(ElementInterface $element = NULL) {
$class='default';
if(isset($_POST['submit'])){
$class=$element->getOption('wrapper_class');
}
return'<div class="'.$class.'">'.$this->view->formElement($element).'<div>';
}
That works (if 'submit' is the name of the submit button) but, if I have two forms into the same page the second form submission will trigger the above condition and the class will be applied.
A workaround could be:
class MyForm extends Form {
public function __construct($name = null){
parent::__construct($name);
$this->add([
'name' => 'myElement',
'type' => MyCustomElement::class,
'options' => [
'triggered_by' => $this->getName(),
'wrapper_class'=>'myClass',
],
]);
$this->add([
'name' => $this->getName(),
'type' => 'submit',
'attributes' => [
'value' => 'Go',
'id' => 'submitbutton',
'class'=>'btn btn-success',
],
]);
}
}
and then: if(isset($_POST[$element->getOption('triggered_by')])){ ... }
But that works good only if the custom element is added directly to the form. If it's added to a fieldset then $this->getName() will return the name of the fieldset. Obviously the name could be added as a string but I would like to avoid it (typos).
The top solution would be to have access to the main form's options/attributes from all the sub-elements but the elements do not extend Form (myElement->extend Element , Form->extend Fieldset->extend Element).
...then...?
Simple answer: no you can't. Elements can also be a part of a fieldset so they're not directly coupled to a form element.
You could take a different approach with your viewhelper. As in: $myHelper::__invoke(Form $form) or $myHelper::setForm(Form $form), which sets the form. From within that method you can check whether or not the form $form::hasValidated() because that tells us that the form was posted. Then from with the $myHelper::render(ElementInterface $element), you could add some logic to add the wrapperclass as in your example. And within your example merge the classes so that the wrapper doesnt replaces all the form element (css) classes.
Assume I'm in my items controller.
Ok say I am in my view action (the url would be something like /items/view/10012?date=2013-09-30) which lists a list of items that belongs to a client on a given date.
I want to link to add a new item. I would use the htmlhelper like so:
echo $this->Html('action'=>'add');
In my add action I have a form which has fields like client_id and item_date.
When I'm in my view action I know these values as I am viewing the items for a specific client on a specific date. I want to pass these variables to my add action so it will prefill those fields on the form.
If I add a query string in my link ('?' => array('client_id'=>$client_id)) it breaks the add action as it will give an error if the request is not POST. If I use a form->postLink I get another error as the add action's POST data must only be used for adding the record, not passing data to prefill the form.
I basically want to make my link on the view page pass those 2 variables to the add action in the controller so I can define some variables to prefill the form. Is there a way to do this?
Here is my add controller code. It may differ in content a bit from my question above as I have tried to simplify the question a bit but the concept should still apply.
public function add(){
if ($this->request->is('post')) {
$this->Holding->create();
if ($this->Holding->save($this->request->data)) {
$this->Session->setFlash(__('Holding has been saved.'), 'default', array('class' => 'alert alert-success'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('Unable to add your holding.'), 'default', array('class' => 'alert alert-danger'));
}
$this->set('accounts', $this->Holding->Account->find('list'));
$sedol_list = $this->Holding->Sedol->find('all', array(
'fields' => array(
'id', 'sedol_description'
),
'recursive' => 0,
'order' => 'description'
)
);
$this->set('sedols', Hash::combine($sedol_list, '{n}.Sedol.id', '{n}.Sedol.sedol_description') );
}
Why not use proper Cake URL parameters?
echo $this->Html->link('Add Item', array(
'action' => 'add',
$client_id,
$item_date
));
This will give you a much nicer URL like:
http://www.example.com/items/add/10012/2013-09-30
And then in your controller, you modify the function to receive those parameters:
public function add($client_id, $item_date) {
// Prefill the form on this page by manually setting the values
// in the request data array. This is what Cake uses to populate
// the form inputs on your page.
if (empty($this->request->data)) {
$this->request->data['Item']['client_id'] = $client_id;
$this->request->data['Item']['item_date'] = $item_date;
} else {
// In here process the form data normally from when the
// user has submitted it themselves...
}
}
The HTML I need:
<label for="text_field_username">User Name</lable>
<input type="text" id="text_field_username" name="text_field_username" class="form-control" />
I want the for of the label to link to the id of the input. This way the user can click on the label to highlight the input. More usefull for checkbox.
Also, less important, I want to had a class to the input field.
What I have tried and does not works for me:
echo $this->formRow($form->get('usr_name'));
I also tried to use partial layout.
echo $this->formElement($element);
Before posting this question I came across this documentation
framework.zend.com/manual/2.2/en/modules/zend.form.view.helpers.html#formlabel
It does not works. It add the for but it point to nothing. !?
View partials help with the rendering of the form, they don't however deal with the properties of the form elements themselves. This is dealt with by the form class and it's collection of form elements (I.e TextElement)
You can use setAttribute('class', 'class name') on any form element
So within the init() method of your form this should work:
$element = $this->getElement('text_field_username');
$element->setAttribute('class', 'class name');
You can also set this in your inherited form helper class like this:
namespace Application\Form;
use Zend\Form\Form;
class NexForm extends Form
{
public function __construct($name = null)
{
parent::__construct('Nex');
$this->setAttribute('method', 'post');
$this->setAttribute(
'enctype',
'multipart/form- data'
);
$this->add(array(
'name' => 'default_widget',
'attributes' => array(
'type' => 'text',
'id' => 'default_widget',
'class' => 'mtz-monthpicker-widgetcontainer',
'required' => 'required',
),
'options' => array(
'label' => 'Please choose the month of records you want to display:',
),
));
}
}
and in your view just call:
$nex=$this->app; //app is the form object we passed from controller to view
echo $this->formElement($nex->get('default_widget'));
I have a small site which allows a user to enter values in a form and then either submit it directly or store the field values in a template to later submit it. To submit the form later, he can load the previously saved template. For that there are three buttons Load Template / Save Template / Submit form.
Because i am using the form validation built-in functionality from Codeigniter i run into problems when i want to populate the form with a template, which had been previously stored.
The form fields are all set up like
$name = array(
'name' => 'name',
'id' => 'name',
'value' => set_value('name', $form_field_values['name'])
);
The variable $form_field_values holds the values from either a loaded template in the case when a template has been loaded or the default values when the form is first loaded.
Initially the form is loaded with the default values. When i click on Load Template the values from the template are not chosen by set_value() because there were the default values in there before. What i want is to replace the values of the form fields with the ones from the template.
Do you have any idea how to do that in a clean approach? What i have done is to introduce a variable to skip the call to set_value() completely like:
$name= array(
'name' => 'name',
'id' => 'name',
'value' => $skip_form_validation ? $form_field_values['name'] : set_value('name', $form_field_values['name'])
);
Where $skip_form_validation is a variable set in the controller, based on what button was pressed. Form validation is skipped for saving/loading a template.
Codeigniter's set_value() function is a simple function which finds value in $_POST if value found then return else returns second argument, you can remove set_value() and write your own code for it. you can write $_POST['field_name'] if you want to populate value of POST data or add whatever value you want to add
Just use like this
$name = array(
'name' => 'name',
'id' => 'name',
'value' => $valueFromYourTemplate
);
You don't need to use set_value() function if you don't want to set POST values in the form
Assuming you retrieve the database fields and pass them to a data array in your controller.
$record = $this->data_model->get_record(array('uid' => $user_id), 'users');
if (!is_null($record)) {
$data['uname'] = $record->username;
$data['loc'] = $record->location;
}
where 'users' is the database table, and the uid is the id field of the table users.
In your form, do something like this
Hope it helps!