Запрос 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); } }
Мысли?
Действительно, лучше всего написать другую Стратегию. Существует 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 )); }
Я думаю, проблема в том, что вы вызываете 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 ?>
Вот лучшее решение (по моему скромному мнению). Я потратил почти два дня, чтобы понять это. Пока никто в Интернете не писал об этом.
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
Я ответил на этот вопрос и, похоже, похоже на него – переменные Access ViewModel в событии отправки
Прикрепите обратный вызов события к триггеру события dispatch
. Как только это событие запускается, оно должно позволить вам получить результат действия метода, вызвав $e->getResult()
. В случае действия, возвращающего ViewModel, он должен позволить вам выполнить модификацию setTerminal ().
Решение aimfeld работает для меня, но если некоторые из вас экспериментируют с расположением шаблона, попробуйте указать модуль:
$this->viewModel->setTemplate('application/ajax/response');
Лучше всего использовать JsonModel, который возвращает приятный json и отключает макет и представление для вас.
public function ajaxCallAction() { return new JsonModel( [ 'success' => true ] ); }
У меня была эта проблема раньше, и вот трюк quikc, чтобы решить это.
Прежде всего, создайте пустой макет в вашем module/YourModule/view/layout/empty.phtml
папок макета module/YourModule/view/layout/empty.phtml
Вы должны только эхом просматривать содержимое этого макета таким образом <?php echo $this->content; ?>
<?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'); } }); } }
public function myAjaxAction() { .... // View - stuff that you returning usually in a case of non-ajax requests View->setTerminal(true); return View; }