2012-11-01 13 views
15

Żądanie AJAX do jednej z moich akcji kontrolera obecnie zwraca cały HTML strony.Zend Framework 2: Automatyczne wyłączanie układu dla wywołań ajaxowych

Chcę tylko, aby zwrócił HTML (zawartość .phtml) dla tej konkretnej akcji.

Poniższy kod słabo rozwiązuje ten problem, ręcznie wyłączając układ dla danego działania:

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

Jak mogę uczynić moją aplikacja automatycznie wyłącza układ po wykryciu żądania AJAX? Czy muszę napisać do tego niestandardową strategię? Wszelkie porady dotyczące tego są bardzo cenne.

Dodatkowo, wypróbowałem poniższy kod w mojej aplikacji Module.php - wykrywa poprawnie AJAX, ale setTerminal() nie wyłącza układu.

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

Myśli?

Odpowiedz

7

W rzeczywistości najlepiej byłoby napisać kolejną strategię. Istnieje JsonStrategy, która może automatycznie wykryć nagłówek accept, aby automatycznie zwracać format Json, ale tak jak w przypadku Ajax-Calls dla fullpages, dobrze jest, że nie robi to automatycznie, ponieważ MOŻESZ chcieć uzyskać pełną stronę. Wspomnianym wyżej rozwiązaniem będzie szybka droga.

Podczas jazdy z pełną prędkością, masz tylko jedną dodatkową linię. Najlepszą praktyką jest zwracanie w pełni kwalifikowanych ViewModels z poziomu kontrolera. Jak:

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

Dzięki, Sam - zaktualizowałem również mój post, aby uwzględnić podejście, które wypróbowałem dzięki aplikacji Module.php. Wszelkie myśli na temat, dlaczego setTerminal() nie ma wpływu na ViewModel? –

+0

Zgaduję, że onBootstrap nie ViewModel() jest jeszcze obecny, pomysłem byłoby wstrzyknąć viewModel z terminalem (true) do kontrolera i użyć tego do wyjścia (czy mam jakiś sens?) – Sam

0

odpowiedziałem na to pytanie wydaje się być może i podobne - Access ViewModel variables on dispatch event

Dołączanie zwrotnego zdarzeń do wyzwalacza dispatch zdarzeń. Po uruchomieniu tego zdarzenia należy umożliwić uzyskanie wyniku działania poprzez wywołanie $e->getResult(). W przypadku akcji zwracającej ViewModel, powinno to pozwolić na modyfikację setTerminal().

6

Myślę, że problemem jest to, że dzwonisz setTerminal() na modelu widoku $e->getViewModel(), która jest odpowiedzialna za renderowanie układ, a nie działania. Musisz utworzyć nowy model widoku, zadzwoń pod numer setTerminal(true) i zwróć go. Używam dedykowanego kontrolera ajax więc nie ma potrzeby ustalania, czy działanie jest ajax czy nie:

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

aw ajax/response.phtml prostu następuje:

<?= $this->response ?> 
0

rozwiązanie aimfeld pracuje dla mnie , ale w przypadku niektórych z was eksperymentować problemów z umieszczeniem szablonu, spróbuj określić moduł:

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

Oto najlepsze rozwiązanie (moim skromnym zdaniem). Spędziłem prawie dwa dni, aby to rozgryźć. Nikt w Internecie nie pisał o tym, jak dotąd, myślę.

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

} 

Nadal nie jestem usatysfakcjonowany. Utworzyłem wtyczkę jako detektor i skonfigurowałem ją za pomocą pliku konfiguracyjnego zamiast metody onBootstrap.Ale dam to po raz kolejny = P

+0

Pamiętaj, że wynik kontrolera może wcale nie być 'ViewModel'; nawet żądanie może nie być "Zend \ Http \ Request", więc należy zachować ostrożność podczas pisania detektorów zdarzeń, zawsze wprowadzać elementy sterujące, co można pobrać z wydarzenia, i pamiętać, że słuchacze wpływają na cały cykl aplikacji MVC, a nie tylko na moduł. –

+0

Jak uzyskać dostęp do tego określonego modelu widoku w kontrolerze? – jkushner

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

najlepiej jest używać JsonModel która zwraca piękny json i wyłączyć układ & widok dla ciebie.

public function ajaxCallAction() 
    { 
     return new JsonModel(
      [ 
       'success' => true 
      ] 
     ); 
    } 
+0

fajnie, chyba że chcesz odesłać gotowy HTML. – David

0

Miałem ten problem przed i tutaj jest quikc lewę, aby rozwiązać to.

Przede wszystkim utworzyć pusty układ w folderze układu module/YourModule/view/layout/empty.phtml

Trzeba tylko echo zawartość widok w tym układ ten sposób <?php echo $this->content; ?>

teraz w Twoich Module.php ustawić układ regulatora do układu/pusty dla zapytania ajaxowego

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