Zend Framework 2: Auto disable layout for ajax calls

前端 未结 8 1765
终归单人心
终归单人心 2020-12-16 13:26

An AJAX request to one of my controller actions currently returns the full page HTML.

I only want it to return the HTML (.phtml contents) for that particular action.

相关标签:
8条回答
  • 2020-12-16 13:50
    public function myAjaxAction() 
    {
        ....
        // View - stuff that you returning usually in a case of non-ajax requests
        View->setTerminal(true);
        return View;
    }
    
    0 讨论(0)
  • 2020-12-16 13:51

    Here's the best solution (in my humble opinion). I've spent almost two days to figure it out. No one on the Internet posted about it so far I think.

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

    I'm still not satisfied though. I would create a plugin as a listener and configure it via configuration file instead of onBootstrap method. But I'll let this for the next time =P

    0 讨论(0)
  • 2020-12-16 13:55

    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
        ));
    }
    
    0 讨论(0)
  • 2020-12-16 13:56

    aimfeld solution works for me, but in case some of you experiment issues with the location of the template, try to specify the module:

     $this->viewModel->setTemplate('application/ajax/response');
    
    0 讨论(0)
  • 2020-12-16 14:03

    The best is to use JsonModel which returns nice json and disable layout&view for you.

    public function ajaxCallAction()
        {
            return new JsonModel(
                [
                    'success' => true
                ]
            );
        }
    
    0 讨论(0)
  • 2020-12-16 14:04

    I think the problem is that you're calling setTerminal() on the view model $e->getViewModel() that is responsible for rendering the layout, not the action. You'll have to create a new view model, call setTerminal(true), and return it. I use a dedicated ajax controller so there's no need of determining whether the action is ajax or not:

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

    and in ajax/response.phtml simply the following:

    <?= $this->response ?>
    
    0 讨论(0)
提交回复
热议问题