msoa
msoa

Reputation: 1349

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

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?

Upvotes: 1

Views: 2306

Answers (3)

topher
topher

Reputation: 14860

  1. Rename one/both of your button ids. This means the event handlers will be attached to different buttons.
  2. 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.

Upvotes: 2

msoa
msoa

Reputation: 1349

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',
                )
            );
            .
            .
            .
        ?>

Upvotes: 2

Benjamin Kaiser
Benjamin Kaiser

Reputation: 2227

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.

Upvotes: 1

Related Questions