2015-04-08 3 views
2

Я создаю индикатор загрузки на моей кнопке отправки и присоединяю процедуру «запуска» к событию beforeSubmit, используя функцию registerJs.Yii2 Pjax и ActiveForm beforeSubmit не работают после перезагрузки?

Он работает правильно в первый раз, но после перезагрузки контейнера Pjax событие не будет срабатывать при повторной отправке формы.

Я прилагаю весь файл вида в контейнере Pjax, чтобы корректно отображались флэш-сообщения.

Вот 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(); ?> 

Я использую Картик Spinner Widget (Details and Demo)

Любые идеи о том, почему событие beforeSubmit не будет срабатывать после того, как Pjax загрузил контейнер данных после успешной отправки?

Спасибо.

+1

Какой метод визуализации вы используете в своем контроллере? просто render()? или renderAjax()? –

+0

Я использовал render(), но сделал быстрый тест с renderAjax(), и это, казалось, сработало. Мне пришлось переместить функцию registerJs() в фактический файл просмотра. И теперь появляются флеш-сообщения. Есть идеи? –

+0

Извините, я хотел сказать, что флеш-сообщения не отображаются на загрузке Ajax. –

ответ

5

Эта проблема возникает по нескольким причинам.

Во-первых, Любой код, помещенный в пределах $(document).ready(); и загруженный на страницу, указанную на ajax (содержащую страницу), не будет выполнен после его загрузки.

Во-вторых, любые ссылки на внешние скрипты (<script src>) не гарантируются для загрузки перед встроенными скриптами. В случае Yii2 эти встроенные сценарии будут регистрироваться с registerJs()

Getting Pjax играть хорошо со сложным сценарием зависимых страницами, чтобы загрузить это не тривиальные.

Несколько вещей, чтобы решить ваши проблемы:?

1) Встроенные скрипты, загруженные registerJs() и установить с позицией POS_READY (по умолчанию) будет содержаться в $(document).ready(), если представление визуализируется с помощью render().

Таким образом, важно визуализировать с помощью renderAjax(). Это обеспечит выполнение встроенных скриптов.

Иногда (в большинстве случаев) вам необходимо использовать render() при статической загрузке и renderAjax(), когда pjax загружает страницу. В вашем случае это необходимо для размещения виджета 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 преуспевает. К сожалению, это может и не желать.

Также имейте в виду, что событие 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) менее важно, хотя это все еще хорошо знать.

+0

Спасибо.Я смог заставить его работать с помощью renderAjax, и я создал оператор «if», который оценивает Yii :: $ app-> request-> isAjax, который использует render или renderAjax соответственно. Я изменю его в соответствии с вашим предложением для проверки X-PJAX. –

+0

Вы знаете, как выполнять перенаправление в контроллере, когда это был вызов ajax от Pjax. Начиная с преобразования в Pjax, я потерял функцию перенаправления. –

+0

Можете ли вы уточнить, что не работает? Не работает перенаправление или pjax не может загрузить перенаправленную страницу через Ajax? –

0

So. У меня есть решение, но оно противоречит документации ...

Если вы посмотрите на фактические функции переадресации (источник):

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  } 

Вы можете видеть, что он проверяет Pjax, прежде чем Ajax и имеет два различных как таковые. заголовок 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; 

Это обсуждалось много, много раз, и я надеюсь, что это помогает другим.