Renderpartial() Don't Generate New Jquery Code For AjaxSubmitButton - php

There is two actions in the controller:
CProfile:
public function actionCProfile()
{
$model=$this->loadModel(Yii::app()->user->id);
$model->scenario = 'updateProfile';
$this->performAjaxValidation($model);
if(isset($_POST['User'])){
$model->attributes=$_POST['User'];
if($model->validate())
if($model->save()){
if(Yii::app()->request->isAjaxRequest)
Yii::app()->end('saved');
else{
Yii::app()->user->setFlash('status','saved');
}
}
if(Yii::app()->request->isAjaxRequest)
if(!$model->validate())
Yii::app()->end('!validate');
}
if(Yii::app()->request->isAjaxRequest)
$this->renderPartial('_cprofile',array('model'=>$model));
else
$this->render('update',array('model'=>$model,'form'=>'_cprofile'));
}
And CPass:
public function actionCPass()
{
$model = $this->loadModel(Yii::app()->user->id);
$model->scenario = 'CPass';
$this->performAjaxValidation($model);
if(isset($_POST['User'])){
$model->attributes = $_POST['User'];
if($model->validate()){
if($model->verifyPassword($model->currentPass)){
$model->changePassword($model->newPass);
Yii::app()->end('changed');
}
}
}
if(Yii::app()->request->isAjaxRequest)
$this->renderPartial('_cpass',array('model'=>$model));
else
$this->render('update',array('model'=>$model,'form'=>'_cpass'));
}
And three view files:
update.php:
<?php
$cs = Yii::app()->clientScript;
$cs->registerCssFile('/x/css/myDetailview.css');
$cs->registerCssFile('/x/css/upanel/user-profile.css');
$url = Yii::app()->getBaseUrl().'/js/upanel.js';
$cs->registerScriptFile($url,CClientScript::POS_HEAD);
?>
<div id='user-profile-menu'>
<ul>
<li><?php echo CHtml::link('profile',Yii::app()->createUrl('/upanel/user/CProfile'),array('id'=>'profile-change-link')) ?></li>
<li><?php echo CHtml::link('change email',Yii::app()->createUrl('/upanel/user/CPass'),array('id'=>'pass-change-link')) ?></li>
</ul>
</div>
<div id='container'>
<?php $this->renderPartial($form,array('model'=>$model)); ?>
</div>
_cprofile.php:
<div class="form" >
<?php
$form = $this->beginWidget('CActiveForm',array(
'id'=>'change-profile-form',
'enableAjaxValidation'=>true,
'enableClientValidation'=>true,
'action' => 'index.php?r=upanel/user/cprofile',
'method' => 'post',
'clientOptions'=>array(
'validateOnSubmit'=>true,
'validateOnChange'=>true,
'validateOnType'=>false,
),
));
?>
.
.
.
<div class="row">
<?php
$url=Yii::app()->createUrl('upanel/user/CProfile');
echo CHtml::ajaxSubmitButton('update',$url,
array(
'type'=>'POST',
'data'=>"js:$('#change-profile-form').serialize()",
'success'=>'callback',
'beforeSend'=>'before',
),
array(
'id'=>'update-button',
'class'=>'submit-button',
)
);
?>
</div>
<?php $this->endWidget() ?>
<?php echo $form->errorSummary($model,'resolve following errors: ') ?>
_cpass.php:
<div class="form">
<?php
$form = $this->beginWidget('CActiveForm',array(
'id'=>'change-pass-form',
'enableAjaxValidation' => 'true',
'action' => Yii::app()->createUrl('upanel/user/CPass'),
'method' => 'POST',
'clientOptions' => array(
'validateOnSubmit' => true,
'validateOnChange' => true,
'validateOnType' => false,
)
));
?>
.
.
.
<div class="row">
<?php
$url=Yii::app()->createUrl('upanel/user/CPass');
echo CHtml::ajaxSubmitButton('update',$url,
array(
'type'=>'POST',
'data'=>"js:$('#change-pass-form').serialize()",
'success'=>'callback',
'beforeSend'=>'before',
),
array(
'id'=>'update-button',
'class'=>'submit-button',
)
);
?>
</div>
<?php $this->endWidget() ?>
</div> <!-- End Password Form -->
<?php echo $form->errorSummary($model) ?>
*Edit #1: *
See, i have a view page named update.php that in this page there is two links:
<div id='user-profile-menu'>
<ul>
<li><?php echo CHtml::link('profile',Yii::app()->createUrl('/upanel/user/CProfile'),array('id'=>'profile-change-link')) ?></li>
<li><?php echo CHtml::link('Change Password',Yii::app()->createUrl('/upanel/user/CPass'),array('id'=>'pass-change-link')) ?></li>
</ul>
The following JQuery code runs exsist actions in controller, that result is a renderpartial() one of these view files: _cpass.php or _profile.php
$('document').ready(function(){
$('#profile-change-link').click(function(){
var link = $(this).attr('href');
$('#container').load(link);
return false;
})
$('#pass-change-link').click(function(){
var link = $(this).attr('href');
$('#container').load(link);
return false;
})
});
In the controller CProfile action defined as default action. with this action there is no any problem in which of POST and Ajax methods.
But main problem: after that _cpass.php view replaced with _profile and have send the exist form in the _profile to CPass action for processing encountered with problem.
The problem is this:
Output of following code as expected is 1:
public function actionCPass()
{
$model = $this->loadModel(Yii::app()->user->id);
$model->scenario = 'CPass';
$this->performAjaxValidation($model);
if (1==1)
Yii::app()->end('1');
}
But output of following code is not that thing we expected. Returned value is a renderpartial() of _profile view. while there is no any related code about _cprofile view in CPass action code!
public function actionCPass()
{
$model = $this->loadModel(Yii::app()->user->id);
$model->scenario = 'CPass';
$this->performAjaxValidation($model);
if(isset($_POST['User'])){
$model->attributes = $_POST['User'];
if($model->validate()){
if($model->verifyPassword($model->currentPass)){
$model->changePassword($model->newPass);
Yii::app()->end('changed');
}
}
}
if(Yii::app()->request->isAjaxRequest)
$this->renderPartial('_cpass',array('model'=>$model));
else
$this->render('update',array('model'=>$model,'form'=>'_cpass'));
}
Output of above code:
<div class="form" >
<form id="change-profile-form" action="index.php?r=upanel/user/cprofile" method="post">
.
.
.
<div class="row">
<input id="update-button" class="submit-button" type="submit" name="yt0" value="update" /> </div>
</form>
</div> <!-- End The Profile Form -->
<div id="change-profile-form_es_" class="errorSummary" style="display:none">resole following errors:
<ul><li>dummy</li></ul></div>
Now understand what is the issue? The problem there is only with Ajax request and when disabled the javascript in the browser the CPass action acts truly.
Excuseme if firstly explained very bad.
Thanks friends
*Edit #2: *
When debugging with Firebug i noticed that snippet of JQuery code didn't change.
When firstly in default action of controller this code:
$this->renderPartial('_cprofile',array('model'=>$model));
be run following JQuery code will create: (As you know following code is related to CHtml::ajaxSubmitButton)
$('body').on('click','#update-button',function(){jQuery.ajax({'type':'POST','data':$('#change-profile-form').serialize(),'success':callback,'beforeSend':before,'url':'/x/index.php?r=upanel/user/CProfile','cache':false});return false;});
So when _cpass view renders with renderpartial() method in CPass action, the above JQuery code must be changed but will not change. I guess it must be the following code:
$('body').on('click','#update-button',function(){jQuery.ajax({'type':'POST','data':$('#change-cpass-form').serialize(),'success':callback,'beforeSend':before,'url':'/x/index.php?r=upanel/user/CPass','cache':false});return false;});
So my problem is with JQuery code generated for CHtml::ajaxSubmitButton. Can anyone help me?

Solved
With applying uniqueId for ajaxSubmitButton and setting CController::processOutput() to True in Controller Action solved.
Summary Code:
actionCPass:
public function actionCPass()
{
$model = $this->loadModel(Yii::app()->user->id);
$model->scenario = 'CPass';
$this->performAjaxValidation($model);
if(isset($_POST['User'])){
$model->attributes = $_POST['User'];
if($model->validate()){
if($model->verifyPassword($model->currentPass)){
$model->changePassword($model->newPass);
Yii::app()->end('changed');
}
}
}
if(Yii::app()->request->isAjaxRequest)
$this->renderPartial('_cpass',array('model'=>$model),false,true);
else
$this->render('update',array('model'=>$model,'form'=>'_cpass'));
}
_cpass.php:
.
.
.
<?php
echo CHtml::ajaxSubmitButton(
'update',
Yii::app()->createUrl('upanel/user/CPass'),
array(
'type'=>'POST',
'data'=>"js:$('#change-pass-form').serialize()",
'success'=>'callback',
'beforeSend'=>'before',
),
array(
'id'=>'update-button'.uniqid(),
'class'=>'submit-button',
)
);
.
.
.
?>

Rename one/both of your button ids. This means the event handlers will be attached to different buttons.
Use renderPartial('view.path',array(parameter_array),false,true); when returning a view via Ajax. The last parameter of CController::renderPartial() calls CController::processOutput() which inserts the required client scripts at appropriate places.

I think I understand your problem, you are wondering why the page does not have the surrounding <div id='profile-container'> and </div>.
I think this may have something to do with the render functions only being able to run once per view called (so it only renders the inside view), you can test this by removing the renderPartial from the update page and see if it prints the blank div.
One way you could get around this is to instead of doing the two renders, always call each page (even in the ajax requests) but pass an extra attribute if it was an ajax request. Then on each of the pages begin and end a custom widget that contains the surrounding template you want on those pages (or just write it in manually).
Example:
controller
public function actionCProfile()
{
// ... same as your example
if(Yii::app()->request->isAjaxRequest){
$this->renderPartial('_cprofile',array('model'=>$model, 'wasAjax'=>false));
} else {
$this->renderPartial('_cprofile',array('model'=>$model, 'wasAjax'=>true));
}
}
then in your view just check if wasAjax is true, if it is then print the surrounding div (or extra elements). If this is big or could change later on, put it in a custom widget.

Related

Having Issues Invoking Actions Of Controller On Button Click

I'm having a problem calling an action in a controller upon button click. So the controller is generated by Gii. All of its actions are the default ones generated by Gii, except for the actionCreate().
Here is the relevant code ::
class ProductsController extends Controller {
public function actionCreate() {
$model = new Products;
if (isset($_POST['params'])) {
// $model->attributes = $_POST['Products'];
//if ($model->save())
// $this->redirect(array('view', 'id' => $model->id));
echo 'Yes Working';
}
$this->render('create', array(
'model' => $model,
));
}
As its clear from the above code snippet this action is calling the view named create.php.
Here is create.php::
<div class="page">
<div class="container">
<div class="row">
<h2>Create Products</h2>
<?php echo $this->renderPartial('_form', array('model' => $model)); ?>
</div>
</div>
And here is the partially rendered form.
<?php
$form = $this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'id' => 'products-form',
'action' => Yii::app()->createUrl('products/create'),
'enableAjaxValidation' => false,
));
?>
<div class="form-actions">
<?php
echo CHtml::submitButton('Create', array(
'submit' => 'EasyAesthetics/index.php/products/create',
'params' => '1'
));
?>
</div>
<?php $this->endWidget(); ?>
Now what I want is that upon clicking the button 'Create', it would call the actionCreate() method in the ProductsController. Right now the button is working and I'm being redirected to /demoProject/index.php/products/create, but the echo 'Yes Working' is not displaying.
Can anyone please show me how to achieve this. How can i invoke the create action again with just a button and just a 1 in the $_POST array.
I need to do this so that on clicking create the actionCreate() method will call the relevant components to create the necessary products.
if your "var_dump()"ed your "$_POST" , you would see sensorario answer.
and also you can set your froms send method to post if still not sending post.
$form = $this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'id' => 'products-form',
'action' => Yii::app()->createUrl('products/create'),
'enableAjaxValidation' => false,
'method' => 'post',
));
?>
or get your parameter like this(this sets by $_REQUEST):
$param = Yii::app()->request->getParam('Products' , null);
Take a look at the code generated by your form. When you have model called "Hello" with a field called "world", your form field will be
<input type="text" name="Hello[world]">
Try to change your action in this way:
class ProductsController extends Controller {
public function actionCreate() {
$model = new Products;
if (isset($_POST['Products'])) {
echo 'Yes Working';
}
$this->render('create', array(
'model' => $model,
));
}
}
Pay particular attention to these two lines:
$model = new Products;
if (isset($_POST['Products'])) {
Fields will takes the same name of model. In case of more models:
<input type="text" name="Model1[field1]">
<input type="text" name="Model1[field2]">
<input type="text" name="Model21[field2]">
<input type="text" name="Model2[field2]">
and so on ...

Passing PHP Variable to controller and get it back

I have a variable and I want to update the value in the controller and render a part of the page based on the value.
This works very well in the first time but the variable doesn't get the value, stay with the first. Here my code:
Model:
public function actionCreate()
{
$model=new CadTeste;
$teste=1;
if(isset($_POST['CadTeste']))
{
$model->attributes=$_POST['CadTeste'];
if($model->save())
$this->redirect(array('view','id'=>$model->icd_teste));
}
$this->render('create',array(
'model'=>$model,
'teste'=>$teste,
));
}
Form:
<div id="data">
<?php $this->renderPartial('_ajaxContent', array('teste'=>$teste)); ?>
</div>
<?php
echo CHtml::ajaxSubmitButton('Alterar Num',CController::createUrl('CadTeste/UpdateAjax'),
array('type'=>'POST',
'data' => array('teste'=> $teste),
'update' => '#data'
)
); ?>
The Controler
public function actionUpdateAjax()
{
$teste = $_POST['teste'];
$teste += 10;
$this->renderPartial('_ajaxContent', array('teste'=>$teste), false, true);
}
And the _ajaxContent
<?php echo $teste; ?>
Every time I click on the button I get the value "11" instead of "11, 21, 31, 41".
How can I do that? Should I change the value every time in the controller?
Try Using Sessions . This Works for me
View File
<?php Yii::app()->session['teste']=$teste ?>
<div id='data'>
<?php $this->renderPartial('_ajaxContent', array('teste'=>$teste)); ?>
</div>
<?php
echo CHtml::ajaxSubmitButton('Alterar Num',$this->createUrl('CadTeste/UpdateAjax'),
array('type'=>'POST',
// 'data' => array('teste'=> $teste),
'update' => '#data'
)
); ?>
Your Controller
public function actionUpdateAjax()
{
$teste = Yii::app()->session['teste'];
$teste += 10;
$this->renderPartial('_ajaxContent', array('teste'=>$teste));
unset(Yii::app()->session['teste']);
Yii::app()->session['teste']=$teste;
}
And Your Model As it Is
public function actionCreate()
{
$model=new CadTeste;
$teste=1;
if(isset($_POST['CadTeste']))
{
$model->attributes=$_POST['CadTeste'];
if($model->save())
$this->redirect(array('view','id'=>$model->icd_teste));
}
$this->render('create',array(
'model'=>$model,
'teste'=>$teste,
));
}
Not sure if this is your problem, but renderPartial() does not play well with AJAX. It is a known Yii issue:
http://www.yiiframework.com/forum/index.php/topic/24699-yii-20-ajaxrenderpartial-conflict/
Try using this for the view:
<?php
echo CHtml::ajaxSubmitButton('Alterar Num',CController::createUrl('CadTeste/UpdateAjax',array('teste'=>$teste)),
array('type'=>'POST',
'update' => '#data'
)
); ?>
This for the controller:
public function actionUpdateAjax($teste)
{
$teste += 10;
$this->renderPartial('_ajaxContent', array('teste'=>$teste));
}
This way you can POST to action/ajaxupdate/teste/1
Its called Parameter Binding, the parameter in $teste is populated automatically from the url, if it's not present, it will give you an error. (You could put a default value $teste=1 to make it optional)

When ajaxVar initialized in CActiveForm

About CActiveForm in document is:(clientOptions section)
ajaxVar: string, the name of the parameter indicating the request is an AJAX request. When the AJAX validation is triggered, a parameter named as this property will be sent together with the other form data to the server. The parameter value is the form ID. The server side can then detect who triggers the AJAX validation and react accordingly. Defaults to 'ajax'.
Now take a look in my example:
Summary: i have a form with two fields mail and newEmail, i submitted form via ajaxSubmitButton(if you need form code tell me put it). In following i get var_dump($_POST) content in two state:
First: Following var_dump($_POST) is for when a field(newEmail) is left empty:
array
'User' =>
array
'email' => string 'user#gmail.com' (length=14)
'newEmail' => string '' (length=0)
Second: Following var_dump($_POST) is for when all the fields are filled:
array
'User' =>
array
'email' => string 'user#gmail.com' (length=14)
'newEmail' => string 'admin#gmail.net' (length=19)
'ajax' => string 'email-form' (length=10)
'yt0' => string 'update' (length=18)
As you see only when all fields are filled the ajaxVar(ajax) exist in $_POST. When ajaxVar(ajax) initialized in CActiveForm?
Edit
email-form:
<?php
<div class="form">
<?php $form = $this->beginWidget('CActiveForm',array(
'id'=>'email-form',
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
'focus'=>'input[type="email"]:first',
)
)); ?>
<div class="row">
<?php echo $form->label($model,'email') ?>
<?php echo $form->textField($model,'email') ?>
<?php echo $form->error($model,'email') ?>
</div>
<div class="row">
<?php echo $form->label($model,'newEmail') ?>
<?php echo $form->textField($model,'newEmail') ?>
<?php echo $form->error($model,'newEmail') ?>
</div>
<hr>
<div class="row">
<?php echo CHtml::ajaxSubmitButton(
'update',
Yii::app()->createUrl('upanel/user/CEmail'),
array(
'dataType'=>'json',
'type' => 'POST',
'data' => "js:$('#email-form').serialize()",
'success'=>'function(data){
if(data.status=="success")
{
//alert(data.status);
hideFormErrors(form="#email-form");
callback(status=data.status);
}else{
formErrors(data,form="#email-form");
}
}',
'beforeSend'=>'before',
),
array(
'id' => 'update-button'.uniqid(),
'class'=>'submit-button'
)
);
?>
</div>
<?php $this->endWidget() ?>
</div>
<?php echo $form->errorSummary($model,'please solve following errors:') ?>
actionCEmail:
public function actionCEmail()
{
/*ob_start();
var_dump($_POST);
$log=ob_get_contents();
$fp = fopen('data.html', 'w');
fwrite($fp, $log);
fclose($fp);
Yii::app()->end();*/ //This block active whenever i want see the $_POST content
$model = $this->loadModel(Yii::app()->user->id);
$model->scenario = 'CEmail';
$this->performAjaxValidation($model,'email-form');
if(Yii::app()->request->isAjaxRequest)
$this->renderPartial('_cemail',array('model'=>$model),false,true);
else
$this->render('update',array('model'=>$model,'form'=>'_cemail'));
}
protected function performAjaxValidation($model,$form)
{
if(isset($_POST['ajax']) && $_POST['ajax']===$form)
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
ajaxVar
initialized onsubmit if 'validateOnSubmit'=>true,. Try to use validateOnChange=>true and show your cactiveform code when init it.
And really stop invent "a bycicle".
Try to read http://learnyii.blogspot.com/2010/12/yii.html if you didnt understand my code in previous question.
I showed you working code of ajax validation which i use on working project. And with that method your $_POST will update on change of all fields with JSON object wich will contain errors for form.
Stop flooding community. Regards.
In your action:
public function actionCEmail()
{
$model = $this->loadModel(Yii::app()->user->id);
$model->scenario = 'CEmail';
if(Yii::app()->request->isAjaxRequest)
{
$error = CActiveForm::validate($model);
if($error!='[]')
{
echo $error;
Yii::app()->end();
}
}
if(isset($_POST['CEmailForm']))
{
//put form name in POST above
//do whatever you need with model here
//save / edit etc.
//in the end
echo CJSON::encode(array(
'status'=>'success',
));
Yii::app()->end();
}
if(Yii::app()->request->isAjaxRequest) //check renders
$this->renderPartial('_cemail',array('model'=>$model),false,true);
else
$this->render('update',array('model'=>$model,'form'=>'_cemail'));
}
In your view submit button:
<?php echo CHtml::ajaxSubmitButton ("Save", Yii::app()->request->url, array (
'dataType' => 'json',
'type'=>'post',
'success' =>
'js:function (data) {
if(data.status=="success"){
//do whatever you need on success
//show flash/notification
};
}
else {//show errors here
$.each(data, function(key, val) {
$("#YourFormIDhere #"+key+"_em_").text(val);
$("#YourFormIDhere #"+key+"_em_").css(\'display\',\'block\');
});
//can show error summarry here or custom notifications
};
}',
), array (
'id' => 'yourbuttonid_submit_'.rand(1,255), // Need a unique id or they start to conflict with more than one load.
));?>
Try to do like this. It works. Keep it simple. You lost 2? days to validation of 2 fields.
I just made this on my changepassword form. It took me 5 minutes.
My post when trying to save with default empty field:
{"UserChangePassword_verifyPassword":["Required field","Retype Password is incorrect."]}
Make like this and dont loose time. Regards.

zf2 form validation (zfcAdmin and BjyAuthorize related)

I'm facing validation problems integrating my custom module in zfcAdmin and BjyAuthorize.
My form class:
...
$formOptions = $this->settings->getFormSettings();
foreach ($formOptions as $field){
if (isset($field['field']))
$this->add($field['field']);
}
...
My filter class:
$formOptions = $this->settings->getFormSettings();
foreach ($formOptions as $filter){
if (isset($filter['filter']))
$this->add($filter['filter']);
}
...
Fields, filters and other options are retrieved from config file.
Basically everything works fine: form data can be added, edited or deleted from db.
Also after the zfcAdmin module installation no problem rose. Everything works fine using both 'site/mymodule' route and 'site/admin/mymodule' route: i can still add, edit and delete items from db.
Here the problem: I need some form elements (a Select in this particular case) editable/viewable only by administrator. (I can write a new controller/entity class 'ad hoc' for admin but i would like to use the same code for the whole site.)
I installed and configured bjyoungblood/BjyAuthorize module: it allowed me to display some form elements/fields only to admin but when i'm in edit mode a form validation error is displayed: "Value is required and can't be empty"
Here the code:
//view/mymodule/mymodule/update.phtml
<div id="page" style="margin-top: 50px;">
<?php if (isset($this->messages) && count($this->messages) > 0 ): ?>
<?php foreach ($this->messages as $msg): ?>
<div class="alert alert-<?php echo $this->escapeHtmlAttr($msg['type']); ?>">
<?php if (isset($msg['icon'])) echo '<i class="'.$this->escapeHtmlAttr($msg['icon']).'"></i> '; ?><?php echo $this->escapeHtml($msg['message']); ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
<?php
$title = 'Edit Item';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>
<?php
$form = $this->form;
$form->setAttribute('action', $this->url($this->route . 'mymodule/update', array('action' => 'update', 'id' => $this->id )));
$form->prepare();
$form->setAttribute('method', 'post');
$input = $form->getInputFilter();
?>
<?php echo $this->form()->openTag($form) ?>
<dl class="zend_form">
<?php foreach ($form as $element): ?>
<?php
//CHECK USER PRIVILEDGES
$elName = $element->getName();
$elResource = isset($this->form_options[$elName]['auth']) ? $this->form_options[$elName]['auth']['resource'] : "userresource";
$elPrivilege = isset($this->form_options[$elName]['auth']) ? $this->form_options[$elName]['auth']['privilege'] : "view";
//SHOW THE ELEMENT IF ALLOWED
if($this->isAllowed($elResource, $elPrivilege)):
?>
<?php if ($element->getLabel() != null): ?>
<dt><?php echo $this->formLabel($element) ?></dt>
<?php endif ?>
<?php if ($element instanceof Zend\Form\Element\Button): ?>
<dd><?php echo $this->formButton($element) ?></dd>
<?php elseif ($element instanceof Zend\Form\Element\Select): ?>
<dd><?php echo $this->formSelect($element) . $this->formElementErrors($element) ?></dd>
<?php else: ?>
<dd><?php echo $this->formInput($element) . $this->formElementErrors($element) ?></dd>
<?php endif ?>
<?php else: ?>
<?php
?>
<?php endif ?>
<?php endforeach ?>
</dl>
<?php echo $this->form()->closeTag() ?>
</div>
<div class="clear-both"></div>
My controller action
//controller
public function updateAction(){
$messages = array();
$id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
$form = $this->getServiceLocator()->get('FormItemService');
$itemMapper = $this->getItemMapper();
$item = $itemMapper->findById($id);
$form->bind($item);
$request = $this->getRequest();
if($request->isPost()){
$form->setData($request->getPost());
if ($form->isValid()) {
die('c');//never here
$service = $this->getServiceLocator()->get('mymodule\Service\Item');
if ( $service->save($form->getData()) )
{
$messages[] = array(
'type' => 'success',
'icon' => 'icon-ok-sign',
'message' => 'Your profile has been updated successfully!',
);
}
else
{
$messages[] = array(
'type' => 'error',
'icon' => 'icon-remove-sign',
'message' => 'Profile update failed! See error messages below for more details.',
);
}
}else{
var_dump($form->getMessages());//Value is required and can't be empty
}
}
return array(
'messages' => $messages,
'form' => $form,
'id' => $id,
'form_options' => $this->getServiceLocator()->get('mymodule_module_options')->getFormSettings(),
'route' => $this->checkRoute($this->getEvent()->getRouteMatch()->getmatchedRouteName())
);
}
If user is not allowed to view the resource, the element is not echoed. So $request->getPost() has no value for that form element and an error is returned by isValid().
Has anyone solved a similar problem or can anyone point me to the right direction?
Thanks
The problem is that you don't do any security check in your FormFilter class, where you define your required fields.
The $form->isValid() function checks the posted data against those filter elements. So it's not enough to prevent the 'echo field' in your view, you still need to apply the security check to the filter element.
One other approach would be to make two forms one for the front end and one for the admin. Since the one for the admin will have the same fields plus one extra select field you can make the admin form extends the front end one. E.g.
class myForm
{
public function __construct(...)
{
// add fields and set validators
}
}
and the admin form could be:
class MyAdminForm extends myForm
{
public function __construct(...)
{
parent::__construct(...);
// add the extra field and extra validator
}
}
In that way even if you edit the front end form (or validators) the back end will always be up to date.
Hope this helps :),
Stoyan

Infinite loop trying to validate/save

I'm using Yii framework to create a really simple 1 text-area field and 2 hidden inputs with predefined values sent from the server.
The way it should work is as expected, I mean, you write something on that text-area and you click on the send button. An ajax validation is made (only requisite for the text-area is that is shouldn't be empty) and if validated, save the data and redirect to some other page.
The problem is that it won't save any data if validation error was triggered.
I mean, if I go to the page, write something and hit on the send button, data will be saved and I'll be redirected correctly. But if I go to the page, hit the send button (without typing anything in the text-area), wait for the error to appear (note that this is done via ajax, so no page-reload here), write something and hit send again Yii is going to start making a request after a request in an infinite loop.
I already have checked the data being sent, and everything is fine (both data and action-url).
Here is my Controller code
public function actionView($id)
{
$user = Usuario::model()->findByAttributes(
array(
'nick'=>Yii::app()->user->getId()
)
);
$dataProvider=new CActiveDataProvider('Mensaje', array(
'criteria'=>array(
'with'=>array('usuario', 'usuario.detallesusuario'),
'condition'=>'Tema_idtema='.$id
),
'pagination'=>array(
'pageSize'=>1000,
),
));
$this->render('view',array(
'model'=>$this->loadModel($id),
'usuario_id'=>$user->idusuario,
'tema_id'=>$id,
'dataProvider'=>$dataProvider,
));
}
public function actionCreateMessage(){
$model=new Mensaje;
$this->performAjaxValidation($model);
if(isset($_POST['Mensaje']))
{
$model->attributes=$_POST['Mensaje'];
$model->fecha_hora=new CDbExpression('NOW()');
$model->save();
$this->redirect(array('view', 'id'=>$model->Tema_idtema));
}
}
And the code from the View
<?php
$model = new Mensaje();
echo $this->renderPartial('_mensaje_form', array(
'model'=>$model,
'usuario_id'=>$usuario_id,
'tema_id'=>$tema_id,
),
false, //return instead of echo
true //post-process
);
?>
Here is the "_mensaje_form" code
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'mensaje-form',
'action'=>CHtml::normalizeUrl(array('tema/createMessage')),
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
'validateOnChange'=>false,
'validateOnType'=>false,
),
)); ?>
<?php echo $form->errorSummary($model); ?>
<div class="row" style="margin:20px 5px 0 176px;">
<?php echo $form->labelEx($model,'mensaje'); ?>
<?php echo $form->textArea($model,'mensaje',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'mensaje'); ?>
<?php echo $form->hiddenField($model, 'Tema_idtema', array('value'=>$tema_id)); ?>
<?php echo $form->hiddenField($model, 'Usuario_idusuario', array('value'=>$usuario_id)); ?>
</div>
<div class="row buttons" style="margin:-3px 0 -8px 176px;">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Responder' : 'Guardar'); ?>
</div>
<?php $this->endWidget(); ?>
Any idea why I'm getting that loop?
This might help you,
http://www.yiiframework.com/forum/index.php/topic/10427-ajax-clientscript/
in your view, the last parameter "true" in renderPartial may be the problem.
My guess (a bit long shot) that form id in your preformAjaxValidation() might be wrong, so it causes the loop! since it won't get in the body of the if and hence executes Yii::app()->end(); !!
Check it in your controller:
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='exact-form-id')//should be mensaje-form
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}

Categories