Yii2 Pjax 和 ActiveForm beforeSubmit 在重新加载后不起作用?

Yii2 Pjax and ActiveForm beforeSubmit not working after reload?

我正在我的提交按钮上创建一个加载指示器,并使用 registerJs 函数将 "start" 过程附加到 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);
?>

这里是活动表单:

<?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 事件不会触发的任何想法?

谢谢。

出现这个问题有几个原因。

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

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

注册

让 Pjax 很好地处理复杂的脚本依赖页面来加载是微不足道的。

解决您问题的几件事:

1) 使用 registerJs() 加载并设置位置 POS_READY(默认?)的内联脚本将包含在 $(document).ready() 如果视图是通过 render().

呈现的

因此通过 renderAjax() 渲染很重要。这将确保内联脚本 运行.

有时(大多数时候)您需要在静态加载时使用 render(),在 pjax 加载页面时使用 renderAjax()。在您的实例中,这是将 Pjax 小部件放置在布局中所必需的。您可以针对这些情况使用以下代码:

if(Yii::$app->request->getHeaders()->has('X-PJAX'))
{
    return $this->renderAjax('myview');
}
else
{
    return $this->render('myview');
}

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

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

这将正确加载脚本。但请记住,每次 Pjax 调用成功时,它都会 reload/rebind 脚本。不幸的是,这可能不是我们想要的。

另请记住,pjax:success 事件不一定会在包含页面的外部脚本加载后触发。参见 3)

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

obj.scripts = findAll(obj.contents, 'script[src]').remove() 

然而,这将导致设置为禁用 eval() 的浏览器出现问题(因此该行首先存在的原因)

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

如果有任何不清楚的地方,请告诉我,我会重新措辞。

更新: Yii 2.0.7 引入了变化。其中之一是将 bower\yii2-pjax 更新为 2.0.6。这使得点 3) 不再必要,并且点 2) 不那么重要,尽管知道它仍然是一件好事。

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

如果您查看实际的重定向功能(来源):

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,并且有两个不同的 header。在整个网络和多个站点中提到的 X-Redirect header 不适用于 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);

并且出于某种原因,这本身是不够的。默认情况下,source 函数运行 checkAjax 代码,但在我从重定向代码中明确调用它之前,它不会工作。

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

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

这个问题已经讨论过很多很多次了,我希望这对其他人有所帮助。