Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [Kohana] Stronicowanie/advAJAX, można lepiej?
Forum PHP.pl > Forum > PHP > Frameworki
magnus
Zastanawiam się, czy to co zrobiłem można zrobić lepiej.
Otóż - mam stronę, na której chcę wyświetlić pewną ilość rekordów. Strona ma się wyświetlić raz, natomiast kolejne porcje rekordów chcę pobierać w tle. Tworząc to proceduralnie mam zawartość "porcji" rekordów razem z kodem, który je pobiera w osobnym inkludzie. Próbując zrobić to w FW wymyśliłem sobie 2 osobne akcje kontrolera - główna (index()) podczas odczytywania strony wywołuje drugą akcję, odpowiedzialną za pobranie określonej porcji rekordów (nazwałem ją best()).

Poniższy kontroler działa, ale mam wrażenie, że nie jest to całkowicie poprawnie zrobione, dlatego proszę o jakieś sugestie ze strony zaawansowanych "kohanowców".

Oczywiście nie patrzcie na sam pager, który jest tu wstawiony tylko roboczo.
Szczególnie mnie drażni ta sztuczka z zamianą nazwy akcji na linku (wówczas przy wyłączonym JS będzie wywoływać /index.php/ipeop/index/X a AJAX'em: /index.php/ipeop/best/X, czyli bezpośrednio akcję "best").
Poza tym rozpoznawanie, czy wywołanie jest zwykłe czy Ajaxowe też jest takie na siłę, bo nie bardzo wiem jak skorzystać z request::is_ajax() - pewnie trzeba jakimś helperem robić linki, ale czy da się wówczas korzystać z advAJAX? A nic więcej niż advAJAX nie jest mi potrzebne.

Kod
<?php defined('SYSPATH') or die ('None shall pass!');

class Ipeop_Controller extends Website_Controller {
    
     //domyślna akcja
     public function index($page=1) {
    
         $this->template->header = new View('elements/header');
         $this->template->header->title = 'Osoby!!';
        
         $this->template->best_div = $this->best($page, FALSE);

     }

     //pobranie porcji rekordów
     public function best($page=1, $render = TRUE) {
        
         $best = new View('_best');
         $best->title = 'Najlepsze osoby';
         if ($render) {
             $best->ajax = 1;
             $this->auto_render = false;
         }
         $limit_start = ($page-1)*5;
         $result = $this->db->query('select count(id_user) as c from nfv_active_users')->result(FALSE);
         $n= $result[0]['c'];
         $pages = $n / 5;
         $osoby = $this->db->query('select * from nfv_active_users '.$limit_start.', 5');
         $best->osoby = $osoby->result(FALSE);
         $link = '<a onclick="advAJAX.get({url: this.href.replace(\'/index/\', \'/best/\'), tag: \'5best\'}); return false;" href="/index.php/ipeop/index/%d">%s</a>';
         $pager = 'Ilość: '.$n.' ';
         if ($page > 1) {
             $pager .= sprintf($link, $page-1, '&lt;&lt;');
         }
         if ($page < $pages) {
             $pager .= sprintf($link, $page+1, '&gt;&gt;');
         }
         $best->link = $pager;
         return $best->render($render);
        
     }
    
}
phpion
Moje rady:
- Pagination
- możliwe, że request::is_ajax() nie działa przy advAjax z powodu braku odpowiedniego nagłówka. Podobny przypadek miałem przy chwilowym używaniu mintAjax. Po powrocie na MooTools / jQuery sprawdzanie wywołania ajaxowego działa bez zastrzeżeń. Nie jest to więc wina Kohany tylko samego advAjax.
- do tworzenia linków używaj html::anchor i wywal kod tworzący link z kontrolera do widoku.
- dobrze Ci radzę: korzystaj z modeli. Pakowanie zapytań do bazy wprost do kontrolera jest naprawdę nieeleganckie... Po to masz w Kohanej MVC żeby z niego korzystać.
magnus
Co do pierwszej i ostatniej rady - zarówno pager jak i pobieranie danych jest tutaj wciśnięte tylko tymczasowo. Chodzi tylko o rozpracowanie problemu współpracy tych dwóch akcji ze sobą i z advAJAX'em winksmiley.jpg

Co do nagłówka - faktycznie! Po przyjrzeniu się w FireBugu jakie nagłówki są wysyłane, okazało się, że nie jest wysyłany 'X-Requested-With: XMLHttpRequest' a po nim właśnie odbywa się rozróżnianie wywołań ajax/nie-ajax.
Dołożyłem w kodzie biblioteki advAJAX taki nagłówek i ten aspekt już jest załatwiony biggrin.gif

To teraz mogę spróbować przerobić ten kontroler, aby się odpowiednio zachowywał w zależności czy z ajaxa czy bez.

Heh, udało się zmienić advAJAX i korzystać z request::is_ajax(). Udało się też zrobić wszystko w jednej akcji kontrolera.
Zastosowałem też html::anchor do generowania linków. Wygląda to teraz tak (znów - nie patrzymy na część pobierającą dane winksmiley.jpg):

Kod
<?php defined('SYSPATH') or die ('None shall pass!');

class Ipeop_Controller extends Website_Controller {

    //domyślna akcja
    public function view($page=1) {
        
        //  !!! Tymczasowo pobieranie danych i paginacja tutaj exclamation.gif!
        $limit_start = ($page-1)*5;
        $result = $this->db->query('select count(id_user) as c from nfv_active_users')->result(FALSE);
        $n= $result[0]['c'];
        $pages = ceil($n / 5);
        $query = $this->db->query('select * from nfv_active_users_by_name limit '.$limit_start.', 5');
        $osoby = $query->result(FALSE);
        
        //pager
        $onclick = 'advAJAX.get({
                url: this.href,
                tag: \'5best\'
            }); return false;';
        $link = 'ipeop/view/%d';
        
        $pager = 'Ilość: '.$n.'; strona '.$page.' z '.$pages.' ';
        if ($page > 1) {
            $pager .= html::anchor(sprintf($link, $page-1), '<<', array('onclick'=>$onclick));
        }
        if ($page < $pages) {
            $pager .= html::anchor(sprintf($link, $page+1), '>>', array('onclick'=>$onclick));
        }
        
        // zasadnicza część kontrolera
        if (request::is_ajax()) {

            //jeśli ajaxowe, to wyświetl tylko _best
            $ipeop = new View('_best');
            $ipeop->osoby = $osoby;
            $ipeop->pager = $pager;
            $this->auto_render=false; //wyłączenie auto renderowania szablonu
            $ipeop->render(true);
            
        } else {
            
            //pomocniczy widok _best
            $best = new View('_best');
            $best->osoby = $osoby;
            $best->pager = $pager;
            
            $this->template->best_div = $best->render();
            $this->template->header = new View('elements/header');
            $this->template->header->title = 'Osoby!!';
            
        }    

    }
    
}


Ale nurtuje mnie jedna kwestia i gdyby ktoś zechciał wrzucić szablon rozwiązania, to byłbym wdzięczny. Mianowicie zdarza się, że mam stronę z kilkoma dynamicznie pobieranymi elementami. Logicznie by było mieć każdy z nich w osobnej akcji - tylko jak to wywoływać??
Czyli wg schematu:
Przy pierwszym wywołaniu strony: Szablon strony -> element A -> element B -> ...
A potem na linku odświeżania elementu A wywołanie tylko akcji A, dla elementu B - tylko akcji B itp.
Oczywiście będzie ciężko zrobić taką stronę, żeby działała bez włączonego JS, ale to na razie nieważne.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.