17

对我的控制器操作之一的 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);
    }
}

想法?

4

8 回答 8

8

Indeed the best thing would be to write another Strategy. There is a JsonStrategy which can auto-detect the accept header to automatically return Json-Format, but as with Ajax-Calls for fullpages, there it's good that it doesn't automatically do things, because you MAY want to get a full page. Above mentioned solution you mentioned would be the quick way to go.

When going for full speed, you'd only have one additional line. It's a best practice to always return fully qualified ViewModels from within your controller. Like:

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
    ));
}
于 2012-11-01T15:32:47.960 回答
6

我认为问题在于您调用的是负责渲染布局setTerminal()的视图模型,而不是操作。您必须创建一个新的视图模型,调用并返回它。我使用专用的 ajax 控制器,因此无需确定操作是否为 ajax:$e->getViewModel()setTerminal(true)

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 ?>
于 2012-11-30T17:27:30.253 回答
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

于 2014-02-14T02:16:16.080 回答
0

最好的方法是使用 JsonModel 返回漂亮的 json 并为您禁用布局和视图。

public function ajaxCallAction()
    {
        return new JsonModel(
            [
                'success' => true
            ]
        );
    }
于 2015-02-13T22:33:19.980 回答
0

Aimfeld 解决方案对我有用,但如果你们中的一些人尝试模板位置的问题,请尝试指定模块:

 $this->viewModel->setTemplate('application/ajax/response');
于 2013-12-19T17:14:16.157 回答
0

我回答了这个问题,似乎可能类似 - Access ViewModel variables on dispatch event

将事件回调附加到dispatch事件触发器。一旦此事件触发,它应该允许您通过调用获取操作方法的结果$e->getResult()。在返回 ViewModel 的操作的情况下,它应该允许您进行 setTerminal() 修改。

于 2012-11-01T16:52:56.430 回答
0

我之前遇到过这个问题,这里有一个快速技巧来解决这个问题。

首先,在你的布局文件夹中创建一个空布局module/YourModule/view/layout/empty.phtml

您应该只以这种方式回显此布局中的视图内容<?php echo $this->content; ?>

现在,在您Module.php将控制器布局设置为 layout/empty 以进行 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');
            }
        });
    }
}
于 2016-07-13T14:26:38.857 回答
-2
public function myAjaxAction() 
{
    ....
    // View - stuff that you returning usually in a case of non-ajax requests
    View->setTerminal(true);
    return View;
}
于 2014-06-17T02:38:24.377 回答