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

Мысли?

Действительно, лучше всего написать другую Стратегию. Существует 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; }