I am creating a form using Phalcon that has a checkbox on it. I use this code to create the checkbox in my PagesForm.php file
$this->add(new Check('usesLayout'));
and then in my view I have
{{ form.render("usesLayout") }}
However, if the checkbox is unchecked then Phalcon complains about usesLayout is required.
The html code produced by the view is
<input type="checkbox" id="usesLayout" name="usesLayout" value="1" checked="checked" />
What is the correct way to create a Phalcon form with a checkbox so that it accepts it both checked and unchecked?
Desired outcome
After looking back at a form made when using CakePHP the html output is
<input type="hidden" name="usesLayout" id="usesLayout_" value="0" />
<input type="checkbox" name="usesLayout" id="usesLayout" value="1" checked="checked" />
This works fine, so I am looking for something similar to this.
Current Workaround
After modifying the code in the final response to this question I have this workaround currently (I use this instead of Phalcon\Forms\Element\Check)
namespace Armaware\InBrowserDev\Forms\Element;
use Phalcon\Forms\Element\Check as PhalconCheck;
class Check extends PhalconCheck
{
/**
* Renders the element widget returning html
*
* #param array|null $attributes Element attributes
*
* #return string
*/
public function render($attributes = null)
{
$attrs = array();
if (!is_null($attributes)) {
foreach ($attributes as $attrName => $attrVal) {
if (is_numeric($attrName) || in_array($attrName, array('id', 'name', 'placeholder'))) {
continue;
}
$attrs[] = $attrName .'="'. $attrVal .'"';
}
}
$attrs = ' '. implode(' ', $attrs);
$id = $this->getAttribute('id', $this->getName());
$name = $this->getName();
$checked = '';
if ($this->getValue()) {
$checked = ' checked';
}
return <<<HTML
<input type="hidden" id="{$id}_" name="{$name}" value="0" />
<input type="checkbox" id="{$id}" name="{$name}" value="1"{$attrs}{$checked} />
HTML;
}
}
public Phalcon\Forms\ElementInterface setDefault (unknown $value) inherited from Phalcon\Forms\Element
Sets a default value in case the form does not use an entity or there is no value available for the element in _POST
Source.
Looks like your declaration of form can look like this:
$controls[] = (new Check('usesLayout', ['value' => '1']))
->setLabel('Should I use layout?')
->setDefault('0') // or `false` in case it's not filtered
->addFilter('bool'); // filtering to boolean value
Not tested, but probably will do. You can always try to make this trick with handling this in beforeValidation() method of form, but have no space to test it right now and am not risking on failurable solution here.
Related
In Codeigniter, the following code is typically used for a page that has a form. But the first time a user lands on the page and a form validation fails gets routed through the same path.
As this example shows, the flash data will trigger. even if the user just land on the page and have not submit any form yet.
I am trying to echo a new class name to some input field to highlight them if validation fails. but currently it highlights the field on first load as well.
I am aware I can echo a validation_error or form_error. is there a way to echo a generic message that is not tied to a field-name and only after submission fails
// rules and other stuff above
if ($this->form_validation->run() == FALSE){
$this->session->set_flashdata('errorClass',"is-invalid");
$this->load->view('defaultOrFalse');
}else{
$this->load->view('success');
}
//view file
<input class=" <?php $this->session->flashdata('errorClass') ; ?>">
Basically I am trying to get bootstrap 4's input validation to show up
https://getbootstrap.com/docs/4.0/components/forms/#server-side
I don't know your exact setup but you can do logic like the following:
<?php
class Some_controller extends CI_Controller {
// controller/search/{$term}
public function some_method($term = null) {
// where some_field is some field in your form
// that gets posted on submit
if ($this->input->post('some_field')) {
// or if (isset($_POST)) {
if ($this->form_validation->run() == FALSE) {
$this->session->set_flashdata('errorClass', "is-invalid");
$this->load->view('defaultOrFalse');
} else {
$this->load->view('success');
}
} else {
// default view
}
}
}
?>
For your second question:
<h5>Username</h5>
<?php echo form_error('username'); ?>
<input type="text" name="username" value="<?php echo set_value('username'); ?>" size="50" <?php if (!empty(form_error('username'))) { echo "class='error'"; } ?> />
Can also make a helper and use instead of form_error to check if field has error for your class (haven't verified this works but it should).
/**
* Checks if form validation field by name
* has error
*
* #param string $field Name of field
* #return boolean
*/
function field_has_error($field) {
$CI = &get_instance();
$CI->load->library('form_validation');
$arr = $CI->form_validation->error_array();
if (isset($arr[$field])) {
return true;
}
return false;
}
Usage:
<?php if (field_has_error('username')) { echo "class='error'"; } ?> />
I want to use a Array Object inside a Fluid form using Property Mapper. The products are dynamic added if user clicks an "add_product" link:
<f:form action="property" name="newOrder" object="{newOrder}">
<f:for each="{newOrder.orderProduct}" as="orderProduct" iteration="iterator">
<f:form.hidden property="orderProduct.{iterator.index}.product" value="8" />
<h3>OrderProduct: {orderProduct.product.title}</h3>
</f:for>
<f:form.hidden name="add_product" value="1" />
<input type="submit" value="submit" />
</f:form>
What I get after submit is this exception.
Uncaught TYPO3 Exception #1297759968:
Exception while property mapping at property path "orderProduct.0":
Property "product" was not found in target object of type "MyVendor\MyShop\Domain\Model\Product".
The hidden field resolves to: <input name="tx_myshop_pi1[newOrder][orderProduct][0][product]" value="8" type="hidden"> (the static value of 8 is just to simplify the example)
I also tried key="key" instead of iterator, empty brackets orderProduct[], using name instead of property without result.
This is the (simplified) Debug output:
newOrder (MyVendor\MyShop\Domain\Model\ShopOrder)
=> orderProduct (TYPO3\CMS\Extbase\Persistence\ObjectStorage)
3222112 => MyVendor\MyShop\Domain\Model\OrderProduct
product => MyVendor\MyShop\Domain\Model\Product
uid => 8
title => 'Product1'
This is the Model Code:
ShopOrder https://pastebin.com/YN7X37ei
OrderProduct https://pastebin.com/zFyztLAQ
For the Property Mapper, I tried a lot of configurations without success. In my opinion this should work but it does not:
public function initializePropertyAction()
{
/** #var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration */
$propertyMappingConfiguration = $this->arguments['newOrder']->getPropertyMappingConfiguration();
$propertyMappingConfiguration->allowAllProperties();
$propertyMappingConfiguration->setTypeConverterOption('TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
TRUE);
$propertyMappingConfiguration->forProperty('orderProduct')->allowAllProperties();
$propertyMappingConfiguration->forProperty('orderProduct')->setTypeConverterOption(
'TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
TRUE
);
//workaround from https://forge.typo3.org/issues/61628
for ($i = 0; $i < 99; $i++) {
$propertyMappingConfiguration->forProperty('orderProduct.' . $i)->allowAllProperties();
$propertyMappingConfiguration->forProperty('orderProduct.' . $i . '.*')->allowAllProperties();
$propertyMappingConfiguration->forProperty('orderProduct.' . $i)->setTypeConverterOption(
'TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
TRUE
);
}
}
I solved it like this, in my case for a question with a dynamic number of answers having two fields, each:
$propertyMappingConfiguration = $this->arguments->getArgument('question')->getPropertyMappingConfiguration();
$propertyMappingConfiguration->skipProperties('category');
$propertyMappingConfiguration->allowProperties('answers');
$propertyMappingConfiguration->forProperty('answers.*')->allowProperties('answerField1', 'answerField2');
$propertyMappingConfiguration->allowCreationForSubProperty('answers.*');
$propertyMappingConfiguration->allowModificationForSubProperty('answers.*');
I built form with GET method but when i submit form empty field also pass to url, can i exclude empty field from passing to url ?
For example > when i submit my form url changed to :
?jobTitle=Title&jobCompany=CompanyName&jobGovernorate=&jobLocation=&postingDate=ad
Here in this example jobGovernorate and jobLocation is empty so i want form skip those when i submit the form.
If there's a way to get url like this
?jobTitle=Title&jobCompany=CompanyName&postingDate=ad
Because jobGovernorate and jobLocation is empty
Sorry for poor english, Thank you.
You can use middleware for your problem
class StripEmptyParams
{
public function handle($request, Closure $next)
{
$query = request()->query();
$querycount = count($query);
foreach ($query as $key => $value) {
if ($value == '') {
unset($query[$key]);
}
}
if ($querycount > count($query)) {
$path = url()->current() . (!empty($query) ? '/?' . http_build_query($query) : '');
return redirect()->to($path);
}
return $next($request);
}
}
then call for specific route like code below
Route::get('/search','YourController#search')->middleware(StripEmptyParams::class);
Assuming you have a form as below
<form>
<input type="text" class="url_params" name="jobTitle" value="">
<input type="text" class="url_params" name="jobCompany" value="">
<input type="text" class="url_params" name="jobGovernorate" value="">
<input type="text" class="url_params" name="jobLocation" value="">
<input type="text" class="url_params" name="postingDate" value="">
<input type="submit" name="submit" id="submit">
</form>
<script type="text/javascript">
$(document).ready(function () {
$("#submit").on("click", function(e) {
e.preventDefault();
var url = '{{ url('/') }}?';
var total = $(".url_params").length;
$(".url_params").each(function (index) {
if ($(this).val().trim().length) {
if (index === total - 1) {
url += $(this).attr('name') + '=' + $(this).val();
} else {
url += $(this).attr('name') + '=' + $(this).val() + "&";
}
}
});
window.location.href = url;
});
});
</script>
The above code will generate an URL based on the field value and redirect to the url. So it won't generate a url with the empty field value key.
And having an empty field value shouldn't make a difference as you could check for the url values in the controller using $request->input('key')
Hope this helps!
Go through array like this, you will just check if your array has empty, will not add the key.
$data = array('foo'=>'bar',
'baz'=>'boom',
'cow'=>'milk',
'php'=>'hypertext processor');
echo http_build_query($data) . "\n";
//echo http_build_query($data, '', '&'); // only for use & instead & if needed
I have applied the next middleware on a Laravel 8.x project to solve a related problem. This may be helpful to other ones...
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class StripEmptyParamsFromQueryString
{
/**
* Remove parameters with empty value from a query string.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
// Get the current query and the number of query parameters.
$query = request()->query();
$queryCount = count($query);
// Strip empty query parameters.
foreach ($query as $param => $value) {
if (! isset($value) || $value == '') {
unset($query[$param]);
}
}
// If there were empty query parameters, redirect to a new url with the
// non empty query parameters. Otherwise keep going with the current
// request.
if ($queryCount > count($query)) {
return redirect()->route($request->route()->getName(), $query);
}
return $next($request);
}
}
Note the middleware should only be applied to specific routes, not to all request. In my particular case I have a resource controller and to apply the middleware only to the index route I have used the next approach inside the resource controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Middleware\StripEmptyParamsFromQueryString;
class MyController extends Controller
{
/**
* Instantiate a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(StripEmptyParamsFromQueryString::class)
->only('index');
}
...
}
I want the following html with two radio button groups in zend form
<label class="inline">
<input type="radio" name="form-field-radio">
<span class="lbl"> Male</span>
</label>
<label class="inline">
<input type="radio" name="form-field-radio">
<span class="lbl"> Female</span>
</label>
and i'm using the following code to make this button in Zend Form
$gender = $this->CreateElement('radio','gender')
->addFilter(new Zend_Filter_StringTrim())
->setMultiOptions(array('M'=>'Male', 'F'=>'Female'))
->setDecorators(array( array('ViewHelper') ));
But I don't know where to set the lable and span classes in this code.
Please help.
Thanks.
I am not sure whether its the perfect method to do this its the first time i am using zend framework, But still here are the steps that i did, if you may find useful:
First I created a custom decorator which extends Zend_Form_Decorator_Abstract and saved it in the location 'decorator/My_Form_Decorator.php'. decorator is a directory created by me in root.
.
/decorator
/application
etc...
Then i included it in a controller. I have read that there are certain methods for adding the decorator like addPrefixPath() but for time sake i just included the decorator file in top with 'include "../decorator/My_Form_Decorator.php";'. Then instead of using the CreateElement method i used Zend_Form_Element.
The following is the code of custom radio decorator
My_Form_Decorator.php
class My_Decorator_RadioInput extends Zend_Form_Decorator_Abstract
{
public function render($content)
{
$element = $this->getElement();
$label = htmlentities($element->getLabel());
$type = $element->type;
$name = $element->elemName;
$multiOptions = $element->multiOptions;
$labelClass = $element->labelClass;
$spanClass = $element->spanClass;
$markup='';
if(!empty($type) && !empty($name) && !empty($multiOptions) && is_array($multiOptions)){
foreach($multiOptions as $key=>$value){
$markup .='<label class="'.$labelClass.'"><input type="radio" name="'.$name.'" value="'.$key.'"> <span class="'.$spanClass.'">'.$value.'</span></label>';
}
}
return $markup;
}
}
and this is the code in my controller function
IndexController.php
$decorator = new My_Decorator_RadioInput();
$form = new Zend_Form();
$form->setAttrib('id', 'test');
$element = new Zend_Form_Element('foo', array(
'elemName'=>'gender',
'type' =>'radio',
'multiOptions' => array('M'=>'Male', 'F'=>'Female'),
'labelClass'=>'inline',
'spanClass'=>'lbl',
'decorators' => array($decorator),
));
$form->addElement($element);
$this->view->form = $form;
And in view index.phtml
echo $this->form
Hope this is helpful to you..
I'm trying to get the option item selected in a form select element using Codeigniter...
I have a controller named results with this code in it
//get form data
if($_SERVER['REQUEST_METHOD'] == "POST"){
$data['searchdata'] = array(
"ionum" => $this->input->post('ionum'),
"thisdb" => $this->input->post('thisdb')
);
}
which loads into a view, the 'ionum' is a text input which I can retrieve, the 'thisdb' is the select, I get no results for it...how do I pull that?
Ensure your html looks like:
<form action="<?= site_url('mycontroller/myfunction');?>" method='post'>
<input type='text' name='ionum'/>
<select name='thisdb'>
<option value='db1'>DB1</option>
<option value='db2'>DB2</option>
</select>
</form>
Then in your controller, you would write:
class Mycontroller extends CI_Controller{
function myfunction(){
$p = $this->input->post();
if($p){
//you can now access the ionum and thisdb... try echo
echo $p['ionum'];
echo $p['thisdb'];
}
}
}
It is unnecessary to run the if($_SERVER['REQUEST_METHOD'] == "POST") conditional. Just check if $p exists as above.