Yii2 Pjax和ActiveForm在重新加载后提交不工作?

时间:2015-04-08 20:43:07

标签: javascript yii2 pjax

我正在我的提交按钮上创建一个加载指示器并附加" start"使用registerJs函数的beforeSubmit事件的过程。

第一次正常工作,但在重新加载Pjax容器后,当再次提交表单时,事件不会激活。

我将整个视图文件放在Pjax容器中,以便正确显示flash消息。

这是main.php布局文件片段:

<?php Pjax::begin([
'id' => 'pjax-container',
'enablePushState' => false,
]); ?>

<?= Alert::widget(); ?>

<?= $content; ?>

<?php Pjax::end(); ?>

这是registerJs函数,位于以下部分的main.php中:

<?php
$js = <<< 'SCRIPT'
$('#form').on('beforeSubmit', function(){
alert('Submitted...');
//$("#spinner").fadeIn();
});
SCRIPT;
$this->registerJs($js);
?>

这是activeForm:

<?php $form = ActiveForm::begin(['id' => 'form', 'options' => ['data-pjax' => true]]); ?>

<?= $form->field($model, 'name')->textInput(['type' => 'text']) ?>

<?= $form->field($model, 'email')->textInput(['type' => 'email']) ?>

<?= $form->field($model, 'subject')->textInput(['type' => 'text']) ?>

<?php
echo $form->field($model, 'message')->textArea(['rows' => 6]);

echo $form->field($model, 'verify_code')->widget(Captcha::className(), [
        'captchaAction' => 'site/captcha',
        'template' => '<div class="row"><div class="col-lg-4">{image}</div><div class="col-lg-6">{input}</div></div>',
]);
?>

<button class="btn btn-success">
<span id="spinner" style="display: none; float:left; margin-right: 26px;">
<?php
echo Spinner::widget([
'pluginOptions' => [
    'top' => '50%',
    'left' => '10px',
    'lines' => 11,
    'length' => 5,
    'width' => 3,
    'corners' => 1,
    'trail' => 100,
    'speed' => 1.25,
    'radius' => 4,
],
]);
?>
</span>
<?php echo $model->isNewRecord ? 'Send Message' : 'Update'; ?>
</button>

<?php ActiveForm::end(); ?>

我使用的是Kartik Spinner Widget (Details and Demo)

在成功提交后,Pjax加载数据容器后,有关为什么beforeSubmit事件不会激活的任何想法?

感谢。

2 个答案:

答案 0 :(得分:5)

出现此问题有几个原因。

首先,任何放在$(document).ready();内并加载到ajax被称为页面(包含页面)的代码在加载后都不会被执行。

其次,任何对外部脚本(<script src>)的引用都不保证在内联脚本之前加载。对于Yii2,这些内联脚本将在registerJs()

中注册

让Pjax与要加载的复杂脚本相关页面一起玩得很好琐碎。

解决问题的一些方法:

1)如果视图为registerJs(),那么加载了POS_READY并且位置为$(document).ready()(默认值为?)的内联脚本将包含在render()中通过renderAjax()呈现。

因此,通过render()进行渲染非常重要。这将确保内联脚本将运行。

有时(大多数情况下)您需要在静态加载时使用renderAjax(),在pjax加载页面时使用if(Yii::$app->request->getHeaders()->has('X-PJAX')) { return $this->renderAjax('myview'); } else { return $this->render('myview'); } 。在您的实例中,这是将Pjax小部件放置在布局中所必需的。您可以在以下情况下使用以下代码:

$(document).on('ready pjax:success', function(){
    // ...
});

2)编写您知道的外部脚本将在pjax调用的上下文中加载。使用:

pjax:success

这将正确加载脚本。但请记住,每次Pjax调用成功时,它都会重新加载/重新绑定脚本。遗憾的是,这可能并不理想。

另请注意,加载包含页面的外部脚本后,obj.scripts = findAll(obj.contents, 'script[src]').remove() 事件不一定会触发。见3)

3)要解决脚本订单问题,您需要从pjax.js脚本中删除以下行:

eval()

但是,这会对设置为禁用bower\yii2-pjax的浏览器产生问题(因此首先存在该行的原因)

Pjax最终会对此进行排序。您可以跟踪进度here

如果有什么不清楚,请告诉我,我会改写。

更新: Yii 2.0.7引入了更改。其中一个是将2.0.6更新为{{1}}。这使得点 3)不再必要,并使得 2)不那么重要,尽管它仍然是一件好事。

答案 1 :(得分:0)

因此。我有一个解决方案,但它与文档相矛盾......

如果你看一下实际的重定向功能(来源):

public function redirect($url, $statusCode = 302, $checkAjax = true) 
743     { 
744         if (is_array($url) && isset($url[0])) { 
745             // ensure the route is absolute 
746             $url[0] = '/' . ltrim($url[0], '/'); 
747         } 
748         $url = Url::to($url); 
749         if (strpos($url, '/') === 0 && strpos($url, '//') !== 0) { 
750             $url = Yii::$app->getRequest()->getHostInfo() . $url; 
751         } 
752  
753         if ($checkAjax) { 
754             if (Yii::$app->getRequest()->getIsPjax()) { 
755                 $this->getHeaders()->set('X-Pjax-Url', $url); 
756             } elseif (Yii::$app->getRequest()->getIsAjax()) { 
757                 $this->getHeaders()->set('X-Redirect', $url); 
758             } else { 
759                 $this->getHeaders()->set('Location', $url); 
760             } 
761         } else { 
762             $this->getHeaders()->set('Location', $url); 
763         } 
764  
765         $this->setStatusCode($statusCode); 
766  
767         return $this; 
768     } 

你可以看到它在Ajax之前检查Pjax并且有两个不同的头。在整个网络和多个网站上提到的X-Redirect标头不适用于Pjax调用。您必须检查X-Pjax-Url是否有Pjax呼叫。

我注册了自己的javascript函数来处理重定向,如下所示:

$js = <<< 'SCRIPT'
$(document).on('pjax:complete', function (event, xhr, textStatus, options) {
//$(document).ajaxComplete(function (event, xhr, settings) {
var url = xhr.getResponseHeader('X-Pjax-Url');
if (url) {
    window.location = url;
}
});
SCRIPT;
$this->registerJs($js);

由于某种原因,这本身还不够。默认情况下,源函数运行checkAjax代码,但在我从重定向代码中明确调用它之前,它将不起作用。

所以这就是我在控制器中使用的内容:

Yii::$app->response->redirect(Yii::getAlias('@web') . '/secure/dashboard/', true)->send();
return;

这已经讨论了很多次,我希望这有助于其他人。