Formulář v komponentě – ztráta ID

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

Zdravím a prosím o radu – vysvětlení.

Mám formulář v komponentě, který odesílám Ajaxem. Vše funguje až do doby, kdy tam přidám onu kontrolu na $id, protože chci použít form pro vkládání i editaci uživatelů a při editaci bude heslo nepovinné, pro vkládání povinné.

Chová se to tak, že pokud zadám heslo je vše ok, form se odešle a uloží. Pokud nezadám heslo, formulář se neodešle a ani to nedumpne nějakou chybu.

Snažím se to krokovat a jeví se mě to tak, že po kliknutí na submit se nejprve překresluje formulář, kde je ale v tu chvíli $id null …

Form vytvářím klasicky přes továrnu.

Co mě prosím uniká? Moc díky!

/**
     * @return Form
     */
    public function createComponentForm() {

	$form = $this->formFactory->create();
	$form->getElementPrototype()->class('ajax');
	$form->addHidden('id');
	$form->addText('name', 'Celé jméno: ')
		->setRequired('Zadejte celé jméno.');
	$form->addText('username', 'Uživatel: ')
		->setRequired('Zadejte uživatelské jméno.');


	$id = $this->getPresenter()->getComponent('usersGrid')->getParameter('id');

	If (!$id) {
	    $form->addPassword('password', 'Heslo: ')
		    ->setRequired('Zadejte heslo');;
	    $form->addPassword('passwordVerify', 'Heslo pro kontrolu: ')
		    ->addConditionOn($form["password"], Form::FILLED)
		    ->addRule(Form::EQUAL, "Hesla se musí shodovat!", $form["password"]);
	} else {
	    $form->addPassword('password', 'Heslo: ');
	    $form->addPassword('passwordVerify', 'Heslo pro kontrolu: ')
		    ->addConditionOn($form["password"], Form::FILLED)
		    ->addRule(Form::EQUAL, "Hesla se musí shodovat!", $form["password"]);
	}

	$form->addSelect('role', 'Oprávnění', array('user' => 'user', 'admin' => 'admin'));
	$form->addSubmit('send', 'Uložit');
	$form->onSuccess[] = array($this, 'formSucceeded');


	if ($id) {
	    $r = $this->usersModel->getUsersTable()->where('id', $id)->fetch();
	    if (!$r) {
		throw new Nette\Application\BadRequestException;
	    }
	    $form->setDefaults($r);
	}
	return $form;
    }

Editoval MW (31. 1. 2017 15:11)

MW
Člen | 615
+
0
-

Přišel jsem na toto.. co vy na to? Lze to takto?
Ta komponenta gridu to ID asi ztrati…

public function createComponentForm() {

	$form = $this->formFactory->create();
	$form->getElementPrototype()->class('ajax');
	$form->addHidden('id');
	$form->addText('name', 'Celé jméno: ')
		->setRequired('Zadejte celé jméno.');
	$form->addText('username', 'Uživatel: ')
		->setRequired('Zadejte uživatelské jméno.');

	If (empty($form['id'])) { // **************************tato podmínka
	    $form->addPassword('password', 'Heslo: ')
		    ->setRequired('Zadejte heslo');;
	    $form->addPassword('passwordVerify', 'Heslo pro kontrolu: ')
		    ->addConditionOn($form["password"], Form::FILLED)
		    ->addRule(Form::EQUAL, "Hesla se musí shodovat!", $form["password"]);
	} else {
	    $form->addPassword('password', 'Heslo: ');
	    $form->addPassword('passwordVerify', 'Heslo pro kontrolu: ')
		    ->addConditionOn($form["password"], Form::FILLED)
		    ->addRule(Form::EQUAL, "Hesla se musí shodovat!", $form["password"]);
	}

	$form->addSelect('role', 'Oprávnění', array('user' => 'user', 'admin' => 'admin'));
	$form->addSubmit('send', 'Uložit');
	$form->onSuccess[] = array($this, 'formSucceeded');


	$id = $this->getPresenter()->getComponent('usersGrid')->getParameter('id');
	if ($id) {
	    $r = $this->usersModel->getUsersTable()->where('id', $id)->fetch();
	    if (!$r) {
		throw new Nette\Application\BadRequestException;
	    }
	    $form->setDefaults($r);
	}
	return $form;
    }

Editoval MW (31. 1. 2017 15:41)

Šaman
Člen | 2634
+
+2
-

To $id musíš komponentě předat, nejspíš v action metodě. Jen formulář si ho získá z POSTu sám (pokud odeslaná data to $id obsahovala).
A načítat nějaká data z jiné komponenty není vůbec hezké – pokud spolu maji úzce spolupracovat, tak je lepší je obalit nějakou nadkomponentou. Ale jestli to dobře chápu, tak ten formulář nyní vyžaduje, aby byl k presenteru připojený (a správně nastavený) i Grid, jinak nebude fungovat. To je typická ukázka skryté závislosti.

MW
Člen | 615
+
0
-

Asi ano :)
Mám v presenteru obě komponenty :

public function createComponentUsersGrid() {
	return $this->usersGridControlFactory->create();
    }

public function createComponentEditForm() {
	return $this->userEditFormControlFactory->create();
    }

no a v šabloně gridu pak lovím

{control $presenter->getComponent('editForm')}

Jak bych to měl správně dát dohromady? .. přiznám se, že se mě to taky nelibí..

Snažím se v Ublaboo gridu udělat editaci v modálním okně, což mě teď funguje dobře, ale rád bych to měl líp :)
Ted jsem obsluhu modálů přidal do komponenty Gridu, ale važně blbě (nepřehledně) se posílají data mezi gridem, formulářem, modelem a ted i něco do presenteru :/

Mohu poprosit o nějaký vzor, jak to spojit?

Moc díky!

Editoval MW (31. 1. 2017 16:41)

CZechBoY
Člen | 3608
+
0
-

Co podědit grid nebo attachnout mu tu tvoji komponentu s formem? Jestli nemáš form v komponentě tak bych zkusil udělat komponentu s formem a vlastní šablonou (v které by byl ten modál).

MW
Člen | 615
+
0
-

myslis tedy treba konstruktorem pridat form do komponenty gridu?

CZechBoY
Člen | 3608
+
+1
-

Připojit ke Gridu komponentu MujModal → třeba v actionXXX připojíš přes addComponent komponentu mujModal + nějak připojit do template

class MujPresenter extends UI\Presenter
{
	public function actionDefault()
	{
		$modal = $this->modalFactory->create();
		$this['mujGrid']->addComponent($modal, 'modal');
		$this['mujGrid']->setTemplateFile('GridModal.latte');
	}

	protected function createComponentMujGrid()
	{
		return $this->gridFactory->create();
	}
}

GridModal.latte

{extends $original_template}

{control modal}

Editoval CZechBoY (31. 1. 2017 17:54)

MW
Člen | 615
+
0
-

Moc díky.. zkusím to nějak takto udělat…

MW
Člen | 615
+
0
-

Upravi jsem to, ale stále mě dobře nefunguje podmínka ve formuláři

If(is_null($form['id']))

to id je stále null :/.. tedy se ten formulář při odeslání nějak znovu rendruje a id se do něj dostane až pozdě… proč?

Presenter:

public function actionDefault($id) {

	$this->id = $this->getComponent('usersGrid')->getParameters('id');
	$this['usersGrid']->addComponent($this->userEditFormControlFactory->create(), 'editForm');

	if($this->id) {
	    $r = $this->userModel->getUsersTable()->where('id', $this->id)->fetch();
	    if (!$r) {
		throw new Nette\Application\BadRequestException;
	    }
	    $this['usersGrid-editForm-form']->setDefaults($r);
	}
    }

    public function setId($id) {
	$this->id = $id;
    }

Komponenta formu:

lass UserEditFormControl extends Control {

    /** @var FormFactory */
    private $formFactory;


    public function __construct(FormFactory $formFactory) {
	$this->formFactory = $formFactory;
     }

    /**
     * @return Form
     */
    public function createComponentForm() {

	$form = $this->formFactory->create();
	$form->getElementPrototype()->class('ajax');
	$form->addHidden('id');
	$form->addText('name', 'Celé jméno: ')
		->setRequired('Zadejte celé jméno.');
	$form->addText('username', 'Uživatel: ')
		->setRequired('Zadejte uživatelské jméno.');

	If(is_null($form['id'])) {
	    $form->addPassword('password', 'Heslo: ')
		    ->setRequired('Zadejte heslo');;
	    $form->addPassword('passwordVerify', 'Heslo pro kontrolu: ')
		    ->addConditionOn($form["password"], Form::FILLED)
		    ->addRule(Form::EQUAL, "Hesla se musí shodovat!", $form["password"]);
	} else {
	    $form->addPassword('password', 'Heslo: ');
	    $form->addPassword('passwordVerify', 'Heslo pro kontrolu: ')
		    ->addConditionOn($form["password"], Form::FILLED)
		    ->addRule(Form::EQUAL, "Hesla se musí shodovat!", $form["password"]);
	}

	$form->addSelect('role', 'Oprávnění', array('user' => 'user', 'admin' => 'admin'));
	$form->addSubmit('send', 'Uložit');
	$form->onSuccess[] = array($this, 'formSucceeded');

	return $form;
    }

    public function formSucceeded(Form $form, $values) {

	unset($values->passwordVerify);
	$this->getPresenter()->getComponent('usersGrid')->saveData($values);
    }

    public function render() {
	$this['form']->render();
    }

}

V komponentě gridu mám handle:

public function handleEditModal($id) {

	$this->getPresenter()->setId($id);
	$this->redrawControl('editForm');
	$this->redrawControl('showModal');
    }
CZechBoY
Člen | 3608
+
0
-

Počkej… já myslel že to ID bude vědět jen presenter.

MW
Člen | 615
+
0
-

Ideálně ano.. asi na to jdu blbe :/ – nevím jak to udělat správně…

Snažím se mít jeden form pro add a edit, ale s tím, že to heslo je v editaci nepovinné..
(Kdybych udělal dva formy, už bych to měl).. ale zajímá mě, jak by to šlo jinak :)

CZechBoY
Člen | 3608
+
0
-

A teda přes ten handle chceš pouze zobrazit modal? Zkus v tom handlu nastavit akci formuláře na nějakou akci edit, id => $id. V tý akci potom nastavit do formu IDečko.

MW
Člen | 615
+
0
-

myslis v handlu zavolat akci, ktera zavola setDefaults na form nebo i v komponente formu definovat dalsi id?

CZechBoY
Člen | 3608
+
0
-

V handlu nastavit akci formu (asi atribut action nebo možná existuje nějaká metoda $form->setAction).

MW
Člen | 615
+
0
-

Zkoumám to setAction, ale přiznám se, ze nevím co s tím .. tedy pokud chci zachovat, že ID bude řízeno presenterem…

CZechBoY
Člen | 3608
+
0
-

Bude řízený tak napůl. ID do presenteru „předá“ ten handle.
Něco jako tohle (píšu z founu)

Komponenta

function handleEditForm($id)
{
   $this['form']->setAction($this->getPresenter()->link('edit', ['id' => $id]));
  // Redraw atd
}

Presenter

function actionEdit($id)
{
  $this['form']->setId($id);
}
MW
Člen | 615
+
0
-

Ten handle neví o žádné komponentě … ani když chci jít přes presenter:

$this->getPresenter()->getComponent('usersGrid-editForm-form')->setAction($this->getPresenter()->link('edit', ['id' => $id]));

To jsem to ale blbe navrhnul, co .. :)

Editoval MW (2. 2. 2017 22:28)

CZechBoY
Člen | 3608
+
0
-

Ajo, asi jsem se v tom zamotal :D
Takže znova. Pro pochopení to radši projdeme celý znova :-)

V actionDefault vytváříš grid pro seznam uživatelů – tady vytvoříš grid, formulář a formulář připojíš ke gridu (v tomto momentě ještě nevíš jestli použiješ/odešleš add nebo edit variantu formuláře).
V šabloně potom přidáš nějaký modální okno s editačním formulářem (to se načte ajaxově), parametr je dynamický.
Handle nastaví akci formuláře na edit, id => $id.
V actionEdit($id) připojíš form zase ke gridu, ale nastavíš ještě ID formuláři přes to ->setId($id).

Takhle by to snad mohlo jet… ale je možný že jsem něco nedomyslel nebo zbytečně zkomplikoval.

MW
Člen | 615
+
0
-

Už ti rozumím, moc díky!
Ale stejně mě není jasny proč se děje to, že form, který je naplněný přes setDefault a obsahuje všechny data, se při odeslaní znovu sestavuje ale už nezná svoje pův. hodnoty – viz ona podmínka s $form[‚id‘]..

Přijde mě to jen děsně složity.. :) To mě fakt nutí udělat dva formuláře.