Problém persistentního parametru při zpracování formuláře

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Jarek92
Člen | 91
+
0
-

Zdravím,
řeším následující problém. Mám výpis položek na stránce, které se přidávají a mažou AJAXově (metodami handle…). Vše funguje v pořádku, nicméně mám také implementované stránkování. Pokud chci přejít na další stránku, obstará to metoda handleMore(), která zvýší aktuální stránku o 1 a načte další data. Nicméně, pokud jsem např. na stránce č. 3 a chci přidat novou položku, tak v metodě addBoardFormSucceded je persistentní parametr nastaven na výchozí hodnotu (1).

BoardPresenter:

const BOARDS_PER_PAGE = 6;

    public $paginator;

    /** @var int @persistent */
    public $page = 1;

public function addBoardFormSucceded(\Nette\Application\UI\Form $form, $values) {
        $user = \Model\Entities\Services\UserService::loadFromSession($this->getUser());
        if($values->boardId == 0) {
            $newBoard = \Model\Entities\Services\BoardService::create($values, $user);
        } else {
            $newBoard = \Model\Entities\Services\BoardService::loadForUpdate($values->boardId, $values->content);
        }
        $this->boardFacade->save($newBoard);

        if($this->isAjax()) {
            if($values->boardId == 0) {
                $form->setValues([], TRUE);
                $this->redrawControl("addBoard");
            } else {
                $form->setValues(array("content" => $newBoard->content));
                $this->template->edit = true;
                $this->redrawControl("editBoard");
            }
            $this->setupPaginator();
            $this->template->boards = $this->boardFacade->findAll($this->getLimit());
            $this->redrawControl("boards");
            $this->redrawControl("paginator");
        } else {
            $this->redirect("this");
        }
    }

    public function getLimit() {
        return $this->page * self::BOARDS_PER_PAGE;
    }

    public function setupPaginator() {
        $this->paginator->setItemCount($this->boardFacade->getAllCount());
        $this->paginator->setPage($this->page);
        $this->template->paginator = $this->paginator;
    }

public function handleMore() {
        if ($this->isAjax()) {
            $this->page += 1;
            $this->paginator->setPage($this->page);
            $this->template->boards = $this->boardFacade->findAll($this->getLimit());
            $this->redrawControl("boards");
            $this->redrawControl("paginator");
	}
        else {
            $this->redirect("this");
        }
    }

V jiných metodách mám hodnotu proměnné page aktuální, proč ji nemám také v metodě addBoardFormSucceded?

Tharos
Člen | 1030
+
0
-

Budu asi trochu věštit (neposlal jsi úplně celý kód), ale třeba se trefím… :)

Hodnoty persistentních parametrů sice do URL adres přidává Nette automaticky, ale platí, že v URL adresách musí být explicitně přítomné. Jinak se skončí na defaultní hodnotě.

V tvém případě bych tedy zkontroloval, jaká URL je v action formuláře addBoardForm ve vygenerované šabloně. Tipuji, že v ní ten parametr page chybí, a proto se tam ztrácí stav, resetuje se na defaultní hodnotu.

A proč tam chybí? Jelikož pracuješ s AJAXem, můj soukromý tip je, že ten formulář nemáš správně obalený snippetem (anebo ho neinvaliduješ), takže se HTML reprezentace toho formuláře při stránkování nepřekresluje a tím se nemění action podle aktuální hodnoty parametru page. :)

Editoval Tharos (17. 10. 2016 1:29)

Jarek92
Člen | 91
+
0
-

Díky moc, pomohlo překreslování snippetu addBoardForm při stránkování (v metodě handleMore). Akorát když se nacházím na poslední stránce a přidám nový příspěvek, tak si po překreslení Paginator myslí, že ještě není na poslední stránce, ale po kliku na „další“ se už zobrazí „žádné další příspěvky“. Ale to bude zřejmě chyba v počítání Paginatoru.

Jarek92
Člen | 91
+
+1
-

Tak nakonec vyřešeno, přikládám funkční kód, kdyby někdo řešil podobný problém. :)

Díky @Tharos.

BoardPresenter.php

class BoardPresenter extends BasePresenter {

    const BOARDS_PER_PAGE = 6;

    /** @var int @persistent */
    public $page = 1;

    private $boardFacade;
    private $addBoardForm;
    private $paginator;

    public function injectBoardFacade(BoardFacade $boardFacade) {
        $this->boardFacade = $boardFacade;
    }

    public function injectAddBoardForm(AddBoardForm $addBoardForm) {
        $this->addBoardForm = $addBoardForm;
    }

    public function createComponentAddBoardForm() {
        return $this->addBoardForm->create();
    }

    public function getLimit() {
        return $this->page * self::BOARDS_PER_PAGE;
    }

    public function setupPaginator() {
        if(!isset($this->paginator)) {
            $this->paginator = new Paginator($this->boardFacade->getAllCount(), self::BOARDS_PER_PAGE);
            $this->paginator->setPage($this->page);
        } else {
            $this->paginator->setItemCount($this->boardFacade->getAllCount());
        }
        $this->template->paginator = $this->paginator;
    }

    public function actionDefault() {
        $this->setupPaginator();
        try {
            $this->template->boards = $this->boardFacade->findAll($this->getLimit());
        } catch (EntitiesNotFoundException $ex) {
            \Tracy\Debugger::log($ex);
            $this->template->boards = null;
        } finally {
            $this->template->edit = false;
        }
    }

    public function handleUpdate($boardId) {
        try {
            $board = $this->boardFacade->findOneById($boardId);
            $this["addBoardForm"]->setDefaults(array("boardId" => $board->id, "content" => $board->content));
        } catch (EntityNotFoundException $ex) {
            \Tracy\Debugger::log($ex);
        } finally {
            if($this->isAjax()) {
                $this->redrawControl("editBoard");
            } else {
                $this->redirect("this");
            }
        }
    }

    public function handleDelete($boardId) {
        try {
            $board = $this->boardFacade->findOneById($boardId);
            if($this->user->id == $board->user->id) {
                $this->boardFacade->delete($boardId);
                $this->template->boards = $this->boardFacade->findAll($this->getLimit());
            } else {
                $this->flashMessage("K této akci nemáš oprávnění!", "alert-danger");
            }
        } catch (EntityNotFoundException $ex) {
            \Tracy\Debugger::log($ex);
            $this->flashMessage("Požadovaný příspěvek nebyl nalezen.", "alert-danger");

        } catch (EntitiesNotFoundException $ex) {
            \Tracy\Debugger::log($ex);
            $this->template->boards = null;
        } finally {
            $this->setupPaginator();
            if($this->isAjax()) {
                $this->redrawControl("flashes");
                $this->redrawControl("boards");
                $this->redrawControl("paginator");
            } else {
                $this->redirect("this");
            }
        }
    }

    public function handleChangeProper($boardId) {
        try {
            $board = $this->boardFacade->findOneById($boardId);
            if(($this->user->isAllowed("ImproperBoard")) && ($this->user->id == $board->user->id)) {
                $board->changeProper();
                $this->boardFacade->save($board);
                $this->template->boards = $this->boardFacade->findAll($this->getLimit());
            } else {
                $this->flashMessage("K této akci nemáš oprávnění!", "alert-danger");
            }
        } catch (EntityNotFoundException $ex) {
            \Tracy\Debugger::log($ex);
            $this->flashMessage("Požadovaný příspěvek nebyl nalezen.", "alert-danger");
        } catch (EntitiesNotFoundException $ex) {
            \Tracy\Debugger::log($ex);
            $this->template->boards = null;
        } finally {
            if($this->isAjax()) {
                $this->redrawControl("flashes");
                $this->redrawControl("boards");

            } else {
                $this->redirect("this");
            }
        }
    }

    public function handleMore() {
        if ($this->isAjax()) {
            $this->page += 1;
            $this->paginator->setPage($this->page);
            $this->template->boards = $this->boardFacade->findAll($this->getLimit());
            $this->redrawControl("paginator");
            $this->redrawControl("addBoard");
            $this->redrawControl("boards");
	}
        else {
            $this->redirect("this");
        }
    }
}

AddBoardForm.php

class AddBoardForm extends \Nette\Application\UI\Control {

    private $boardFacade;

    public function __construct(BoardFacade $boardFacade) {
        parent::__construct();
        $this->boardFacade = $boardFacade;
    }

    public function create() {
        $form = new Form();
        $form->setRenderer(new BootstrapVerticalRenderer());
        $form->getElementPrototype()->class("ajax");
        $form->addTextArea("content")
             ->setAttribute("rows", 5)
             ->setRequired("Zadej prosím text příspěvku.");
        $form->addHidden("boardId", 0);
        $form->addSubmit("submit");
        $form->onSuccess[] = array($this, "addBoardFormSucceded");
        return $form;
    }

    public function addBoardFormSucceded(Form $form, $values) {
        $user = UserService::loadFromSession($form->getPresenter()->getUser());
        if($values->boardId == 0) {
            $newBoard = BoardService::create($values, $user);
        } else {
            $newBoard = BoardService::loadForUpdate($values->boardId, $values->content);
        }
        $this->boardFacade->save($newBoard);
        if($form->getPresenter()->isAjax()) {
            if($values->boardId == 0) {
                $form->setValues([], TRUE);
                $form->getPresenter()->redrawControl("addBoard");
            } else {
                $form->setValues(array("content" => $newBoard->content));
                $form->getPresenter()->getTemplate()->edit = true;
                $form->getPresenter()->redrawControl("editBoard");
            }
            $form->getPresenter()->setupPaginator();
            $form->getPresenter()->getTemplate()->boards = $this->boardFacade->findAll($form->getPresenter()->getLimit());
            $form->getPresenter()->redrawControl("boards");
            $form->getPresenter()->redrawControl("paginator");
        } else {
            $form->getPresenter()->redirect("this");
        }
    }
}