How to implement custom_checklist_from_array? Like checklist but the data is inputted in CrudController - laravel-backpack

I want to use Checklist Field in laravel backpack, but it says that we have to need a relation with another table. But I would like to put the Options in my CrudController like select_from_array.
I have no idea how to custom this field.
I want to use checklist instead of select_from_array

Create a file at resources/views/vendor/backpack/crud/fields/checklist_direct.blade.php with the below content (checklist_direct can be any name you choose):
<!-- checklist with directly provided options -->
<!-- checklist_filtered -->
#php
$options = isset($field['options']) ? $field['options'] : [];
#endphp
<div #include('crud::inc.field_wrapper_attributes') >
<label>{!! $field['label'] !!}</label>
#include('crud::inc.field_translatable_icon')
<?php $entity_model = $crud->getModel(); ?>
<div class="row">
#foreach ($options as $option)
<div class="col-sm-4">
<div class="checkbox">
<label>
<input type="checkbox"
name="{{ $field['name'] }}[]"
value="{{ $option }}"
#if( ( old( $field["name"] ) && in_array($option , old( $field["name"])) ) )
checked = "checked"
#endif > {!! $option !!}
</label>
</div>
</div>
#endforeach
</div>
{{-- HINT --}}
#if (isset($field['hint']))
<p class="help-block">{!! $field['hint'] !!}</p>
#endif
</div>
Then update your call to addField to in your controller would look something like:
$this->crud->addField([
'label' => 'Printers',
'type' => 'checklist_direct',
'name' => 'printer',
'attribute' => 'printer_name',
'options' => ['HP', 'Cannon', 'Dell'],
]);
NOTE: You might also consider using an enum column on your table and using the enum.blade.php field template or possibly making a custom enum field that uses checkboxes instead of a select box.

I needed to do some updates on the code. I create a file at resources/views/vendor/backpack/crud/fields/checklist_array.blade.php with the below content (checklist_array can be any name you choose):
I updated the code for the one below, One of the updates I did was, when editing it did not bring the selected values. Now you are bringing through script in javascript
<!-- checklist with directly provided options -->
<!-- checklist_filtered -->
#php
$options = isset($field['options']) ? $field['options'] : [];
// calculate the value of the hidden input
$field['value'] = old(square_brackets_to_dots($field['name'])) ?? ($field['value'] ?? ($field['default'] ?? []));
if (is_string($field['value'])) {
$field['value'] = json_decode($field['value']);
}
// define the init-function on the wrapper
$field['wrapper']['data-init-function'] = $field['wrapper']['data-init-function'] ?? 'bpFieldInitChecklist';
#endphp
#include('crud::fields.inc.wrapper_start')
<label>{!! $field['label'] !!}</label>
#include('crud::fields.inc.translatable_icon')
<input type="hidden" value='#json($field['value'])' name="{{ $field['name'] }}">
<div class="row">
#foreach ($options as $option)
<div class="col-sm-4">
<div class="checkbox">
<label>
<input type="checkbox" name="{{ $field['name'] }}[]" value="{{ $option }}" #if( ( old( $field["name"] )
&& in_array($option , old( $field["name"])) ) ) checked="checked" #endif> {!! $option !!}
</label>
</div>
</div>
#endforeach
</div>
{{-- HINT --}}
#if (isset($field['hint']))
<p class="help-block">{!! $field['hint'] !!}</p>
#endif
#include('crud::fields.inc.wrapper_end')
{{-- ########################################## --}}
{{-- Extra CSS and JS for this particular field --}}
{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
#if ($crud->fieldTypeNotLoaded($field))
#php
$crud->markFieldTypeAsLoaded($field);
#endphp
{{-- FIELD JS - will be loaded in the after_scripts section --}}
#push('crud_fields_scripts')
<script>
function bpFieldInitChecklist(element) {
//console.log(element);
var hidden_input = element.find('input[type=hidden]');
var selected_options = JSON.parse(hidden_input.val() || '[]');
var checkboxes = element.find('input[type=checkbox]');
var container = element.find('.row');
// set the default checked/unchecked states on checklist options
checkboxes.each(function(key, option) {
var id = $(this).val();
if (selected_options.map(String).includes(id)) {
$(this).prop('checked', 'checked');
} else {
$(this).prop('checked', false);
}
});
// when a checkbox is clicked
// set the correct value on the hidden input
checkboxes.click(function() {
var newValue = [];
checkboxes.each(function() {
if ($(this).is(':checked')) {
var id = $(this).val();
newValue.push(id);
}
});
hidden_input.val(JSON.stringify(newValue));
});
}
</script>
#endpush
#endif
{{-- End of Extra CSS and JS --}}
{{-- ########################################## --}}
//form
$this->crud->addField([
'label' => 'Printers',
'type' => 'checklist_direct',
'name' => 'printer',
'attribute' => 'printer_name',
'options' => ['HP', 'Cannon', 'Dell'],
]);
//model
protected $casts = [
...
'printer' => 'array',
];

Related

Linking edit button from table to Laravel Edit form

I have a table that displays the data from my database. at the end of each row I have an Edit/Update Button. I would like it when clicking on the edit button it reference the the Edit Form.
My edit form works. I can access the data when visiting computers/{id}/edit, The form displays the current data and I can edit the data and submit the updates and it updates in the database (mysql).
This is my index.blade.php, which displays the table with the update button
#extends('layout')
#section('content')
<h1>Inventory</h1>
<table class="table table-striped">
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Department</th>
<th>Building</th>
<th>Room</th>
<th>Manufacturer</th>
<th>Device</th>
<th>Model</th>
<th>Service Tag</th>
<th>Mac Address</th>
<th>Status</th>
<th>Comments</th>
</tr>
</thead>
<tbody>
#foreach($inventories as $inventory)
<tr>
<td>{{$inventory->lastName}}</td>
<td>{{$inventory->firstName}}</td>
<td>{{$inventory->department}}</td>
<td>{{$inventory->building}}</td>
<td>{{$inventory->room}}</td>
<td>{{$inventory->manufacturer}}</td>
<td>{{$inventory->device}}</td>
<td>{{$inventory->model}}</td>
<td>{{$inventory->tag}}</td>
<td>{{$inventory->macAddress}}</td>
<td>{{$inventory->status}}</td>
<td>{{$inventory->comments}}</td>
<td>
{{--Need the button to open up my edit form--}}
<button formaction="computers/{id}/edit">{{ trans('computers.edit') }}</button>
{{--<input type="submit" name="update" id="update" value="Update" class="btn btn-primary">--}}
</td>
</tr>
#endforeach
</tbody>
</table>
#stop
This is my form.blade.php - which is a partial that I include in my create.blade.php and edit.blade.php and both of these pages work.
<div class="row">
<div class="col-md-6">
<div class="form-group">
{!! Form::label('lastName', 'Last Name:') !!}
{!! Form::text('lastName', null, ['class' => 'form-control' ]) !!}
</div>
<div class="form-group">
{!! Form::label('firstName', 'First Name:') !!}
{!! Form::text('firstName', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label('departmen', 'Department:') !!}
{!! Form::text('department', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group" >
{!! Form::label('building', 'Building:') !!}
{!! Form::select('building', ['vanHall' => 'Vanderbilt Hal',
'wilf' => 'Wilf Hall',
'dag' => 'D Agostino Hall',
'furmanHall' => 'Furman Hall',
'wsn' => 'WSN',
'mercer' => 'Mercer',
'training' => 'Traing Room',
'storage' => 'Storage'
</div>
<div class="form-group">
{!! Form::label('room', 'Room:') !!}
{!! Form::text('room', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label('manufacturer', 'Manufacturer:') !!}
{!! Form::text('manufacturer', null, ['class' => 'form-control']) !!}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
{!! Form::label('device', 'Device:') !!}
{!! Form::select('device', ['desktop' => 'Desktop',
'laptop' => 'Laptop',
'classroom' => 'Classroom',
'printer' => 'Printer',
'mifi' => 'MiFi',
'panopto' => 'Panopto',
'Other' => 'Other',
], null, ['placeholder' => 'Select Device'])!!}
</div>
<div class="form-group">
{!! Form::label('model', 'Model:') !!}
{!! Form::text('model', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label('tag', 'Service Tag:') !!}
{!! Form::text('tag', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label('macAddress', 'Mac Address:') !!}
{!! Form::text('macAddress', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label('status', 'Status:') !!}
{!! Form::select('status', ['active' => 'Active',
'inactive' => 'Inactive',
], null, ['placeholder' => 'Status'])!!}
</div>
<div class="form-group">
{!! Form::label('comments', 'Comments:') !!}
{!! Form::text('comments', null, ['class' => 'form-control']) !!}
</div>
</div>
<div class="col-md-12">
<hr>
<div class="form-group">
{!! Form::submit($submitButtonText, ['class' => 'btn btn-primary form-control']) !!}
{{--<button type="submit" class="btn btn-primary">Submit</button>--}}
</div>
</div>
Instead of using a button I would use an <a> tag.
<a href="{{ url('computers/'.$inventory->id.'/edit') }}>{{ trans('computers.edit') }}</a>
the url() function is a Laravel helper function
Also.. I'm sure there are enough examples of things like this, so make sure you google your question first.
Try this:
<button href="computers/{id}/edit">{{ trans('computers.edit') }}</button>
Or you could use form (Laravel Collective way):
{!! Form::open(['method' => 'Get', 'route' => ['computers.edit', $inventory->id]]) !!}
{!! Form::submit(trans('computers.edit')) !!}
{!! Form::close() !!}
sorry for the late reply
if you are creating the bigger project and if you hate being write the code in every
index.balde.php file for generarting the Edit,Show,Delete Buttons
just use my helper function
For Eg:
Laravel 5.7
Open Your Model it may be Computer or SomeModel
Just Paste the following Code into it
public static function tableActionButtons($fullUrl,$id,$titleValue,$buttonActions = ['show', 'edit', 'delete'],$buttonOptions='')
{
//Value of the post Method
$postMethod = 'POST';
//if the application is laravel then csrf is used
if (function_exists('csrf_token'))
{
$token = csrf_token();
}elseif (!function_exists('csrf_token'))
//else if the mcrypt id is used if the function exits
{
if (function_exists('mcrypt_create_iv'))
{
// if the mcrypt_create_iv id is used if the function exits the set the token
$token = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
}
else{
// elseopenssl_random_pseudo_bytes is used if the function exits the set the token
$token = bin2hex(openssl_random_pseudo_bytes(32));
}
}
//action button Value
//(url()->full()) will pass the current browser url to the function[only aplicable in laravel]
$urlWithId =$fullUrl.'/'.$id;
//Charset UsedByFrom
$charset = 'UTF-8';
// Start Delete Button Arguments
//title for delete functions
$deleteFunctionTitle = 'Delete';
//class name for the deletebutton
$deleteButtonClass = 'btn-delete btn btn-xs btn-danger';
//Icon for the delete Button
$deleteButtonIcon = 'fa fa-trash';
//text for the delete button
$deleteButtonText = 'Delete Button';
//dialog Which needs to be displayes while deleting the record
$deleteConfirmationDialog = 'Are You Sure t';
$deleteButtonTooltopPostion = 'top';
// End Delete Button Arguments
// Start Edit Button Arguments
//title for Edit functions
$editFunctionTitle = 'Edit';
$editButtonClass = 'btn-delete btn btn-xs btn-primary';
//Icon for the Edit Button
$editButtonIcon = 'fa fa-pencil';
//text for the Edit button
$editButtonText = 'Edit Button';
$editButtonTooltopPostion = 'top';
// End Edit Button Arguments
// Start Show Button Arguments
//title for Edit functions
$showFunctionTitle = 'Show';
$showButtonClass = 'btn-delete btn btn-xs btn-primary';
//Icon for the Show Button
$showButtonIcon = 'fa fa-eye';
//text for the Show button
$showButtonText = 'Show Button';
$showButtonTooltopPostion = 'top';
// End Show Button Arguments
//Start Arguments for DropDown Buttons
$dropDownButtonName = 'Actions';
//End Arguments for DropDown Buttons
$showButton = '';
$showButton .='
<a href="'.$fullUrl.'/'.$id.'"class="'.$showButtonClass.'"data-toggle="tooltip"data-placement="'.$showButtonTooltopPostion.'"title="'.$showFunctionTitle.'-'.$titleValue.'">
<i class="'.$showButtonIcon.'"></i> '.$showButtonText.'
</a>
';
$editButton ='';
$editButton .='
<a href="'.$urlWithId.'/edit'.'"class="'.$editButtonClass.'"data-toggle="tooltip"data-placement="'.$editButtonTooltopPostion.'" title="'.$editFunctionTitle.'-'.$titleValue.'">
<i class="'.$editButtonIcon.'"></i> '.$editButtonText.'
</a>
';
$deleteButton='';
$deleteButton .='
<form id="form-delete-row' . $id . '" method="'.$postMethod.'" action="'.$urlWithId.'" accept-charset="'.$charset.'"style="display: inline" onSubmit="return confirm("'.$deleteConfirmationDialog.'")">
<input name="_method" type="hidden" value="DELETE">
<input name="_token" type="hidden" value="'.$token.'">
<input name="_id" type="hidden" value="'.$id.'">
<button type="submit"class="'.$deleteButtonClass.'"data-toggle="tooltip"data-placement="'.$deleteButtonTooltopPostion.'" title="'.$deleteFunctionTitle.'-'.$titleValue.'">
<i class="'.$deleteButtonIcon.'"></i>'.$deleteButtonText.'
</button>
</form>
';
$actionButtons = '';
foreach ($buttonActions as $buttonAction)
{
if ($buttonAction == 'show')
{
$actionButtons .= $showButton;
}
if ($buttonAction == 'edit')
{
$actionButtons .= $editButton;
}
if ($buttonAction == 'delete')
{
$actionButtons .= $deleteButton;
}
}
if (empty($buttonOptions))
{
return $actionButtons;
}
elseif (!empty($buttonOptions))
{
if ($buttonOptions == 'group')
{
$buttonGroup = '<div class="btn-group" role="group" aria-label="">
'.$actionButtons.'
</div>';
return $buttonGroup;
}elseif($buttonOptions == 'dropdown')
{
$dropDownButton =
'<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
'.$dropDownButtonName.'
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
'.$actionButtons.'
</div>
</div>
';
return $dropDownButton;
}else
{
return 'only <code>group</code> and <code>dropdown</code> is Available ';
}
}
}
Now all are set then open your index.blade.php
and replace your code
<td>
{{--Need the button to open up my edit form--}}
<button formaction="computers/{id}/edit">{{ trans('computers.edit') }}</button>
<input type="submit" name="update" id="update" value="Update" class="btn btn-primary">
</td>
With This
{!! Computer::tableActionButtons(url()->full(),$inventory->id,$inventory->firstName,['edit',delete,delete],'dropdown'); !!}
If you find any bugs or any issues in buttons please comment in below section to improve my helper script
VERY CAREFUL NOTE THIS IS FOR LARAVEL EXPERTS IF YOU ARE NOW BEGGINER DONT USE IT
just Watch the tutorial at
https://appdividend.com/2018/09/06/laravel-5-7-crud-example-tutorial/
https://laracasts.com/series/laravel-from-scratch-2018
Hope it saved time

My form is not populating when there is some validation error in the input data. Laravel Collective

Hope yo are all doing great.
I am using Laravel 5.3 and a package LaravelCollective for form-model binding.
I have subjects array that I want to validate and then store in database if there is no error in the input data.
The following snippets show the partial view of form, other views, rules for validations and controller code.
UserProfile.blade.php
<!-- Panel that Adds the Subject - START -->
<div class="col-md-12">
<div class="panel panel-default" id="add_Subject_panel">
<div class="panel-heading">Add Subject(s):</div>
<div class="panel-body">
{!! Form::open( array('method'=>'post', 'url'=>route('user.store.subject', 1)) ) !!}
#include('user.partials.subjects', ['buttonText'=>'Add Subject(s)'])
{!! Form::close() !!}
</div>
</div>
</div>
<!-- Panel that Adds the Subject - END -->
subjects.blade.php
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
<div class="subject-list">
<div class="input-group subject-input">
<input type="text" name="name[]" class="form-control" value="" placeholder="Subject" />
<span class="input-group-btn">
<span class="btn btn-default">Primary subject</span>
</span>
</div>
</div>
<div class="text-right">
<br />
<button type="button" class="btn btn-success btn-sm btn-add-subject"><span class="glyphicon glyphicon-plus"></span> Add Subject</button>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4 text-right">
<button type="submit" class="btn btn-primary">
{{ $buttonText }} <i class="fa fa-btn fa-subject"></i>
</button>
</div>
</div>
#push('scripts')
{{-- <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script> --}}
<script src="{{ asset('scripts/jquery-2.2.4.min.js') }}" type="text/javascript" charset="utf-8" async defer></script>
<script>
$(function()
{
$(document.body).on('click', '.btn-remove-subject', function(){
$(this).closest('.subject-input').remove();
});
$('.btn-add-subject').click(function()
{
var index = $('.subject-input').length + 1;
$('.subject-list').append(''+
'<div class="input-group subject-input" style="margin-top:20px; margin-bottom:20px;">'+
'<input type="text" name="name['+index+']" class="form-control" value="" placeholder="Subject" />'+
'<span class="input-group-btn">'+
'<button class="btn btn-danger btn-remove-subject" type="button"><span class="glyphicon glyphicon-remove"></span></button>'+
'</span>'+
'</div>'
);
});
});
</script>
#endpush
I want to validate all the subjects passed as an array to the controller using a custom created form request. the following is the code for that form request
SubjectRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SubjectRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
// dd("Rules Area");
foreach($this->request->get('name') as $key => $val)
{
$rules['name.'.$key] = 'required|min:5|max:50';
}
// dd($rules);
return $rules;
}
public function messages()
{
// dd('Message Area. . .');
$messages = [];
foreach($this->request->get('name') as $key => $val)
{
$messages['name.'.$key.'.required'] = ' Subject Name '.$key.'" is required.';
$messages['name.'.$key.'.min'] = ' Subject Name '.$key.'" must be atleast :min characters long.';
$messages['name.'.$key.'.max'] = ' Subject Name '.$key.'" must be less than :max characters.';
}
// dd($messages);
return $messages;
}
}
the following is the code for controller method I am using to store inputted array data to database.
public function storeSubjects(SubjectRequest $request)
{
$data = $request->all();
// save logic
dd($data);
}
Problem:
My form is not populating when there is some validation error in the input data.
After getting validation errors, my input fields are blank.
Problem
In subject.blade.php, your code looks like
<input type="text" name="name[]" class="form-control" value="" placeholder="Subject" />
Your fields are not populating because you have left value attribute blank.
Solution:
Pass the old value to solve your problem.
<input type="text" name="name[]" class="form-control" value="{{old('name[]')}}" placeholder="Subject" />
Use Form Model Binding instead
https://laravelcollective.com/docs/5.3/html#form-model-binding
{{ Form::model($user, [....]) }}
{{ Form::text('firstname', null, [...]) }}
{{ Form::close() }}

Laravel 4 Preview Form Submit

Any idea how to solve the following approach.
I have a form and want to display the entered data in a specific formtemplate before store it in the DB. If the entered data looks properly, the user can save the form.So I am searching for a way to display the entered data as a preview in a new window/tab first. With my code below I am not able to preview the form without saving the data in the databse. Also display the preview in a new window or tab is not possible. I guess there is no way to achieve this with php / laravel. I tried some onlick events, but no luck. As it seems like the route is prefered.
Any idea how to solve this?
My form looks like:
{{ Form::open(array('url' => 'backend/menubuilder/'.$id, 'method' => 'PUT'))}}
<section>
<div class="container">
<div class="row">
<div class="inputBox">
<div class="col-xs-12 col-md-6">
<h3>Montag</h3>
<div class="form-group">
{{Form::label('gericht_1_mo','Gericht 1')}}
{{Form::textarea('gericht_1_mo', Auth::user()->gericht_1_mo,array('class' => 'form-control'))}}
</div>
<div class="form-group">
{{Form::label('preis_1_mo','Preis', array('class' => 'col-md-6'))}}
{{Form::text('preis_1_mo', Auth::user()->preis_1_mo, array('class' => 'col-md-6'))}}
</div>
<div class="form-group mrgT55">
{{Form::label('gericht_2_mo','Gericht 2')}}
{{Form::textarea('gericht_2_mo', Auth::user()->gericht_2_mo,array('class' => 'form-control'))}}
</div>
<div class="form-group">
{{Form::label('preis_2_mo','Preis', array('class' => 'col-md-6'))}}
{{Form::text('preis_2_mo', Auth::user()->preis_2_mo, array('class' => 'col-md-6'))}}
</div>
</div>
</div>
</div>
</div>
</div>
{{Form::submit('update')}}
{{-- <input type="submit" name="preview" value="preview"> --}}
{{Form::close()}}
{{ Form::open(array('url' => 'backend/menubuilder/templatesview/'.$id, 'method' => 'POST'))}}
{{-- {{Form::submit('Preview',array('onClick' => 'target_blank'))}} --}}
<input onclick="newTab()" type="submit" name="preview" value="preview" >
{{Form::close()}}
My routes:
Route::get('backend/menubuilder/templates/{id}', 'MenuBuilderController#template');
Route::post('backend/menubuilder/templatesview/{id}', 'MenuBuilderController#preview');
My Controller:
public function preview($id)
{
$user = User::find($id);
$owner = (Auth::id() === (int) $id);
return View::make('backend/menubuilder/templatesview/tempone')->withUser($user)->withOwner($owner);
}
public function template($id)
{
$user = User::find($id);
$owner = (Auth::id() === (int) $id);
return View::make('backend/menubuilder/templates/tempone')->withUser($user)->withOwner($owner);
}

daterangepicker and codeigniter form not working

I'm using an example of bootstrap-datetimepicker in my codeigniter project.
I create a form with only the datetimepicker input.
view:
<?php // Change the css classes to suit your needs
$attributes = array('class' => '', 'id' => '');
echo form_open('/calendario/nadevent/', $attributes); ?>
<div class="form-group">
<label for="reservationtime">Fecha:</label>
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-calendar"></i>
</span>
<input type="text" name="reservationtime" id="reservationtime" class="form-control" value="<?php echo set_value('reservationtime') ?>" />
</div>
</div>
<?php echo form_submit( 'submit', 'Submit','class="btn btn-default"'); ?>
<?php echo form_close(); ?>
JS:
$('#reservationtime').daterangepicker({timePicker: true, timePickerIncrement: 30, format: 'DD-MM-YYYY hh:mm:ss', timePicker12Hour: false, separator: '/'});
The datepicker works fine but when i submit the form, I want to format the data and split into an array:
Controller:
$this->form_validation->set_rules('reservationtime', 'reservationtime', '');
$array = explode('/',set_value('reservationtime'));
Then I try to insert the values:
form_data = array(
'start' => $array[0],
'end' => $array[1]
;
But if I print the array, its empty:
Array ( [start] => [end] => )
Wha'ts wrong with the code?
Thanks for the help :)
You really not getting data from your form, can you dump the $_POST?

Yii - Error (and possible solution) validating form with clientValidation active, and using a custom container

I was creating a CActiveForm with the ClientValidation enabled, but stepped in an error when I wrapped a RadioButtonList inside a UL container.
Whenever I submited the form I get a "field cannot be empty" message, even if the radios were checked.
My form:
$form=$this->beginWidget('CActiveForm', array(
'id'=>'enrollment-form',
'enableClientValidation'=>true,
'clientOptions'=>array(
'inputContainer'=>'ul',
'validateOnSubmit'=>true,
),
));
And one of the RadioButtonLists I use:
<div id="drinks">
<?php echo $form->label($model,'drink_id',array('class' => 'title')); ?>
<?php echo $form->radioButtonList($model,'drink_id', CHtml::listData($drinks, 'id', 'name'), array('container'=>'ul', 'template' => '<li class="radio_row">{input}{label}</li>','separator' => '')); ?>
<?php echo $form->error($model,'drink_id'); ?>
</div>
Was I making something wrong?
I studied the code of the jquery.yiiactiveform.js and found that my problem was that in the function that gets the value of the inputs, the value was not taken correctly, because the ID used to identify the inputs was not set in a span, or in the checkboxes/radios themselves (the id was set in the UL container I defined):
var getAFValue = function (o) {
var type,
c = [];
if (!o.length) {
return undefined;
}
if (o[0].tagName.toLowerCase() === 'span') {
o.find(':checked').each(function () {
c.push(this.value);
});
return c.join(',');
}
type = o.attr('type');
if (type === 'checkbox' || type === 'radio') {
return o.filter(':checked').val();
} else {
return o.val();
}
};
So I solved this adding || o[0].tagName.toLowerCase() === 'ul':
var getAFValue = function (o) {
var type,
c = [];
if (!o.length) {
return undefined;
}
if (o[0].tagName.toLowerCase() === 'span' || o[0].tagName.toLowerCase() === 'ul') {
o.find(':checked').each(function () {
c.push(this.value);
});
return c.join(',');
}
type = o.attr('type');
if (type === 'checkbox' || type === 'radio') {
return o.filter(':checked').val();
} else {
return o.val();
}
};
Maybe I was just making some mistake and this solution is just a crappy workaround... but maybe this is just a bug ¿?
The HTML generated:
<form id="enrollment-form" action="/enrollment" method="post">
<div style="display:none"><input type="hidden" value="b06e1d1d796f838f30ba130f8d990034aa9fdad6" name="YII_CSRF_TOKEN" /></div>
<div id="enrollment-form_es_" class="errorSummary" style="display:none"><p>Please fix the following input errors:</p>
<ul><li>dummy</li></ul>
</div>
<div id="drinks">
<label class="title" for="EnrollmentForm_drink_id">Drinks</label>
<input id="ytEnrollmentForm_drink_id" type="hidden" value="" name="EnrollmentForm[drink_id]" />
<ul id="EnrollmentForm_drink_id">
<li class="radio_row">
<input id="EnrollmentForm_drink_id_0" value="2" type="radio" name="EnrollmentForm[drink_id]" />
<label for="EnrollmentForm_drink_id_0">Tea</label>
</li>
<li class="radio_row">
<input id="EnrollmentForm_drink_id_1" value="1" type="radio" name="EnrollmentForm[drink_id]" />
<label for="EnrollmentForm_drink_id_1">Juice</label>
</li>
</ul>
<div class="errorMessage" id="EnrollmentForm_drink_id_em_" style="display:none"></div>
</div>
I noticed that if I didn't use any container when generating the RadioButtonList, Yii aplies a "class=success" to a span. And with my UL container, that class is not generated. When I've changed the Javascript, the class success is generated again.
** The HTML generated without the inputContainer option and without the last array in radioButtonList:
<div id="drinks">
<label class="title" for="EnrollmentForm_drink_id">Bebidas</label>
<input id="ytEnrollmentForm_drink_id" type="hidden" value="" name="EnrollmentForm[drink_id]">
<span id="EnrollmentForm_drink_id">
<input id="EnrollmentForm_drink_id_0" value="2" type="radio" name="EnrollmentForm[drink_id]"> <label for="EnrollmentForm_drink_id_0">Tea</label><br>
<input id="EnrollmentForm_drink_id_1" value="1" type="radio" name="EnrollmentForm[drink_id]"> <label for="EnrollmentForm_drink_id_1">Juice</label>
</span>
<div class="errorMessage" id="EnrollmentForm_drink_id_em_" style="display:none"></div>
</div>
As you can see, Yii generates a strange span that controls if the form is valid or not, by aplying to it the class "success". If I use the inputContainer UL then this class="success" is not generated (with my workaround it is generated and it works).