2012-11-01 9 views
15

Eine AJAX-Anfrage an eine meiner Controller-Aktionen gibt derzeit den HTML-Code der gesamten Seite zurück.Zend Framework 2: Layout für Ajax-Aufrufe automatisch deaktivieren

Ich möchte nur den HTML-Inhalt (.phtml) für diese bestimmte Aktion zurückgeben.

Der folgende Code löst schlecht das Problem, indem manuell das Layout für die jeweilige Aktion zu deaktivieren:

$viewModel = new ViewModel(); 
    $viewModel->setTerminal(true); 
    return $viewModel; 

Wie kann ich den Antrag stellen automatisch das Layout deaktivieren, wenn eine AJAX-Anforderung erkannt wird? Muss ich eine benutzerdefinierte Strategie dafür schreiben? Irgendein Rat, wie man dies tut, wird sehr geschätzt.

Zusätzlich habe ich den folgenden Code in meiner App Module.php versucht - es erkennt AJAX korrekt, aber die SetTerminal() deaktiviert das Layout nicht.

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

Gedanken?

Antwort

7

In der Tat wäre das Beste, eine andere Strategie zu schreiben. Es gibt eine JsonStrategy, die den Accept-Header automatisch erkennen kann, um Json-Format zurückzugeben, aber wie bei Ajax-Calls für ganze Seiten, ist es gut, dass es nicht automatisch Dinge tut, weil Sie vielleicht eine ganze Seite bekommen wollen. Die oben erwähnte Lösung wäre der schnellste Weg.

Wenn Sie die volle Geschwindigkeit anstreben, haben Sie nur eine zusätzliche Linie. Es ist eine bewährte Methode, immer vollständig qualifizierte ViewModels von Ihrem Controller aus zurückzugeben. Wie:

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

Danke, Sam - Ich habe auch meinen Beitrag aktualisiert, um eine Vorgehensweise, die ich mit der App Module.php ausprobiert haben. Irgendwelche Gedanken darüber, warum setTerminal() keine Auswirkungen auf das ViewModel hat? –

+0

Meine Vermutung ist, dass OnBootstrap kein ViewModel() vorhanden ist, eine Idee wäre, ein ViewModel mit Terminal (true) in den Controller zu injizieren und dies für die Ausgabe zu verwenden (mache ich irgendeinen Sinn?) – Sam

0

Ich antwortete auf diese Frage und scheint es vielleicht ähnlich - Access ViewModel variables on dispatch event

Bringen Sie ein Ereignis Rückruf an den dispatch Ereignisauslöser. Sobald dieses Ereignis ausgelöst wird, sollten Sie das Ergebnis der Aktionsmethode abrufen können, indem Sie $e->getResult() aufrufen. Im Falle einer Aktion, die ein ViewModel zurückgibt, sollte es Ihnen möglich sein, die setTerminal() - Modifikation durchzuführen.

6

ich glaube, das Problem ist, dass Sie setTerminal() auf der View-Modell $e->getViewModel() sind aufrufen, die für die Wiedergabe des Layout verantwortlich ist, nicht die Handlung. Sie müssen ein neues Ansichtsmodell erstellen, setTerminal(true) aufrufen und es zurückgeben. Ich benutze einen eigenen Ajax-Controller, so gibt es keine Notwendigkeit, festzustellen, ob die Aktion Ajax ist oder nicht:

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

und in Ajax/response.phtml einfach folgendes:

<?= $this->response ?> 
0

aimfeld Lösung funktioniert für mich , aber falls einige von Ihnen Probleme mit dem Speicherort der Vorlage experimentieren, versuchen, das Modul zu spezifizieren:

$this->viewModel->setTemplate('application/ajax/response'); 
4

Hier ist die beste Lösung (in meiner bescheidenen Meinung nach). Ich habe fast zwei Tage damit verbracht, es herauszufinden. Niemand im Internet hat darüber so weit geschrieben, denke ich.

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

} 

Ich bin immer noch nicht zufrieden, obwohl. Ich würde ein Plugin als Listener erstellen und es über die Konfigurationsdatei anstelle der onBootstrap-Methode konfigurieren.Aber ich werde dies für das nächste Mal lassen = P

+0

Denken Sie daran, dass das Ergebnis eines Controllers darf kein 'ViewModel' sein; selbst die Anfrage darf kein 'Zend \ Http \ Request' sein, also sei vorsichtig, wenn du Event Listener schreibst, setze immer Kontrollen darüber was du aus dem Event gehst und denke daran, dass Listener den gesamten MVC Applikationszyklus beeinflussen, nicht nur deine Modul. –

+0

Wie kann ich auf dieses spezifische Ansichtsmodell in meinem Controller zugreifen? – jkushner

-1
public function myAjaxAction() 
{ 
    .... 
    // View - stuff that you returning usually in a case of non-ajax requests 
    View->setTerminal(true); 
    return View; 
} 
0

Das Beste ist JsonModel zu verwenden, die für Sie schöne json und deaktivieren Layout & Ansicht zurückgibt.

+0

das ist nett, außer wenn Sie fertigen HTML zurück senden möchten. – David

0

Ich hatte dieses Problem vor und hier ist ein Quikc-Trick, um das zu lösen.

Zunächst einmal ein leeres Layout im Layout-Ordner erstellen module/YourModule/view/layout/empty.phtml

Sie sollten nur die Ansicht Inhalt in diesem Layout Echo auf diese Weise <?php echo $this->content; ?>

in ihrem Module.php setzen die Controller-Layout Layout/Leer für Ajax Anfrage

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