Zend Framework 2: автоматическое отключение макета для вызовов ajax - программирование

Zend Framework 2: автоматическое отключение макета для вызовов ajax

Запрос 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);
    }
}

Мысли?

4b9b3361

Ответ 1

Действительно, лучше всего написать другую Стратегию. Существует JsonStrategy, которая может автоматически обнаруживать заголовок accept, чтобы автоматически возвращать Json-Format, но, как и в случае Ajax-Calls для полных страниц, там хорошо, что он не выполняет автоматически, потому что вы МОЖЕТЕ получить полную страницу. Вышеупомянутое решение, о котором вы говорили, было бы быстрым способом.

При переходе на полную скорость у вас будет только одна дополнительная строка. Лучше всего всегда возвращать полностью квалифицированные ViewModels из вашего контроллера. Как:

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
    ));
}

Ответ 2

Я думаю, проблема в том, что вы вызываете 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 ?>

Ответ 3

Вот лучшее решение (по моему скромному мнению). Я потратил почти два дня, чтобы понять это. Об этом пока никто не сообщил в Интернете.

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

Я ответил на этот вопрос и, похоже, похоже на него - Переменные Access ViewModel в событии отправки

Прикрепите обратный вызов события к триггеру события dispatch. После запуска этого события вы должны получить результат действия метода, вызвав $e->getResult(). В случае действия, возвращающего ViewModel, оно должно позволить вам выполнить модификацию setTerminal().

Ответ 5

Решение aimfeld работает для меня, но если некоторые из вас экспериментируют с расположением шаблона, попробуйте указать модуль:

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

Ответ 6

Лучше всего использовать JsonModel, который возвращает приятный json и отключает макет и view для вас.

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

Ответ 7

У меня была эта проблема до этого и вот трюк quikc, чтобы решить это.

Прежде всего, создайте пустой макет в папке макета module/YourModule/view/layout/empty.phtml

Вы должны только эхо-изображения содержимого в этом макете <?php echo $this->content; ?>

Теперь в вашем Module.php установите макет контроллера для макета/пустой для запроса ajax

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');
            }
        });
    }
}

Ответ 8

public function myAjaxAction() 
{
    ....
    // View - stuff that you returning usually in a case of non-ajax requests
    View->setTerminal(true);
    return View;
}