měnitelný počet formulářových elementů

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

Ahoj,

potřeboval bych udělat selectbox, kde vyberu počet a po odkliknutí se mi zobrazí vybraný počet textinputů.

našel jsem na githubu addDynamic od Hosiplana, ale neumím to upravit na požadované chování.

Mohl by mě někdo prosím nasměrovat správnou cestou?

díky

vladimir
Člen | 11
+
0
-

Já bych to asi řešil nějak takhle, přes Sessions. Podle hodnoty v selectboxu bych vytvoril dodatecna policka formulare, a v sessions bych si pamatoval predchozi obsah, aby kdyz uzivatel prihodi vic radku, predchozi data nezmizela. Ale jelikoz s Nette si hraju teprv chvili, tak to je mozna uplne zcestny reseni a rad se poucim jak lepe to resit :-)

MujPresenter.php

<?php
public function renderAdd($active = false)
{
	$session = $this->session->getSection('mySess');
	if ($active != true)
	{
		// pokud kreslim formular poprve, smazu si session z minula
		$session->remove();
	}
	else
	{
		//pokud naopak jen upravuju pocet inputu, naplnim predchozi hodnoty ze session
		if (isset($session))
		{
			$this['myForm']->setDefaults($session->form);
		}
	}
}

public function createComponentMyForm($name)
{
	$session = $this->session->getSection("mySess");
	$rows = (isset($session->form['rows'])) ? $session->form['rows'] : 2; //def je 2

	$form = new Nette\Application\UI\Form;
	$ints = array(); //nejak naplnit selectbox
	for($i = 0; $i < 10; $i++)
	{
		$ints[$i] = $i;
	}

	$form->addSelect('rows', "Textboxů:", $ints)->setDefaultValue($rows);
	$form->addSubmit("submit", "Vytvořit textboxy")
		->setValidationScope(NULL)
		->onClick[] = callback($this, "fillTextboxs");

	$textboxs = $form->addContainer('textboxs');
	for ($i = 1; $i <= $rows; $i++)
	{
		$sec = $textboxs->addContainer($i);
		$sec->addText('inp', 'Input ' . $i . ':');
	}

	return $form;
}

public function fillTextboxs()
{
	// zapamatuju si co bylo ve formulari
	$session = $this->session->getSection('mySess');
	$session->form = $this['myForm']->getValues();
	// a uzivatele presmeruju na formular s novym poctem inputu
	$this->redirect('this', array('active' => TRUE));
}
?>

add.latte

{control myForm}
Ot@s
Backer | 476
+
0
-

Psano z hlavy… Nezapomnět zaregistrovat addDynamic dle návodu.

$form = new Nette\Application\UI\Form;

// vyber poctu
$form->addSelect('count', 'Pocet', range(1,10) )->addRule(Nette\Application\UI\Form::FILLED, 'Zvolte pocet...');

if ($form->isSubmitted()) {
   // jméno, továrnička, výchozí počet
   $replicator = $form->addDynamic('textFields', function (Container $container) {
       $i = (int) $container->getName();
       $container->addText('text', 'Textbox c. '.$i);
   }, $form['count']->getValue() );
   $form->addSubmit('save', 'Ulozit obsah textboxu')
       ->onClick[] = callback($this, 'saveResult');
} else {
   $form->addSubmit('show', 'Zobraz textboxy');
}

return $form;

Editoval Ot@s (14. 10. 2011 9:35)

colek
Člen | 59
+
0
-

Tak tohle se mi nepodařilo rozchodit, ale nakonec jsem si uvědomil, že v tom hledám asi zbytečnou složitost…

co takhle?

$form->addText('age0', 'Věk osoby č. 1');
if ($form->isSubmitted()) {

      for($i = 1;$i <= $form['count']->getValue() + 1 ; $i++){
        $form->addText('age'.$i, 'Věk osoby č. '.($i + 1));
      }
       //$form->addText('age'.$i, 'Věk');
} else {
   $form->addSelect('count', 'Počet dalších osob', range(1,10) )->addRule(\Nette\Application\UI\Form::FILLED, 'Zvolte pocet...');
   $form->addSubmit('show', 'Zobrazit další pole')->setValidationScope(FALSE) ;
}

Takhle mi to funguje tak jak chci. Jen bych se ještě zeptat, jak to zajaxovatět? Aby se to načetlo po změně toho selectboxu, abych na to nemusel klikat „Zobrazit další pole“.

díky moc

Ot@s
Backer | 476
+
0
-

colek napsal(a):
Takhle mi to funguje tak jak chci. Jen bych se ještě zeptat, jak to zajaxovatět? Aby se to načetlo po změně toho selectboxu, abych na to nemusel klikat „Zobrazit další pole“.

Asi bys musel formulář manuálně rozepsat v šabloně. Část, ketrou cheš „ajaxovat“ dát do snippetu, na ovládací formulářový prvek navěsit onchange/onblure a pomocí JS submitnout formulář (nebo v tom samém JS nasimuluješ signál s parametrem počtu vypisovaných formuklářovýchy polí).

colek
Člen | 59
+
0
-

díky za nakopnutí. Pustil jsem se do toho s vervou ale ani po dnu zkoušení jsem to nerozchodil… Udělal jsem různí varianty téhož: (osekal jsem to o ten cyklus, mělo by to přidávat jeden prvek, snad pochopíte co mám v plánu :) )
V šabloně mám

<tr>
    <th>{label count /}</th>
    <td>{input count}</td>
</tr>
{snippet formular}
{if isset($potvrzeni)}
<tr>
    <th>text</th>
    <td>{input age_1}</td>
</tr>
{/if}
{/snippet}

a presenter:

  $form->addSelect('count', 'Pocet', range(1,10) )->addRule(\Nette\Application\UI\Form::FILLED, 'Zvolte pocet...')
  ->getControlPrototype()->onChange("submit()");
$form->addText('age_0', 'Věk osoby č. 1');
if ($form->isSubmitted()) {
    $this->invalidateControl('formular');
    $this->template->potvrzeni = true;
       $form->addText('age_1', 'Věk osoby č. XXX');


}

Pokusil jsem se udělat to co mi napsal Ot@s, ale evidentně jsem někde pochybil.

díky za radu

Ot@s
Backer | 476
+
0
-

colek napsal(a):

Pokusil jsem se udělat to co mi napsal Ot@s, ale evidentně jsem někde pochybil.

díky za radu

  1. Připomínám, že budeš potřebovat ajaxové formuláře a JQuery
  2. Obsah komponenty v presenteru, resp. formulář
protected function createComponentUkazkovyFormular($name)
   $form = new Form($this, $name);
   $form->addSelect('count', 'Pocet', range(1,10) )->addRule(\Nette\Application\UI\Form::FILLED, 'Zvolte pocet...');
   $age = $form->addContainer('age');
   $age->addText('0', 'Věk osoby č. 1');
   if ($form->isSubmitted()) {
	if ($this->presenter->isAjax()) $this->invalidateControl('formular');
	for ($i=1;$i<=$form['count']->getValue();$i++) $age->addText($i, 'Věk osoby č. '.($i+1));
   }
   $form->addSubmit('show', 'Generovat'); // nahrada za ->getControlPrototype()->onChange() u selectboxu
   $form->addSubmit('save', 'Ulozit'); // chybi doplnit onClick s callbackem
   return $form;
}

V render příslušného presenteru ještě „namontuj“ formulář do šablony.

$this->template->form = $this['ukazkovyFormular'];
  1. Šablona
{$form->render('begin')}
<p>
    {$form['count']->label}
    {$form['count']->control}
    {$form['show']->control}
</p>
{snippet formular, table}
	<tr n:foreach="$form['age']->getComponents() as $f">
    		<th>{$f->label}</th><td>{$f->control}</td>
	</tr>
{/snippet}
{$form['save']->control}
{$form->render('end')}

<script>
$(function () {
	// "naroubovani" ajaxu na formular
        $("form").submit(function () {
                $(this).ajaxSubmit();
                return false;
        });
});
</script>

Editoval Ot@s (14. 10. 2011 9:28)

colek
Člen | 59
+
0
-

Tak až zas někdy dorazím na PS, máš u mě minimálně pivo :)

Nicméně to „skoro funguje“, ale nepodařilo se mi rozchodit, aby se formulář odeslal po změně u selectboxu. Po stisknutí tlačítka generovat vše funguje.

Js jsem navěsil tak, jak se formulář jmenuje v šabloně, to je asi správný postup ne?

Jenže když udělám selectbox s ->getControlPrototype()->onChange(„submit();“) stejně se to neodešle…

$("frm-travelIForm1").submit(function () {
                $(this).ajaxSubmit();
                return false;
        });
Ot@s
Backer | 476
+
0
-

colek napsal(a):

Tak až zas někdy dorazím na PS, máš u mě minimálně pivo :)

Já takto Hosiplanovi dlužím už 3 pivka :-D

Nicméně to „skoro funguje“, ale nepodařilo se mi rozchodit, aby se formulář odeslal po změně u selectboxu. Po stisknutí tlačítka generovat vše funguje.

Doplň si tedy:

<script>
$(function () {
	$("#{!$form['count']->getHtmlId()}").change(function(){
		$(this).closest('form').submit();
	});
        $("form").submit(function () {
                $(this).ajaxSubmit();
                return false;
        });
});
</script>

Edit: teoreticky by mělo fungovat i $form['count']->getControlPrototype()->onChange("$(this).closest('form').submit()")

Editoval Ot@s (14. 10. 2011 14:44)

colek
Člen | 59
+
0
-

já nevím, je hodně troufalé tě poprosit se na to podívat? osekal jsem to o vše ostatní a nahrál ke stažení…

http://jdem.cz/sdfs2

já to prostě zkouším, vůbec netuším co dělám špatně…

díky moc

Ot@s
Backer | 476
+
0
-

2 věci (viz. opravy v http://www.ulozto.cz/…/example-tgz dostupný do 2011–10–24):

  1. nenalinkoval jsi do @layout.latte JS knihovny:
  1. V default.latte, resp. v inline zápisu JS $("frm-mainIForm1").submit(...); má být $("#frm-mainIForm1").submit(...); (chybí #, který říká, že se má hledat v ID tagů). Ještě lepší je ale použít $("#{!$form->getElementPrototype()->id}").submit(...); (Nette samo dosadí ID formuláře).

PS: Tento přispěvek je přínosný jen pro Tebe ale je neužitečný pro ostatní. Takže buď pošli soukromý vzkaz, nebo uveď indicie tak, aby to bylo užitečné i pro ostatní.

colek
Člen | 59
+
0
-

Díky moc! Ještě asi drobnost…

jak nastavit, aby se formulář nevalidoval? Protože musím nejdříve vyplnit celý form, než budu měnit počet políček.

<script>
$(function () {
        $("#{!$form['count']->getHtmlId()}").change(function(){
                $(this).closest('form').submit();
        });
        $("#{!$form['count']->getHtmlId()}").submit(function () {
                $(this).ajaxSubmit();
                return false;
        });
});
</script>
Ot@s
Backer | 476
+
0
-

colek napsal(a):

jak nastavit, aby se formulář nevalidoval? Protože musím nejdříve vyplnit celý form, než budu měnit počet políček.

Zkus trik, kterým spojíš příjemné s užitečným:

  1. ponech v definici formuláře submitovací tl. (pomocí setValidationScope zakážeš validaci)
$form->addSubmit('show', 'Generovat')->setValidationScope(FALSE); // do sablony pak pridej {$form['show']->control}
  1. pomocí JS $("#{!$form['show']->getHtmlId()}").hide(); ho zneviditelni (když někdo zakáže v prohlížeči JS, bude formulář funkční)
  2. Pomoci JQuery nesubmituj formulář, ale simuluj klik na submitovaci tl., které má vyplou validaci:
$(function () {
	$("#{!$form['show']->getHtmlId()}").hide();
	$("#{!$form['count']->getHtmlId()}").change(function(){
                // $(this).closest('form').submit(); // nesubmitujeme formular
	        $("#{!$form['show']->getHtmlId()}").click(); // ale simulujeme click na submitbutton
	});
	// aktivace ajaxoveho submitnuti
	$("form").submit(function () {
		$(this).ajaxSubmit();
		return false;
	});
});