I am trying to pass the values of form inputs to a controller for validation. The values are populated in the view using an array. The problem is that I don't know how to get the necessary 'name' values from the array for the individual inputs in order to pass them through validation.
In the first view the form inputs are described this way:
<?php echo form_checkbox('study_items[]', 'Medical History', FALSE);
echo form_label('Medical History', 'Medical History');?>
<br>
<?php echo form_checkbox('study_items[]', 'Physical Exam', FALSE);
echo form_label('Physical Exam', 'Physical Exam');?>
<br>
<?php echo form_checkbox('study_items[]', 'Clinical Assessment', FALSE);
echo form_label('Clinical Assessment', 'Clinical Assessment');?>
The user only has to check the item(s) that apply to their specific need. This is submitted to the validation controller which, after successful validation, ONLY sends those items that were selected back to a view in an array like so:
$data['si_items'] = $this->input->post('study_items');
In the next view, the code for a sample input looks like this:
<?php foreach ($si_items as $si_item) {
echo $si_item. ' '. "$";
$data001 = array(
'name' => $si_item,
'id' => $si_item,
'value' => '',
'maxlength' => '10',
'size' => '50',
'style' => 'width:100px',
);
echo form_input($data001);
echo '<br>';
}
?>
and allows the user to enter a dollar amount for the items they selected to fit their need on the previous page.
As sample output of this portion of the code looks like this:
"Medical History $_______________"
"Physical Exam $_______________"
"Clinical Assessment $_______________"
where the blank is a textbox for entering the price of each item. So far, this all works perfectly to display each form input box and labels checked by the user in the previous view.
However, I'm at a loss as to how to get the 'name' for each individual input in order to validate it. The validation controller does not recognize '$si_items' as a name value. This has me stumped and there HAS to be a way to do this.
In my validation controller I want to check that each entry has a decimal value (i.e. 234.56) as the user's input.
Any ideas? Is there a more efficient way to do this?
we are missing swaths of code, but from what you have shown;\
$data['si_items'] = $this->input->post('study_items');
is the assignment of your study items (which is an array), meaning that the call in your foreach should not be
foreach ($si_items as $si_item) {
but rather
foreach ($data['si_items'] as $si_item) {
that or change your initial assignment to the following;
$si_items = $this->input->post('study_items');
Related
Im working on a piece of code to alter permissions for users of an app. Currently, each permission is added one at a time, Im revising it to be added in a faster way, being able to select multiple permissions to add at once.
The checkboxes aren't going to be the same number, since they are only the permissions the user doesn't yet have. It needs to pass an id with the permissions.
The problem is, my checkbox form doesn't appear to be sending any data to the controller. Upon submitting, it just loads a blank page with the url of the controller.
Heres the view code, that generates the checkbox form
<?php
if (!empty($lstAvailablePermissions)) {
$c=0;
echo $form->create('Administrator', array('action'=>'addPermission'));
echo $form->input('id');
foreach($lstAvailablePermissions as $key){
echo "<br>";
echo $form->input(
'permission',
array(
'id'=>$key,
'label'=>$key,
'type'=>'checkbox',
'multiple'=>'checkbox',
'value' => $key,
'name' =>'data[Administrator][permission]['.$c.']'
));
$c=$c+1;
}
echo $form->button(__('Add', true), array('type'=>'submit', 'class' => 'button', 'style'=>'padding: 2px; font-size: 12px;'));
echo $form->end();
}
?>
and the method in the controller
function AddPermission() {
if (empty($this->data)) { $this->RedirectWithFlash(__("Only POST Requests", true), "/administrators"); }
ErrorLogWarning("This is the form data sent to the controller", $this->data);
$length=count($this->data['Administrator']['permission']);
for ($i = 0; $i < $length; $i++){
$this->Acl->allow(
array('model' => 'Administrator', 'foreign_key' => $this->data['Administrator']['id']),
$this->data['Administrator']['permission'][$i]
);
}
$this->RedirectWithSuccessFlash(__("Permission added", true), array('action'=>'edit', $this->data['Administrator']['id']));
}
can anyone help me figure out whats going on? I assume ill need to loop through the data once its in the controller, but it doesn't even send the error message as of right now.
EDIT: problem appears to be fixed by adding the name property at the bottom of the form echo, which send it as an array which can be looped through in the controller.
I think the problem might be that you specify 'action'=>'addPermission' when you create the form, but your controller action is named AddPermission (capital A). Try changing to 'action'=>'AddPermission'.
Also, I think you might only get the last permission input because you're adding the permission inputs in a loop. Try indexing the inputs like this:
foreach($lstAvailablePermissions as $i => $key) {
echo "<br>";
echo $form->input(
"Administrator.{$i).permission",
I always send data from view like this ->with(array('message'=>'there is an error ')), and it works.
I want to allow the customer to edit some information, so when he/she clicks on the the edit like, this function in a controller is being executed:
public function edit($id)
{
$waitingTimes = WaitingTimes::find($id);
return View::make('waitingtimes.edit')->with(array(
'verticalMenu' => 'none',
'verticalMenuTab' => 'none',
'data' => $waitingTimes
));
}
So later in the view, I should be able to say this:
$data->startTime, $data->endTime, $data->id, $data->restaurant_id
but every time I do that, I got $data->startTime printed on the browser, but I should have got the value of the startTime attribute.
This is my view:
<div class="oneInfo">
{{ Form::text('startTime', '', array('class' => 'time ui-timepicker-input', 'id' => 'startTime', 'autocomplete' => 'off'))}}
<span class="errorMessage">
<?php
echo $errors->first('startTime');
?>
</span>
</div>
The view has an input text and I want that input text to be filled with the data that has been sent from the controller.
how could I do that please?
The Form::text() method's second parameter allows you to pass it the value to be assigned to the input element. Your form input declarations are currently setting the value of the inputs to an empty string.
The best way to handle this would be to replace your empty string with $value=null.
{{ Form::text('startTime', $value=null, array('class' => 'time ui-timepicker-input', 'id' => 'startTime', 'autocomplete' => 'off'))}}
This will automatically replace the value with your models data or the data input by the user (should validation fail and you redirect back to the form).
From the looks of things, you could also make things a bit easier for yourself by using form model binding to bind the WaitingTimes model to your form.
I'm using CakePHP's SecurityComponent. And it's very essential as it saves forms from CSRF attacks. My project has total 10-12 forms and this is my first CakePHP project. After enabling SecurityComponent I was in a bit trouble but could get rid off after some careful minutes. This is the last form of my project and seems everything is correct to me but still the form is being black holed :(. Can anybody please tell me the problem? I don't want to disable CSRF checking or SecurityComponent. Here is my view code:
<?php
echo $this->Form->create('Record');
?>
<script type="text/javascript"> var me = new MetroExam(); </script>
<div class="exam_paper">
<div class="question_box" id="q_b">
<div class="q_n_a_header">
<div class="instructions">
<b>Instructions:</b><br>
<?=$inst['value_text']; ?>
</div>
<div id="timer">Please wait</div>
</div>
<div id="q_paper">
<img id="q" style="display: none;" src="/oes/<?=$exam['path'].'?ts='.time(); ?>">
<img id="loading_img" src="/oes/img/loading.gif">
</div>
</div>
<div class="ans_box" id="a_b">
<!-- information about answer paper. !important -->
<?php
$i = 0;
//these fields are essential for evaluating ans paper
echo $this->Form->hidden('submit', array('value' => 'true'));
echo $this->Form->hidden('start_time', array('value' => ''));
echo $this->Form->hidden('end_time', array('value' => ''));
echo $this->Form->hidden('duration', array('value' => ''));
echo $this->Form->hidden('valid', array('value' => ''));
echo $this->Form->hidden('passed', array('value' => ''));
//options for all radio
$options = array(
'1' => 'A',
'2' => 'B',
'3' => 'C',
'4' => 'D'
);
if($exam['choices'] == 5){
$options['5'] = 'None';
}
$questions = (int)$exam['questions']; // 40 <= $exam['questions'] <= 100
$i = 1;
while($questions--){
echo '<div class="'.(($i%2)==1?'each_answer_even':'each_answer_odd').'" id="ans-'.$i.'">';
echo '<div class="q_number">'.($i <= 9 ? '0'.$i : $i).'</div>';
$name = 'ans'.str_pad($i, 3, '0', STR_PAD_LEFT);
$attributes = array('empty' => false, 'legend' => false, 'onclick' => 'me.answer_click('.$i.')');
echo '<div class="mcq">'.$this->Form->radio($name, $options, $attributes).'</div>';
echo '</div>';
$i++;
}
echo $this->Form->end('Submit');
?>
</div>
</div>
This is basically a MCQ exam form. Where each group has 4 or 5 radio buttons and total 40 to 100 groups in a form. I'm using CakePHP 2.4. Thanks in advance.
As per the comments, the problem appears because you are changing the hidden values of the form. The way SecurityComponent works, is that it "locks" the name of the fields, so an evildoer can't add new fields or change the values once the form is sent. But it is even more strict with the hidden values, because it locks the field name and value. So by changing it with jQuery you're blackhole-ing your own form.
There's a nice little post where I learned this, take a look at it. The author there also explains two ways of bypassing this problem. One is to disable the security for hidden fields, so the hash calculated for the token doesn't include those values... which isn't really secure...
And another solution is to modify the FormHelper, and tell it to "lock" the hidden fields names but not the values. I don't remember what version of Cake the author uses for the example, but the code given there should be practicaly the same. So with that solution, you can tell the form to not be so strict with you with an option array.
Oh, and the other option given there (this is what I normally use) (I just read it now there... I thought I figure that on my own... oh well), is to just use normal input text fields for the ones you want hidden, and add a css style like display:none.
It's up to you what you think is best. I like the css option because is simpler, and really, if someone is going to mess with my css evily (with firebug or something like that), they might just as well do it with the values of hidden fields, it doesn't require any more effort. You should take all the extra steps and verifications when handling that form submission anyway. But like I said, up to you which do you think is best for your situation.
In addition to what was already posted, here's something else what might be causing the problem: in my case, a hidden input had it's name overwritten.
$this->Form->create('ExampleModel'):
$this->Form->input('foo_bar', array(
'type' => 'hidden',
'name' => 'foo_bar',
));
As a result, the final $this->request->data had the corresponding key $this->request->data['foo_bar']. It was not within the $this->request->data['ExampleModel'] array, and that's what the problem was.
To fix the issue, I had to remove the name key from the template, making the input belong to the model's data, and then just change the controller to accept that value.
Hope this helps someone else.
Update: this would also work on a form not attached to any model, e.g.:
$this->Form->create(false, array(
'url' => '/example',
)):
Hope you are all good. I have a problem that is I use an extension i.e. select2 which shows all Products' name in the dropdown list and it works fine to me. In my database, every product has individual price. So, I want to show the sum of all selected products' price in the next of dropdown. So, I used ajax to send the product id to the controller to find the product price. Unfortunately, I can't sum all of product price because when I add new product then previous Id of product gets change then price also gets change. But I want to hold the price of products in a variable when product is selected.
the form code:
<div class="row">
<?php echo $form->labelEx($model,'item_list'); ?>
<?php
$data = CHtml::listData(Products::model()->findAll(),'id', 'name');
echo Select2::activeMultiSelect(
$model, 'item_list', $data, array(
'required' => 'required',
'style' => 'width: 270px;',
'placeholder' => 'Add Product',
'select2Options' => array(),
'ajax' => array('type'=>'POST',
'url'=>$this->createUrl('totalOrderPrice'), //url to call.
'update'=>'#price', //selector to update
'data'=>array('item_list'=>'js:this.value'),
),
)
);
?>
<?php echo $form->error($model,'item_list'); ?>
</div>
the controller code:
...
...
public $prices;
...
...
public function actionTotalOrderPrice(){
$data = Products::model()->findByPk(array('id'=>$_POST['item_list']));
$this->prices += $data->prices;
echo CHtml::tag('input', array( 'type'=>'text' , 'name'=>'Order[price]' , 'value' => $this->prices));
}
I spent a lot of time to solve this problem but anyhow couldn't. Please help someone.
Thanks in advance,
Shimul
Since I don't have products schema , I have used another model i.e User to give you can example of how it could be done.
<div class="row">
<?php
$model=User::model();
$attribute='products';
$data = CHtml::listData(Yii::app()->db->createCommand("select id, concat(RAND()*1000,':',username) as name FROM `User` ")->queryAll(),'id','name');
echo Select2::activeMultiSelect($model,$attribute, $data,
array(
'required' => 'required',
'style' => 'min-width:200px',
'placeholder' => 'Choose User',
'select2Options'=>array(
'formatResult'=>'js:format',
'formatSelection'=>'js:format',
),
'onChange'=>'js:{
var total=0;
$($(this).select2("data")).each(function(){
total+=this.text.split(":")[0]*1;
});
$("#total > label").text(total);
}',
)
);
$js_format_fun = <<<JS
function format(opt){
var price_lbl=opt.text.split(':');
return price_lbl[1];
}
JS;
Yii::app()->clientScript->registerScript('select2_format_option', $js_format_fun, CClientScript::POS_READY);
?>
</div>
<br/>
<div id="total"><strong>Total Price: </strong><label></label></div>
You will see sth like this:
The idea is to avoid ajax and add prices to names e.g product name will be of format: price:name. You split the price ,name and calculate the total as I give above.
Maybe you have to look outside YII, you can use javascript for this, out there, you can find JS libraries and frameworks who can help you to save variables and calculate the sum, for example CanJS has can.compute which has an observable nature so it fires events everytime the sum changes and you can implement function who does the calculation or KnockoutJS too has computed values this two libs are my favorite (I use canjs) they are lightweight and effecient and you can use them just where you need, hope this can help you
Store it in user session
Yii::app()->session['products_prices'] += $data->prices
But you will face a problem when you remove items from your list
I don't know this widget but there is certainly a .seralize() function witch will serialize all selected items id into a json string array.
You then can then use this array in a "in" Condition to sum your total.
I am trying to build in a "search" box on a results page in my cakephp app. The page uses the cakePHP pagination component to show and "page" results. This is perfect, but I am having difficulties to get the next part to work.
The desired outcome:
A cakephp form (post) with an input box and a couple of select boxes, including a date selector so that I can select between dates. The user should be able to populate these fields and submit
On submit, the user selection should change the cakePHP pagination conditions in the controller
In the view I want the pagination bar to keep record of the user selection, so that when I filter through different pages, it keeps the users search. I understand this can be achieved using $this->passedArgs, hence why I am using post and not get.
The code:
// Form:
<?php
echo $this->Form->create('search', array('class' => false));
echo $this->Form->input('searchFor');
echo $this->Form->input('dateFrom');
echo $this->Form->input('dateTo');
echo $this->Form->end();
?>
// Controller:
if($this->request->is("post")) {
$filters = $this->request->data["search"];
$this->passedArgs["searchFor"] = $filters["searchFor"];
$this->passedArgs["dateFrom"] = $filters["dateFrom"]." 00:00:00";
$this->passedArgs["dateTo"] = $filters["dateTo"]." 00:00:00";
// Assign search parameters:
if($this->passedArgs["searchFor"] != "") {
$conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
}
$conditions["Model.created >="] = $this->passedArgs["dateFrom"];
$conditions["Model.created <="] = $this->passedArgs["dateTo"];
} else {
$conditions = array("Result.status_id >=" => 12);
}
$this->paginate = array(
'conditions' => $conditions,
'order' => array('Result.created ASC'),
'limit' => 20
);
$this->set("results",$this->paginate("Model");
// The view file:
<?php
$this->Paginator->options(array('url' => $this->passedArgs));
?>
Where I am now:
The initial page loads with all of the results
When I populate the search boxes it does return my results
The problem:
I am convinced the way I am doing it is incorrect as I now need to do 2 checks, a) being if results has been posted and b) check if there is passedArgs available. I am 100% convinced this is not the right way of doing it.
Let's say I have 2 free form fields for search, say name and surname, if I leave surname blank my url would be written as below, and this does not look or appear to be correct. That means I have to assign default values to ensure the items below does not happen, which does not appear to be very dynamic.
http://localhost/site/controller/action/surname:0/name:John/date:0/
On refresh it says the page does not exist because the posted values is not available anylonger.
usually I proceed like this in the controller:
//transform POST into GET
if($this->request->is("post")) {
$url = array('action'=>'index');
$filters = array();
if(isset($this->data['searchFor']) && $this->data['searchFor']){
//maybe clean up user input here??? or urlencode??
$filters['searchFor'] = $this->data['searchFor'];
}
//redirect user to the index page including the selected filters
$this->redirect(array_merge($url,$filters));
}
$conditions = array();
//check filters on passedArgs
if(isset($this->passedArgs["searchFor"])){
$conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
}
//paginate as normal
$this->paginate = array(
'conditions' => $conditions,
'order' => array('Result.created ASC'),
'limit' => 20
);
The idea is to transform the POST sent by your form into GET. so you wont have problems with the paginator nor the refresh
Hope this helps
What you want can be done a lot more simple and DRY by using this search plugin.
It automates what you want more or less plus it already can do more than your code.
So I suggest you to use the plugin directly or take a look at it how it does the trick. :)