web-dev-qa-db-ja.com

ajax化された形式のときにハードリダイレクトを行う方法は?

Ajaxマルチステップフォームがあり、いくつかの条件が満たされたときにユーザーを特定のルートにリダイレクトしたい(特に、ユーザーがN秒以上非アクティブであり、フォームがこの制限後に送信された場合)。

検証ハンドラでリダイレクトを実行したかったのですが、うまくいきませんでした。だから私は送信ハンドラを試しましたが、まだ運がありません。私はかなり困惑しています。

リダイレクト応答を返そうとしました、フォーム状態にリダイレクト応答を設定しようとしました、フォーム状態にリダイレクトを設定しようとしました、再構築されたフォーム状態を無効にしようとしました、gotoアクションロジックをコピーしてイベントディスパッチャーを使用しました、\ Drupal\Core\Form\FormBuilderInterface :: AJAX_FORM_REQUESTのリクエストを解除しようとしましたが、まだうまくいきませんでした。

リダイレクトコマンドとしてリダイレクトをajaxコールバックで返すこともできますが、無効なjsでこれを機能させたいので、window.locationを呼び出すだけでは不十分です。

5
user21641

かなりの後、いくつかの実験を行って、この実用的なソリューションにたどり着きました。

条件は、送信ハンドラの先頭にある必要があります。

  if ($condition) {
    $form_state->setRedirect('foo.bar')->disableRedirect(FALSE)->setRebuild(FALSE);
    // Return here so the code that activates form rebuilding for ajax or any data processing logic is not invoked.
    return;
  }

そして、ajaxコールバックは次のようにフォーマットする必要があります。

public static function ajaxRebuildForm(array $form, FormStateInterface $form_state) {
    /** @var \Drupal\Core\Form\FormSubmitterInterface $submitted */
    $submitter = \Drupal::service('form_submitter');
    /** @var \Symfony\Component\HttpFoundation\RedirectResponse $redirect */
    $redirect = $submitter->redirectForm($form_state);
    if ($redirect) {
      return (new AjaxResponse())->addCommand(new RedirectCommand($redirect->getTargetUrl()));
    }

    return $form;
  }

これは、jsが有効な環境とjsが無効な環境の両方で機能します。 JSが有効な場合、ajaxコールバックは設定されたリダイレクトを検出し、配列をレンダリングする代わりにリダイレクトコマンドを使用してajax応答を返します(これは内部的にajax応答にも変換されます)。 jsが無効になっている場合、フォームの送信時にリダイレクトはリダイレクト応答として処理されます。


編集:これは100%有効な解決策ではないことがわかりました。フォームまたはperofrmsリダイレクトを返すルートコントローラーがあります。 ajax化されたフォームになり、コントローラーがリダイレクトを実行すると(つまり、いくつかの条件がun/metでした)、ajaxコールバックがトリガーされないためフォームにスタックし、何もできないので、基本的にページへのリクエストを実行していますこれはリダイレクトを返し、フォームロジックは呼び出されなくなります。つまり、フォームAPIは最初に呼び出されてフォームを処理する機会があるため、フォームだけでなく、コントローラーにも追加のロジックを実装する必要があります。

私はこれを私のコントローラーに実装する必要がありました:

  if ($request->request->get(AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER)) {
    return (new AjaxResponse())
      ->addCommand(
        new RedirectCommand(
          $this->redirect(
            $this->currentRouteMatch->getRouteName()
          )->getTargetUrl()
        )
      );
  }
4
user21641

私の場合(D8)、私はAjaxSubmitにRedirectCommandを実装する必要がありました:

送信ボタンのコード:

$form['submit_' . $this->uniqueIdentifier] = [
  '#type' => 'submit',
  '#value' => $this->t('Submit'),
  '#attributes' => [
    'class' => ['btn', 'btn-primary']
  ],
  '#ajax' => [
    'callback' => [$this, 'submitModalFormAjax'],
    'event' => 'click',
  ],
];

送信コールバックのコード:

public function submitModalFormAjax(array $form, FormStateInterface $form_state) {
  $response = new AjaxResponse();

  if ($form_state->hasAnyErrors()) {
    // Do validation stuff here
    // ex: $response->addCommand(new ReplaceCommand... on error fields
  }

  else {
    // Do submit stuff here

    $url = Url::fromRoute('page_route');
    $command = new RedirectCommand($url->toString());
    $response->addCommand($command);
  }

  return $response;
}

宣言することを忘れないでください:

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Url;
5
romain ni