Jak rychle rozchodit paginator (IPub/VisualPaginator)

ludek
Člen | 83
+
+7
-

Návod – rychlovka v češtině, jak promptně rozchodit skvělý doplněk VisualPaginator (github).

1. stáhnout do projektu:

composer require ipub/visual-paginator:@dev

2. zaregistrovat v config.local.neon:

extensions:
        visualPaginator: IPub\VisualPaginator\DI\VisualPaginatorExtension

3. do Presenteru, kde chcete něco stránkovat:

// nahoru:
use IPub\VisualPaginator\Components as VisualPaginator;

// a někam mezi metody:
// továrna, která vrátí stránkovač
    protected function createComponentVisualPaginator() {
        // Init visual paginator
        $control = new VisualPaginator\Control;
        // vypnout Ajax, s tím si budeme hrát až bude čas
        $control->disableAjax();
		// nastavit vlastní šablonu
		$control->setTemplateFile(__DIR__ . '/../../templates/paginator.latte'); // šablona je v app/templates

        return $control; // <-- v šabloně dáme jen {control visualPaginator}
    }

// a přidat k dotazu do databáze:
   public function renderDefault() {

        $items = $this->database->table('polozky')
                        ->where('nějaké podmínky')
                        ->order('datum DESC');

        // přístup ke komponentě VisualPaginatoru:
           $visualPaginator = $this['visualPaginator'];
        // přístup k samotnému paginatoru:
           $paginator = $visualPaginator->getPaginator();
        // počet položek na stránku
           $paginator->itemsPerPage = 15;
        // spočítat celkový počet položek
           $paginator->itemCount = $items->count();

        // přidat stránkovač k dotazu
           $items->limit($paginator->itemsPerPage, $paginator->offset);

        // poslat do šablony:
           $this->template->polozky = $items;
}

4. vlastní česká bootstrap šablona pro stránkovač app/templates/paginator.latte:

{if $paginator->pageCount > 1}
    <nav aria-label="Stránkování">
	<ul class="pagination">

	    {* PŘEDCHOZÍ *}
	    {if $paginator->isFirst()}
		<li class="page-item disabled"><a class="page-link" href="#">« Předchozí</a></li>
	    {else}
		<li class="page-item">
		    <a class="page-link{if $useAjax} ajax{/if}" href="{link $handle, 'page' => $paginator->page - 1}" rel="prev" >« Předchozí</a>
		</li>
	    {/if}

	    {foreach $steps as $step}
		{if $step == $paginator->page} {* AKTIVNÍ STRÁNKA *}
		    <li class="page-item active">
			<a class="page-link" href="#">
			<span>{$step}</span>
			</a>
		    </li>
		{else}
		    <li class="page-item">
			<a class="page-link{if $useAjax} ajax{/if}" href="{link $handle, 'page' => $step}">{$step}</a>
		    </li>
		{/if}

		{if $iterator->nextValue > $step + 1}
		    <li class="disabled">…</li>
		{/if}
	    {/foreach}

	    {* NÁSLEDUJÍCÍ *}
	    {if $paginator->isLast()}
		<li class="page-item disabled"><a class="page-link" href="#">Následující »</a></li>
	    {else}
		<li>
		    <a class="page-link{if $useAjax} ajax{/if}" href="{link $handle, 'page' => $paginator->page + 1}" rel="next" >Následující »</a>
		</li>
	    {/if}
	</ul>
    </nav>
{/if}

5. stránkovač do šablony s výpisem dat:

{control visualPaginator} {* stránkovač nahoře *}

<table class="table table-hover table-striped table-bordered">
  {foreach $polozky as $p}
    <tr>
      <td>{$p->datum}</td><td>{$p->cislo}</td><td>{$p->nazev}</td>
    </tr>
  {/foreach}
</table>

{control visualPaginator} {* stránkovač dole *}

Adamu Kadlecovi za doplněk moc díky.

AKTUALIZACE: doplněk byl opuštěn (Package ipub/visual-paginator is abandoned, you should avoid using it. No replacement was suggested.). Nicméně prozatím se dá používat dál – poslední verze 2.0.1 z 24.5.2019, vyzkoušeno na NETTE 3.1.4.

Editoval ludek (20. 1. 2022 15:11)

akadlec
Člen | 1326
+
0
-

díky že se ti to chtělo takto popsat. jen k tomu bodu 5, nepřepisoval bych šablonu ve vendoru ale jak si uvedl použít setter a změnit šablonu. Do budoucna se plánuje s implementací translatoru, jen zatím je podpora neimplementována, bylo použito kdyby/translation a jeho provider nicméně to přináší nutnou závislost na kdyby což né všem musí vyhovovat.

ludek
Člen | 83
+
0
-

Translator: na ty 2 slova…

Nevidím do toho, ale kdyby to šlo tak, jak to má TwiGrid (4 slova k překladu), dalo by se to v projektech kde ve skutečnosti žádnou velkou lokalizaci nepotřebujete překládat takto primitivně.

akadlec
Člen | 1326
+
0
-

ludek: no spíše šlo o to aby se to začlenilo do appky, osobně nemám moc rád když něco je tam a něco zase tam, ale ano i takto se to dá řešit.

David Kregl
Člen | 52
+
0
-

Díky za tutoriál.
Paginator mi chodí parádně včetně vlastní šablony, ale nemohu rozchodit ten Ajax.

Mohl by mi někdo prosím ukázat příklad? Pravděpodobně stačí metoda renderDefault()

Díky,
David

Fyasko
Člen | 106
+
0
-

Také bych se přimlouval za pomoc při zapnutí ajaxu :)

CZechBoY
Člen | 3608
+
+3
-

No bacha s tim ->count()! Lepší je imo ->count(‚*‘), protože nepočítá počet řádků v php, ale rovnou na straně databáze.
https://api.nette.org/…ion.php.html#433

TomasHuttner
Člen | 66
+
0
-

Ahoj, při použití paginatoru jsem postupoval přesně podle tohoto návodu ale nedaří se mi to. Stránkování se mi zobrazuje i dopočítává správně jen když chci přejít na druhou stránku tak se mi stránka změní ale data ne. Používám Doctrine místo Nette Database a myslím si že bude chyba někde ve vytahování dat z databáze jen nemůžu přijít na to kde.

Takto vytahuji data:

$data = $this->facade->findBy(['category' => 'menu','subMenu' => ''],['position' => 'ASC'],$paginator->itemsPerPage,$paginator->offset);

Nejsem si jist jestli správně používám $paginator->itemsPerPage a $paginator->offset. Děkuji za radu

Fyasko
Člen | 106
+
0
-

@DavidKregl

Ajax v komponentě jsem zapl už v Presenteru kde vytvářím tu továrnu.

<?php
public function createComponentAdminChat()
    {
	$test = $this->adminchat->create();
	$test->redrawControl('adminchat');
	return $test;
    }
?>

myslím že pro Presenter se má dát do renderu

<?php
public function renderDefault()
    {
	$that = $this;
        // Define event for example to redraw snippets
        $this['visualPaginator']->onShowPage[] = (function ($component, $page) use ($that) {
            if ($that->isAjax()){
                $that->invalidateControl();
            }
        });
    }
?>
akadlec
Člen | 1326
+
0
-

@TomasHuttner a pošlou se ti data pro tabulku a její překreslení? Podívej se co máš v odpovědi od serveru.

mario85
Člen | 22
+
0
-

čau, zkusil jsem to podle tohoto jednoduchého návodu (díky moc!), ale paginator se mi nezobrazí. Žádnou chybu ale tracy nehlásí. V čem může být problém?

Presenter:

class DocumentsPresenter extends BasePresenter
{
    /** @var DocumentsModel @inject */
    public $documentsModel;


    /**
     * Create items paginator
     *
     * @return VisualPaginator\Control
     */
    protected function createComponentVisualPaginator()
    {
        // Init visual paginator
        $control = new VisualPaginator\Control;

        $control->setTemplateFile('bootstrap.latte');
        // vypnout Ajax, s tím si budeme hrát až bude čas
        $control->disableAjax();

        return $control;
    }

    public function renderShowAll()
    {
        // Get visual paginator components
        $visualPaginator = $this['visualPaginator'];
        // Get paginator form visual paginator
        $paginator = $visualPaginator->getPaginator();
        // Define items count per one page
        $paginator->itemsPerPage = 5;
        // Define total items in list
        $paginator->itemCount = $this->documentsModel->count();
        // Apply limits to list
        $this->template->documents = $this->documentsModel->selectAll($paginator->itemsPerPage, $paginator->offset);
    }
}

a ještě šablona:

{control visualPaginator}

{block content}
    {foreach $documents as $doc}
        <p>{$doc->name}</p>
    {/foreach}


{control visualPaginator}
Lukeluha
Člen | 130
+
+2
-

Je to už trochu pozdější reakce, ale pokud by se sem někdo znovu dostal… AJAX paginator jsem rozjel takto:

public function createComponentVisualPaginator()
	{
		$paginator = new \IPub\VisualPaginator\Components\Control();
		$paginator->setTemplateFile(__DIR__ . '/../pagination.latte');
		$paginator->enableAjax();
		$paginator->onShowPage[] = function() {
			$this->redrawControl('my-snippet'); // my-snippet mi obaluje celou mou tabulku záznamů včetně paginatoru
		};

		return $paginator;
	}
Dismember
Člen | 50
+
0
-

Mám jeden problém a nepřišel jsem na řešení.

Mám stránku s výpisem položek podle nějakého názvu předaného v URL.

SourcePresenter, function renderDefault a v URL je parametr source

<?php
/source/?source=aaa
?>

Když připojím VisualPaginator, tak mi to vytvoří odkazy takto:

<?php
/source/?page-page=2&do=page-showPage
?>

Můj parametr je pryč…potřebuji, aby ten odkaz vypadal takto:

<?php
/source/?source=aaa&page-page=2&do=page-showPage
?>

Na dřívější verzi VisualPaginatoru to fungovalo. Můžete mi prosím poradit.

Díky

ali
Člen | 342
+
+1
-

Nastav si ten parametr jako persistentni

/** @persistent */
public $source;
Mardzis
Člen | 33
+
0
-

Lukeluha napsal(a):

Je to už trochu pozdější reakce, ale pokud by se sem někdo znovu dostal… AJAX paginator jsem rozjel takto:

public function createComponentVisualPaginator()
	{
		$paginator = new \IPub\VisualPaginator\Components\Control();
		$paginator->setTemplateFile(__DIR__ . '/../pagination.latte');
		$paginator->enableAjax();
		$paginator->onShowPage[] = function() {
			$this->redrawControl('my-snippet'); // my-snippet mi obaluje celou mou tabulku záznamů včetně paginatoru
		};

		return $paginator;
	}

díky za toto, vše funguje skvěle, jen mám maličkej bug, po kliknutí na stránku se mi vykreslí nový paginátor na webu. Neresil si tento problem?

jAkErCZ
Člen | 321
+
0
-

Chtěl sem dle tohoto návodu rozběhnout paginator ale přišel jsem na chybu…

Call to a member function count() on array
$paginator->itemCount = $reviews->count();

ReviewManager

/**
 * @return Vrátí jméno uživatele + překreslí user_id na jméno a příjmení
 */

public function getNameIdentification()
{

    $reviews = $this->database->table(self::TABLE_NAME)->order('(sent) DESC');

    $names = [];
    foreach ($reviews as $review) {
        $names[] = $review->user_id;
    }

    $use_name = $this->database->table(self::TABLE_USER)->where('user_id', $names)->select("user_id, CONCAT(first_name, ' ',last_name) AS use_names")->fetchPairs('user_id', 'use_names');

    $reviewsAsArray = [];
    foreach ($reviews as $review) {
        $reviewAsArray = $review->toArray();
        $reviewAsArray['user_id'] = isset($use_name[$reviewAsArray['user_id']]) ? $use_name[$reviewAsArray['user_id']] : null;
        $reviewsAsArray[] = $reviewAsArray;
    }

    return $reviewsAsArray;

}

Kde dělám chybu?

David Matějka
Moderator | 6445
+
0
-

@jAkErCZ vracis pole, ktere nema metody. na pole se pouziva klasicka funkce count(). a cela ta tva implementace je spatne, jelikoz tam zpracovavas vse z te tabulky self::TABLE_NAME, takze to bude pomale.

jAkErCZ
Člen | 321
+
0
-

David Matějka napsal(a):

@jAkErCZ vracis pole, ktere nema metody. na pole se pouziva klasicka funkce count(). a cela ta tva implementace je spatne, jelikoz tam zpracovavas vse z te tabulky self::TABLE_NAME, takze to bude pomale.

No tu funkci co mám mi vrací jméno místo id uživatele… proto to mám nebo jak to udělat jinak?

David Matějka
Moderator | 6445
+
0
-

standardni postup s nette database je, ze vratis $reviews a v sablone mas pak neco jako

{foreach $reviews as $review}
	{$review->user->first_name} {$review->user->last_name}
{/foreach}
jAkErCZ
Člen | 321
+
0
-

David Matějka napsal(a):

standardni postup s nette database je, ze vratis $reviews a v sablone mas pak neco jako

{foreach $reviews as $review}
	{$review->user->first_name} {$review->user->last_name}
{/foreach}

Však ale to mám

<div n:foreach="$reviews as $review" class="entry clearfix">
    <div class="entry-image">
        <div  class="fslider" data-arrows="false" data-lightbox="gallery">
            <div class="flexslider">
                <div class="slider-wrap">
                    <div n:for="$img = 0; $img < $review['images_count']; $img++" class="slide"><a href="{$basePath}/images/reviews/{$review['review_id']}/{$review['review_id']}_{$img}.jpg" data-lightbox="gallery-item"><img class="image_fade" src="{$basePath}/images/reviews/{$review['review_id']}/{$review['review_id']}_{$img}.jpg" alt="Standard Post with Gallery"></a></div>
                    <div n:if="!$review['images_count']">
                        <p><strong>Litujeme k této recenzi nebyli přidané žádné fotografie</strong></p>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="entry-title">
        <h2><a href="#">{$review['title']}</a></h2>
    </div>
    <ul class="entry-meta clearfix">
        <li><i class="icon-calendar3"></i> {$review['sent']|date:'j. n. Y H.i'}</li>
        <li><a href="#"><i class="icon-user"></i> {$review['user_id']}</a></li>
    </ul>
    <div class="entry-content">
        <p>{$review['content']|noescape}</p>
    </div>
</div>

Phalanx napsal(a):

@jAkErCZ Tohle není chyba v paginatoru. Máš chybně návrh – z metody vracíš assoc pole a pak voláš na pole ->count() (viz chybová hláška). Můžeš to sice opravit count($reviews), ale stejně tam musíš přidat offset a limit.

Osobně používám vždycky 2 metody u paginatorů

  1. jedna vrací počet položek, parametr $params, kde si předám potřebné parametry do where
  2. vrací data a má parametry většinou $params, $offset = null, $limit = 20

No teď jde o to že v té celé metodě co mám public function getNameIdentification() si spojuji user_id s jménem a příjemním člověka… A teď jak vyřešit to aby mi to takto fungovalo stále ale zároveň fachal ten peginator

David Matějka
Moderator | 6445
+
0
-

Však ale to mám

ne, mas tam uplne neco jinyho. precti si to znova.

edit: v te metode modelu nedelej to spojovani, jen vrat $reviews

jAkErCZ
Člen | 321
+
0
-

No a to spojováni udělám kde aby mi to fungovalo jako doposud?

David Matějka
Moderator | 6445
+
+1
-

Upravis, aby v sablone bylo:

{foreach $reviews as $review}
  {$review->user->first_name} {$review->user->last_name}
{/foreach}
jAkErCZ
Člen | 321
+
0
-

David Matějka napsal(a):

Upravis, aby v sablone bylo:

{foreach $reviews as $review}
  {$review->user->first_name} {$review->user->last_name}
{/foreach}

Super tohle funguje díky moc :)

jikki
Člen | 73
+
0
-

Ahoj, poradí někdo jak rozjet IPub\VisualPaginator s Doctrine místo Nette Database Explorer prosím?

Díky moc