I think I've found a bug in Cake's FormHelper class, but maybe I'm just not using the correct function, so hopefully somebody on here knows. Here's the relevant code:
<?php
echo $this->Form->input('first_name', array('value' =>'First Name', 'label' => false));
?>
As you can see, I'm just outputting an input text field that has a default value of First Name. The issue I'm experiencing is that if the user does not provide a valid name, then the form does not preserve the value that the user tried to submit with, instead it just shows the default value again (First Name). So basically, if I were to enter into the field "hey123" and then click submit, the form will show the appropriate validation error message next to the text field, but the text field itself won't contain my previous entry of hey123, it will show the First Name text again.
Is it possible to have the input field show the default value initially while also allowing whatever the user entered into the form to be preserved when validation errors occur? So in the previous example, instead of showing the First Name text on the error validation page, it'd show my original entry that caused the issue, hey123.
Use:
<?php
echo $this->Form->input('first_name', array('default' =>'First Name', 'label' => false));
?>
Note, use default instead of value. Default will set a 'default' value, while value will explicitly set the value of that field.
Related
I'm working with forms where the checkboxes are present, but the target model's fields must be in boolean type, since they are defined in my migrations as boolean. For example:
$table->boolean('is_active')->default(true);
The Model's values are filled in this way:
foreach (static::getFillableFields() as $field) {
$entry->$field = $request->input($field);
}
So I added the cast to make this field boolean:
class Entry extends Model
{
protected $casts = [
'is_active' => 'boolean',
];
But now what I see: when the form's checkbox is checked and I have '1' string in the request, it works well - '1' gives 'true' when I access $entry->is_active then. But when checkbox isn't checked, it gives the 'null' value, and - I don't know why - when the model's field is set to null, then it returns null (not 'false', as I expected).
Why is it so? This makes casts useless in my case. Can I change this behavior?
I'm not too inspired with idea of adding this (accessors/mutators) for every boolean field (but in fact this results in what I need):
public function setIsActiveAttribute($value)
{
$this->attributes['is_active'] = (bool)$value;
}
public function getIsActiveAttribute(bool $value): bool
{
return $value;
}
As #Devon mentioned, checkboxes that are not checked are not included in the request data sent to the controller. The HTML spec deems unchecked checkboxes as unsuccessful, and therefore does not submit them.
One trick that is used to get around this "limitation", however, is to add a hidden input to your HTML that has the same name as your checkbox, but contains the false value. This hidden input must come before your checkbox input.
This will allow you to continue to use your mass-assignment functionality.
So, your form should look something like:
<input type="hidden" name="is_active" value="0" />
<input type="checkbox" name="is_active" value="1" />
Now, when the form is submitted with an unchecked checkbox, the hidden input will ensure the input value exists in the request data with the false value (0).
When the form is submitted with a checked checkbox, both inputs will submit successfully with the same name, but the server side will only take the last value it sees. This is why the checkbox must come after the hidden input field, so that the last value the server sees is the successful value defined on the checkbox (1).
As a side note, this is also how the Ruby on Rails form helper handles checkboxes. From their documentation.
The HTML specification says unchecked check boxes are not successful, and thus web browsers do not send them. Unfortunately this introduces a gotcha: if an Invoice model has a paid flag, and in the form that edits a paid invoice the user unchecks its check box, no paid parameter is sent. So, any mass-assignment idiom like
#invoice.update(params[:invoice])
wouldn’t update the flag.
To prevent this the helper generates an auxiliary hidden field before the very check box. The hidden field has the same name and its attributes mimic an unchecked check box.
This way, the client either sends only the hidden field (representing the check box is unchecked), or both fields. Since the HTML specification says key/value pairs have to be sent in the same order they appear in the form, and parameters extraction gets the last occurrence of any repeated key in the query string, that works for ordinary forms.
This is a controller issue, not a model issue. HTML checkboxes will not have a value if they are unchecked, this is how they work.
Therefore, when retrieving the value from your Request object in the controller, you should set the default value as false.
Example in controller method:
$model->is_active = $request->input('is_active', false);
If you leave the second argument of input() empty, it will default to null.
Suddenly: casts don't work for Model::save() method.
laravel eloquent model casts on save?
So all that's left for me is to use accessors/mutators..
I have a form which works fine without it but when I add
CreditCardField::create('CreditCard','Credit Card')->setAttribute('placeholder', '0000')
it displays the credit card field with the same name, id and other attributes. When I go to submit it of course the validation throws an error as it's expecting an array but only gets a string of the last 4 digits.
Am I creating this field correctly? I'm assuming that once I fix the display issues it will fix the validation issues.
I'm not hugely familiar with this field type, but you can see from it's template that it doesn't expect to be able to set a placeholder:
<span id="{$Name}_Holder" class="creditCardField">
<input $AttributesHTML('id', 'name', 'value', 'tabindex') name="{$Name}[0]" value="{$ValueOne}" $TabIndexHTML(0)/>
-
<input $AttributesHTML('id', 'name', 'value', 'tabindex') name="{$Name}[1]" value="{$ValueTwo}" $TabIndexHTML(1)/>
-
<input $AttributesHTML('id', 'name', 'value', 'tabindex') name="{$Name}[2]" value="{$ValueThree}" $TabIndexHTML(2)/>
-
<input $AttributesHTML('id', 'name', 'value', 'tabindex') name="{$Name}[3]" value="{$ValueFour}" $TabIndexHTML(3)/>
</span>
The attributes you can set are ID, name, value and tabindex. Placeholder may be omitted deliberately for some sort of security reason, or it may just be a missing feature.
Your best bet might be to use some javascript instead:
$('#MyCreditCard_Holder').find('input').attr('placeholder', '0000');
So there is a bug in the template that I've logged a ticket for. The work around for it at the moment is you have to have your own CreditCardForm.ss template that uses $getAttributesHTML rather than $AttributesHTML
So i have this field i want to keep hidden in my form.
For this purpose i have tried the following:
<?php echo $this->Form->input('group_id', array('hiddenField' => true, 'value'=> 2)); ?>
I also tried:
<?php echo $this->Form->input('group_id', array('options' => array('hiddenField'=> 'true'), 'value'=>2 )); ?>
How ever i still see the input field..
What am i doing wrong?
You misread the documentation, I assume.
hiddenField is to enable/disable specific hidden fields for specific form fields.
You are either looking for
$this->Form->hidden('group_id')
or
$this->Form->input('group_id', ['type' => 'hidden']);
I usually only use the latter.
See http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html
BUT - that said - you shouldnt actually use either one of those. And omit any fields that serve no real purpose for the view and its form.
Instead you should inject those fields into the data array prior to saving.
See http://www.dereuromark.de/2010/06/23/working-with-forms/
If you are looking to add a hidden field that uses a related second data array that will not be passed via post or put by default, you can use this to pass it:
echo $this->Form->hidden('Group.name');
This is useful for echoing out edit page titles when the post or put encounters an error. A dynamic title can lose Group.name data array when your form is set up such as this:
<h1>Edit Group - <?php echo h($this->request->data['Group']['name']); ?></h1>
For data that is to be saved to db however, follow Mark's suggestion above.
Try following code in cakephp 3 to set hidden field
<?php
echo $this->Form->hidden('name');
?>
Due to the appearance of the website I'm working on, I've had to modify how radio fields appear on the screen in Cakephp. To do this, I create a radio input with the 'div' set to false, then I add my own version of a label and create the 'input radio' field div on top of this myself. However, this doesn't work with the built-in error messages added via the Cakephp validation. In other words, when a validation fails, the error class is not added to the fields div that I manually created. I'm wondering how Cakephp determines which div to add the error message to upon a validation failure. Can anyone explain this and/or point to where it happens in the code? Thanks!
If you're using the FormHelper, you can specify 'error' => false in the $options array when doing $form->input() or $form->radio(), or in the $form->create(); call if you're using that (this will turn off errors for ALL elements in the form though). That will turn off default error messages. You can then manually check for errors like so:
if ($form->error('ModelName.field_name')) {
echo $form->error('ModelName.field_name');
}
You can add options while doing the specific error call - add div wrappers, class names, whatever you need.
<?php
$this->widget('CAutoComplete', array(
'name'=>'search',
'id'=>'input-box',
'attribute'=>'search',
'url'=> $this->createAbsoluteUrl('products/suggestions'),
'value'=>($_GET['search'] == '')?'Search for Mobiles, Cameras & Laptops':$_GET['search'],
'minChars'=>2,
'scroll'=>false,
'resultsClass'=>'searchAutoComplete ac_results',
'htmlOptions'=> array(
'class'=>'searchClickClear',
),
'methodChain'=>'.result(function(){$("form#search-form").submit();})'
));
?>
This is my widget for taking input, and I am passing the class searchAutoComplete. What the class should be? What I want is, when I click on the field the value will be empty.
When you click on input field, event onclick is going on.
So, you can handle it and change input value to empty. Howto?
Change your 'htmlOptions' like this:
'htmlOptions'=> array(
'onclick'=>'$("#input-box").val("")';
),
#input-box - css-selector of your input.
val() - jQuery method for setting some value to elements. See more info about this method
resultsClass - the CSS class for the dropdown list. Defaults to "ac_results". More info
For the task solution you don't need change resultsClass from the default value. Remove this string.