Kombinované / zlúčené formuláre

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

Rad by som sa opytal, ci je technicky mozne, mat viac formularov naprogramovanych spolocne, v jednom createComponent*Form() za nasledujucich podmienok (polozky su [A-Z][0–9]):

spolocna cast formulara
S1, S2*, S3*…

FormA
A1, A2*..

FormB
B1, B2*…

FormC
C1*, C2…

SUBMIT (spolocny)

Frontend:
Uzivatel ma vzdy vidiet spolocnu cast… a potom si vyberie ako pokracuje, ale nema to byt viacstrankovy formular, ale na tej istej stranke… napr radio button + javascript, alebo iba prepinanie tw. bootstrap tabov a pod.

Problem:
Je problem s validaciou povinnych poli. Chcem ich mat oznacene ako povinne (aby sa vykreslovali spravne), ale ich automaticku validaciu chcem v pripade vyplnania inej sekcie potlacit.

Je to mozne? Ako sa to robi?
Ak nie, mate nejake napady?

duskohu
Člen | 778
+
0
-

Ahoj, v podstate si to urob ako jeden formular, ale prvky tam budes pridavat podla toho ako chces.Pridas si tam ovladacie prvky napr. : buttonA, buttonB, buttonC a samozrejme buttonSend, kazdy bude mat svoje spracovanie na prve 3 naviazes ->setValidationScope(FALSE) aby ti formular nevalidovalo a v metodach budes pridavat do formulara dalsie prvky a nasledne invalidujes snippet. cize sa ti formular prekresli. Este som to takto nepotreboval riesit tak predpokladam ze este budes musiet riesit nejake doladovacky.

duskohu
Člen | 778
+
0
-

Pisem z hlavy

	protected function createComponentForm()
	{
		$form = new Form;
		$form->addText('for-all', 'Text');

		$form->addSubmit('formA', 'formA')
			->setValidationScope(FALSE)
			->onClick[] = callback($this, 'processFormA');

		$form->addSubmit('formB', 'formB')
			->setValidationScope(FALSE)
			->onClick[] = callback($this, 'processFormB');

		$form->addSubmit('formC', 'formC')
			->setValidationScope(FALSE)
			->onClick[] = callback($this, 'processFormC');

		$form->addSubmit('send', 'Send')
			->setValidationScope(FALSE)
			->onClick[] = callback($this, 'processSend');

		return $form;
	}

	public function processFormA(Form $form){
		$this['form']->addText('for-a', 'Text');
		$this->invalidateControl();
	}

	public function processSend(Form $form){
		// send
	}
Tomas P
Člen | 27
+
0
-

Tyjo, super, vdaka… to je presne co potrebujem.

Skoda ze v SubmitButton.php je len todo :-)

<?php
	public function setValidationScope($scope)
	{
		// TODO: implement groups
		$this->validationScope = (bool) $scope;
		...
?>

A ked pouzijem invalidateControl so snippetom, musim to mat poriesene ajaxom? Mne nevadi reload ak to bude vyzerat rovnako a zapamata si to hodnoty co uz raz boli vyplnene.

Dik za priklad, vela to ozrejmilo.
Hlavny submit ale asi dam do processFormA/B/C() a uz s validaciou, aby sa form nedal poslat este pred doplnenim A/B/C.

Velmi pekne dakujem.

Tomas P
Člen | 27
+
0
-

Hmm…
nejak mi to nechce v poslednom kroku zavolat submit handler… je to divne.

prepinanie formularov funguje spravne … dokonca sa ani nescitaju polozky z A/B/C, co ma milo prekvapilo, som sa bal ze uz bude formular v parametri process*() vacsi, ale nie je.

Problem mam ale s tym, ze ked kliknem na zaverecny submit (pridany dielcim submitom), formular sa iba reloadne a zostane sice vyplneny (pamata si hodnoty), ale nezavola sa moj handler.
Skusal som v dielcom process*() pridat aj onSuccess[], ale to sa aplikovalo vzdy po kazdom stlaceni.

Toto je kod (je to s nejakym placeholder textom ohladne mena, originalne to potrebujem na nieco ovela vacsie :-) ).

<?php
	public function createComponentServiceForm()
	{
		$form = new Form;

		$form->addText('firstname', 'Jméno')
			->setRequired('Vyplňte jméno');
		$form->addText('lastname', 'Příjmení')->setRequired('Příjmení');

		$form->addSubmit('a', 'first')
			->setValidationScope(false)
			->onClick[] = callback($this, 'processA');

		$form->addSubmit('b', 'second')
			->setValidationScope(false)
			->onClick[] = callback($this, 'processB');

		$form->addSubmit('c', 'third')
			->setValidationScope(false)
			->onClick[] = callback($this, 'processC');

		return $form;
	}

	public function processA(Nette\Forms\Controls\SubmitButton $button)
	{
		$form = $button->getForm();

		$form->addText('title_before', 'Titul před jménem')
			->setRequired('Titul před jménem');

		$form->addSubmit('submit', 'submit')
			->onClick[] = callback($this, 'serviceSubmit');

	}

	public function processB(Nette\Forms\Controls\SubmitButton $button)
	{
		$form = $button->getForm();

		$form->addText('title_after', 'Titul za')
			->setRequired('Titul za');

		$form->addSubmit('submit', 'submit')
			->onClick[] = callback($this, 'serviceSubmit');

	}

	public function processC(Nette\Forms\Controls\SubmitButton $button)
	{
		$form = $button->getForm();

		$form->addText('middle_name', 'Další jméno')
			->setRequired('Další jméno');

		$form->addSubmit('submit', 'submit')
			->onClick[] = callback($this, 'processForm');


	}

	public function processForm(Nette\Forms\Controls\SubmitButton $button)
	{
		dump($button);
		exit;
	}

?>

Neviem ci nezavolanie mojho handleru je sposobene chybou kodu alebo je to bug, alebo sa tlacitka nesmu pridavat v handleroch onClick… neviem ani ako by som to debugoval, kedze to nevola to co chcem.

--

Potom som si povedal, ze este nieco vyskusam…

<?php

	public function createComponentServiceForm()
	{
		//...
		$form->onSuccess[] = callback($this, 'processFullForm');
	}

	// ostatne sa nemenili

	public function processFullForm(Form $form)
	{
		if ($form->submitted === true) {
			$this->flashMessage('submit button');
		} else {
			$button = $form->submitted->name;
			$this->flashMessage($button);
		}

		return;
	}
?>

tu uz je jednoznacne co sa ma vykonat v zaverecnom submit handleri.
onClick posledneho tlacitka sa stale nevola.
Problem je, ze ked si dumpnem $form->getValues(), tak chyba to co som pridal onClick funkciou. Takze je to stale nepouzitelne :-(

Tomas P
Člen | 27
+
0
-

Uz som si vsimol, ze mam v A a B callback na „serviceSubmit“ ktory neexistuje, ale to nie je kamen urazu.

duskohu
Člen | 778
+
0
-

Hmmm, to bude preto lebo ked sa formular spracuvava v processForm tak neobsahuje polozky ktore sa mu pridali v A,B, alebo C, tym padom dumpnes len zakladne polozky. Este ma napadlo toto, len neviem ci je to ciste.

	protected function attached($presenter)
	{
		if ($presenter instanceof Presenter) {

			/** @var Form $form */
			$form = $this['form'];
			$form->addSubmit('submit', 'submit')
				->onClick[] = callback($this, 'processForm');
		}
		parent::attached($presenter);
	}


	/**
	 * FORM Page
	 * @return Form
	 */
	protected function createComponentForm()
	{
		$form = new Form;

		$form->addText('firstname', 'Jméno');
		$form->addText('lastname', 'Příjmení');

		$form->addSubmit('submitByA', 'first')
			->setValidationScope(FALSE)
			->onClick[] = callback($this, 'processA');

		$form->addSubmit('submitByB', 'second')
			->setValidationScope(FALSE)
			->onClick[] = callback($this, 'processB');

		$form->addSubmit('submitByC', 'third')
			->setValidationScope(FALSE)
			->onClick[] = callback($this, 'processC');

		return $form;
	}


	/**
	 * @param Form $form
	 */
	private function setAForm($form)
	{
		$form->addText('title_before', 'Titul před jménem');
		$form->addHidden('formType')
			->setValue('A');
	}


	public function processA(\Nette\Forms\Controls\SubmitButton $button)
	{
		$form = $this['form'];
		$this->setAForm($form);
	}


	public function processForm(\Nette\Forms\Controls\SubmitButton $button)
	{
		$form = $button->getForm();
		$values = $form->getHttpData();
		if ($values['formType']) {
			$this->setAForm($form);
		}
		dump($values);
	}
duskohu
Člen | 778
+
0
-

Inak dalsia varianta: v presenteri, alebo komponente budes mat persistentni parameter reprezentujuci A,B,C na zaklade neho budes vediet aky formular potrebujes a nasledne poskladas variantu koru potrebujes. Parameter budes prepinat odkazom.

Tomas P
Člen | 27
+
0
-

jj, toto (7.) ma tiez napadlo.

ze by som v tom finalnom handleri podla niecoho co je v tom povodnom formulari (teda addHidden() v createComponentForm) zavolal rozsirenie formulara jednou z processA/B/C funkcii. A snad tym ze samotny HTTP POST data obsahuje, ze by sa mi tam objavili.

prislo mi to ale dost skarede, tak asi spravim 3 formulare a bude to len trosku menej user friendly ale zato naprogramovane pouzitim normalnych, zdokumentovanych postupov. v kode mozem mat jednotlive casti rozdelene vo funkciach a tak ako pises v dalsom poste, si to len poskladam.

skoda ze to nette nevie (ciastocne obmedzenie validacie), ked budem mat cas by som sa na to mal pozriet, ci je to skutocne tak velky problem. v Drupal7 to je aj s kopou inych veci, ktore mi v nette chybaju :-(.

Inak podla tychto zisteni mam pocit ze v nette nielen ze nejde spravit to co som chcel ja (tj. obmedzit validationScope), ale nefunguju ani viacstrankove formulare nijak jednoducho…

duskohu
Člen | 778
+
0
-

Takze mi to nedalo. Funkcne riesenie:

	/** @persistent */
	public $type;


	protected function createComponentForm()
	{
		$form = new Form;

		$form->addText('firstname', 'Jméno');

		if ($this->type == 'a') {
			$form->addText('lastname', 'Příjmení');
			$form->addSubmit('submit', 'submit');
			$form->onSuccess[] = callback($this, 'processForm');
		}
		return $form;
	}


	public function processForm(Form $form)
	{
		$values = $form->getValues();
		dump($values);
	}

latte:

{control form}

<a n:href="this type=>a">aaaa</a>