对我的某个控制器操作的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);
}
}
思想?
答案 0 :(得分:8)
确实,最好的办法是编写另一份战略。有一个JsonStrategy可以自动检测accept头以自动返回Json-Format,但是就像Ajax-Calls for fullpages一样,它不会自动执行任何操作,因为你可能想要获得一个完整的页面。您提到的上述解决方案将是快速的方法。
当全速前进时,你只需要一条额外的线路。始终从控制器中返回完全限定的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
));
}
答案 1 :(得分:6)
我认为问题在于您在视图模型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 ?>
答案 2 :(得分:4)
这是最好的解决方案(以我的拙见)。我花了将近两天的时间才搞清楚。到目前为止,我认为互联网上没有人发布过它。
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
答案 3 :(得分:0)
我回答了这个问题,看起来可能类似 - Access ViewModel variables on dispatch event
将事件回调附加到dispatch
事件触发器。一旦此事件触发,它应该允许您通过调用$e->getResult()
来获取操作方法的结果。如果一个动作返回一个ViewModel,它应该允许你进行setTerminal()修改。
答案 4 :(得分:0)
aimfeld解决方案适用于我,但如果你们中的一些人试验模板的位置问题,请尝试指定模块:
$this->viewModel->setTemplate('application/ajax/response');
答案 5 :(得分:0)
最好的方法是使用JsonModel,它会返回漂亮的json并为你禁用布局和视图。
public function ajaxCallAction()
{
return new JsonModel(
[
'success' => true
]
);
}
答案 6 :(得分:0)
之前我遇到过这个问题,这是一个解决问题的技巧。
首先,在布局文件夹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');
}
});
}
}
答案 7 :(得分:-2)
public function myAjaxAction()
{
....
// View - stuff that you returning usually in a case of non-ajax requests
View->setTerminal(true);
return View;
}