web-dev-qa-db-ja.com

Zend Framework 2:ajax呼び出しのレイアウトを自動的に無効にする

コントローラーアクションの1つに対するAJAXリクエストは、現在、ページ全体のHTMLを返します。

その特定のアクションのHTML(.phtmlコンテンツ)のみを返すようにします。

次のコードは、特定のアクションのレイアウトを手動で無効にすることで、問題をうまく解決できません。

    $viewModel = new ViewModel();
    $viewModel->setTerminal(true);
    return $viewModel;

AJAXリクエストが検出されたときに、アプリケーションでレイアウトを自動的に無効にするにはどうすればよいですか?このためのカスタム戦略を作成する必要がありますか?これを行う方法についてのアドバイスは大歓迎です。

さらに、アプリModule.phpで次のコードを試しました。AJAXを正しく検出していますが、setTerminal()がレイアウトを無効にしていません。

public function onBootstrap(EventInterface $e)
{
    $application = $e->getApplication();
    $application->getEventManager()->attach('route', array($this, 'setLayout'), 100);

    $this->setApplication($application);

    $this->initPhpSettings($e);
    $this->initSession($e);
    $this->initTranslator($e);
    $this->initAppDi($e);
}

public function setLayout(EventInterface $e)
{
    $request = $e->getRequest();
    $server  = $request->getServer();

    if ($request->isXmlHttpRequest()) {
        $view_model = $e->getViewModel();
        $view_model->setTerminal(true);
    }
}

考え?

17
Daniel Sposito

確かに最良のことは、別の戦略を書くことです。 Acceptヘッダーを自動検出してJson-Formatを自動的に返すことができるJsonStrategyがありますが、フルページのAjax-Callsと同様に、フルページを取得したい場合があるため、自動的に処理を行わないのは良いことです。あなたが言及した上記の解決策は、行くための迅速な方法でしょう。

フルスピードを目指す場合、追加の回線は1つだけです。コントローラ内から常に完全に修飾されたViewModelを返すことをお勧めします。お気に入り:

public function indexAction() 
{
    $request   = $this->getRequest();
    $viewModel = new ViewModel();
    $viewModel->setTemplate('module/controller/action');
    $viewModel->setTerminal($request->isXmlHttpRequest());

    return $viewModel->setVariables(array(
         //list of vars
    ));
}
8
Sam

問題は、アクションではなく、layoutのレンダリングを担当するビューモデルsetTerminal()$e->getViewModel()を呼び出していることだと思います。新しいビューモデルを作成し、setTerminal(true)を呼び出して、それを返す必要があります。私は専用のajaxコントローラーを使用しているので、アクションがajaxであるかどうかを判断する必要はありません。

use Zend\View\Model\ViewModel;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Controller\AbstractActionController;

class AjaxController extends AbstractActionController
{
    protected $viewModel;

    public function onDispatch(MvcEvent $mvcEvent)
    {
        $this->viewModel = new ViewModel; // Don't use $mvcEvent->getViewModel()!
        $this->viewModel->setTemplate('ajax/response');
        $this->viewModel->setTerminal(true); // Layout won't be rendered

        return parent::onDispatch($mvcEvent);
    }

    public function someAjaxAction()
    {
        $this->viewModel->setVariable('response', 'success');

        return $this->viewModel;
    }
}

そしてajax/response.phtmlでは、単に次のようになります。

<?= $this->response ?>
6
aimfeld

これが最善の解決策です(私の謙虚な意見では)。私はそれを理解するためにほぼ2日を費やしました。これまでのところ、インターネット上の誰もそれについて投稿していないと思います。

public function onBootstrap(MvcEvent $e)
{
    $eventManager= $e->getApplication()->getEventManager();

    // The next two lines are from the Zend Skeleton Application found on git
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);

    // Hybrid view for ajax calls (disable layout for xmlHttpRequests)
    $eventManager->getSharedManager()->attach('Zend\Mvc\Controller\AbstractController', MvcEvent::EVENT_DISPATCH, function(MvcEvent $event){

        /**
         * @var Request $request
         */
        $request = $event->getRequest();
        $viewModel = $event->getResult();

        if($request->isXmlHttpRequest()) {
            $viewModel->setTerminal(true);
        }

        return $viewModel;
    }, -95);

}

私はまだ満足していません。プラグインをリスナーとして作成し、onBootstrapメソッドの代わりに構成ファイルを介して構成します。しかし、次回はこれを許可します= P

4
Keyne Viana

私は以前にこの問題を抱えていましたが、これを解決するための簡単なトリックがあります。

まず、レイアウトフォルダに空のレイアウトを作成しますmodule/YourModule/view/layout/empty.phtml

このレイアウトのビューコンテンツは、この方法でのみエコーする必要があります<?php echo $this->content; ?>

今あなたのModule.phpajaxリクエストのコントローラーレイアウトをlayout/emptyに設定します

namespace YourModule;
use Zend\Mvc\MvcEvent;

class Module {
    public function onBootstrap(MvcEvent $e) {
        $sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
        $sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
            if ($e->getRequest()->isXmlHttpRequest()) {
                $controller = $e->getTarget();
                $controller->layout('layout/empty');
            }
        });
    }
}
0
BoCyrill

aimfeldソリューションは私には機能しますが、テンプレートの場所で問題を実験する場合は、モジュールを指定してみてください。

 $this->viewModel->setTemplate('application/ajax/response');
0
Conti

私はこの質問に答えましたが、おそらく似ているようです- ディスパッチイベントでViewModel変数にアクセスします

イベントコールバックをdispatchイベントトリガーにアタッチします。このイベントがトリガーされると、$e->getResult()を呼び出してアクションメソッドの結果を取得できるようになります。 ViewModelを返すアクションの場合、setTerminal()の変更を許可する必要があります。

0
DrBeza

最良の方法は、Nice jsonを返すJsonModelを使用し、layout&viewを無効にすることです。

public function ajaxCallAction()
    {
        return new JsonModel(
            [
                'success' => true
            ]
        );
    }
0
tomekSzad