Závislé FormControly (nejen SelectBoxy) – primitivní řešení

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

EDIT:
Ahoj. Prokousal jsem se všemi dále probíranými problémy. A jelikož jde spíše o záležitost formulářů, Ajax se snažím naopak z hlediska uživatele tvořené komponenty úplně vynechat, pokračuji dále v
 jiném vlákně .

_________________________________________

Ahoj. Zatím je to ve vývoji. Zkuste se mrknout na ukázku (po kliku vždy chvíli počkejte na výsledek, je to pomalé a na freeserveru). Totéž si zde asi naprogramuje každý a lépe, šlo mi hlavně o co nejjednodušší syntaxi pro začátečníky. Takže výše uvedené vypadá v kódu takto:

	function createComponentMyForm($name)
	{
$handle = 'changeData';
$pres = 'Homepage';
		$form = new Nette\Application\AppForm($this, $name);
$form->addSelect('pristup', 'Vyber:', array(1 => 'Nechci změnit', 2 => 'Změnit'));
$form->addSelect('hodnota', 'Vyber:', array(1 => 'Input', 2 => 'String'));
		$form->addText('text', 'Text:');

//Pouze těchto pár řádků "zajaxuje" jednotlivé kontroly formuláře:
$form['pristup']->addAjax('Homepage', 'changeData', 'pristup')
        ->addAjax('Homepage', 'changeData2', 'hodnota')
        ->addAjax('Homepage', 'changeData3', 'text');
$form['hodnota']->addAjax('Homepage', 'changeData3', 'text');

$form->addSubmit('send', 'Odeslat');
		$form->onSubmit[] = callback($this, 'valuesSubmitted');

return $form;
	}

Funkce AddAjax(Presenter,Handler,CílovýControl) je definována kdekoli v kódu (a v definitivní verzi bude přejmenována), já ji mám na začátku BasePresenteru:

function addAjaxToFormControl(Nette\Forms\FormControl $control, $pres, $handle, $applyTo = NULL)
{
    $form = $control->getForm();
    $on_change = $control->getControlPrototype()->onchange;
    if (is_null($applyTo))
    {
        $apply_to = 'this.id';
    }
    else
    {
        $appTo = $form[$applyTo];
        $apply_to = $appTo->getHtmlId();
    }
    $jsOnChange = '$.get("?do="+"'.$handle.'"+"&presenter="+"'.$pres.
        '", {"ident": this.name, "value": this.value, "applyto": "'.$apply_to.
        '"}, function(data) {$("#"+"'.$apply_to.'").replaceWith(data);}, "html");';
    $control->getControlPrototype()->onchange($on_change.$jsOnChange);
    return $control;
}

Nette\Forms\FormControl::extensionMethod('addAjax', 'addAjaxToFormControl');

Kvůli getHtmlId() to neumím jednoduše udělat lazy, proto $form[‚pristup‘]->addAjax(…) atd.

Obslužné handlery mám v HomepagePresenteru, ale mohou být umístěny kdekoli. Syntaxe je snad pochopitelná, pro složitější konstrukce mohu využít parametry $ident a $applyto, zde v prvním z handlerů mění SelectBox „sám sebe“:

public function handleChangeData($ident, $value, $applyto, $all = TRUE)
{
    $item = $this['myForm'][$ident];
    if ($value == 1)
    {
          $item->setItems(array(1 => 'Tento seznam seřadit vzestupně', 2 => 'Tento seznam seřadit sestupně'));
          $item->setValue(1);
    }
    else //Změním pořadí
    {
          $item->setItems(array(2 => 'Tento seznam seřadit sestupně', 1 => 'Tento seznam seřadit vzestupně'));
          $item->setDefaultValue(2);
    }

    if ($all)
    {
        echo $item->getControl();
        // konec zpracování
        $this->terminate();
    }
}

public function handleChangeData2($ident, $value, $applyto, $all = TRUE)
{
    $item = $this['myForm']['hodnota'];
    $item->setItems(array(1 => 'Změnit text na input', 2 => 'Změnit text na string', 3 => 'Úplně nová hodnota, která tu dříve nebyla, ale odteď bude validní'));
    if ($value == 1)
    {
          $item->setDefaultValue(1);
    }
    else
    {
          $item->setDefaultValue(3);
    }

    if ($all)
    {
        echo $item->getControl();
        // konec zpracování
        $this->terminate();
    }
}

public function handleChangeData3($ident, $value, $applyto, $all = TRUE)
{
    $item = $this['myForm']['text'];//$applyto
    if ($value == 1)
    {
        $item->setDefaultValue('Tak už jsem zase input');
    }
    else
    {
        $item->setDefaultValue('Do mě už si nezapíšeš!');
          if ($all)
          {
                echo '<div id='.$applytoid.'>Do mě už si nezapíšeš!</div>';
			//Ten div id= nesmí chybět kvůli možnosti zpětné změny!!!!
                // konec zpracování
                $this->terminate();
          }
   }

    if ($all)
    {
        echo $item->getControl();
        // konec zpracování
        $this->terminate();
    }
}

Pro funkčnost je nutné někde v šabloně vložit jquery:

<script type="text/javascript" src="{$basePath}/js/jquery.min.js"></script>

Handlery by se daly vyřešit elegantněji (jedním handlerem a callbacky), chybí escapování (v handleru si je musí každý ohlídat sám), o javascript se stará presenter, není to lazy a určitě přijdete na mnoho námětů k vylepšení či úplnému zamítnutí. Zatím intenzivně pracuji na lidském a čistém způsobu změny definice formuláře v handleru bez nutnosti použití getRawValue() v onSubmit(). Jsme tu od toho, abychom Nette používali a ne hackovali. Jak jsem Nette zatím stihl poznat, David někde určitě tuto možnost připravil. Jen se o ní zřejmě zatím méně ví a nechce se mi ho otravovat s dotazy, na které najdu odpověď i jinak. Chystám se také pokusit se o lazy řešení, rozšířit parametry o jednoduchou možnost navázání kromě onChange() na onClick() a další callbacky, také o jiné zpracování výstupu než nahrazení html elementu (jednosměrný požadavek, změna pouze hodnot atd), vše si ale musí zachovat intuitivní a jednoduché použití. Hlavní výhodou je v současném stavu jednoduchá syntaxe přidání Ajaxové obsluhy jednotlivého FormControlu a pro začátečníky i bezproblémové použití s ConventionalRendererem. A třeba SelectBox měnící sám sebe jsem zatraceně moc potřeboval při procházení velmi rozsáhlého stromu stránek.

Editoval Martin (9. 4. 2011 10:51)

Martin
Člen | 171
+
0
-

Tak už je to tak nějak po kupě a funkční. Chvíli ale ještě potrvá vše hezky zabalit a vyčistit. Problém samozřejmě je udržet vysoký bezpečnostní standard, který Nette formuláře nabízejí. Takže mají-li hodnoty získané po odeslání formuláře být kontrolovány stejně jako u ostatních formulářů (například povolené hodnoty SelectBoxu atd), musí se uchovat historie změn kontrolů a znovu použít při kontrolním vytváření formuláře před getValues() v onClick či onSubmit callbacku. Pokud uživatel v handlerech použije jen bezkontextové změny (nezávislé na historii), stačí si uchovat jméno handleru a jeho parametry použité při poslední změně každého kontrolu. Session by pro to nebyla vhodná (kdo ví, co uživatel, jeho prohlížeč a připojení s formulářem mezitím dělají), musí se tedy použít něco přímo ve formuláři na straně klienta – nejlépe skrytá pole. V těch však musí být hodnoty, které odolají jakýmkoli útokům, tedy musí se před voláním handlerů interpretovat s dostatečnou kontrolou. A zárověň je vhodné jejich hodnoty z vraceného pole odebrat, aby v něm zbytečně nestrašily, i když by to jinak ničemu nevadilo. Vše již poměrně funguje až na případ záměny kontrolu za zcela jiný typ (třeba text input za div z příkladu). Tam dochází k drobným chybám, po jejich vyřešení zveřejním výsledek.

Editoval Martin (6. 4. 2011 12:38)

Filip Procházka
Moderator | 4668
+
0
-

První věc co mě práskla do oka: zvaž

$form['pristup']->addAjax('Homepage', 'changeData2', 'hodnota');

vs

$form['pristup']->addAjax('Homepage', 'changeData2', $form['hodnota']);
Martin
Člen | 171
+
0
-

Zdravím, děkuji za nápovědu. Mohu se zeptat na důvod změny? Nijak mi nevadí to tam takto dát, jen moje první myšlenka byla zajistit co nejméně psaní ze strany uživatele komponenty a takto to bude mít sice trochu intuitivnější, bude však muset psát o několik znaků víc. Nebo že by šlo o možnost odkazovat se na kontroly různých formulářů? Jinak naskytl se mi nečekaný problém. Při „zajaxování“ kontrolu vytvářím skrytá pole pro posledně volaný handler a jeho parametry. Zatím je to neohrabané (viz ukázka dále), ale vše většinou funguje:

function addAjaxToFormControl(Nette\Forms\FormControl $control, $pres, $handle, $applyTo = NULL)
{
    $form = $control->getForm();
    $on_change = $control->getControlPrototype()->onchange;
    if (is_null($applyTo))
    {
        $apply_to = 'this.id';
        $applyTo = $control->name;//'this.name';
    }
    else
    {
        $appTo = $form[$applyTo];
        $apply_to = $appTo->getHtmlId();
    }
    $applyToHandler = $applyTo.'Handler';
    if (!$form->offsetExists($applyToHandler))
    {
        $form->addHidden($applyToHandler, "NULL");
    }
    $applyToIdent = $applyTo.'Ident';
    if (!$form->offsetExists($applyToIdent))
    {
        $form->addHidden($applyToIdent, 'NULL');
    }
    $applyToValue = $applyTo.'Value';
    if (!$form->offsetExists($applyToValue))
    {
        $form->addHidden($applyToValue, 'NULL');
    }
    $applyToApplyTo = $applyTo.'ApplyTo';
    if (!$form->offsetExists($applyToApplyTo))
    {
        $form->addHidden($applyToApplyTo, 'NULL');
    }
    $applyToApplyToId = $applyTo.'ApplyToId';
    if (!$form->offsetExists($applyToApplyToId))
    {
        $form->addHidden($applyToApplyToId, 'NULL');
    }

    $jsOnChange = '$.get("?do="+"'.$handle.'"+"&presenter="+"'.$pres.
        '", {"ident": this.name, "value": this.value, "applyto": "'.$applyTo.'", "applytoid": "'.$apply_to.
        '"}, function(data) {$("#"+"'.$apply_to.'").replaceWith(data);}, "html");'.
        $applyToHandler.'.value = "'.$handle.'";'.
        $applyToIdent.'.value = this.name;'.
        $applyToValue.'.value = this.value;'.
        $applyToApplyTo.'.value = "'.$applyTo.'";'.
        $applyToApplyToId.'.value = "'.$apply_to.'";';
    $control->getControlPrototype()->onchange($on_change.$jsOnChange);
    return $control;
}

Nette\Forms\FormControl::extensionMethod('addAjax', 'addAjaxToFormControl');

Když si ale otevřu konzoli Firebugu, objeví se mi například toto:

Byl dosažen limit logu Firebugu. 0 záznamů není zobrazeno		Předvolby
GET http://gymnastikazizkov.profitux.cz/ZavisleContr...ue=1&applyto=pristup&applytoid=frmmyForm-pristup
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData&presenter=Homepage&ident=pristup&value=1&applyto=pristup&applytoid=frmmyForm-pristup
200 OK 1.28s	jquery.min.js (řádek 141) pristupHandler is not defined [Zastavit při této chybě] <!DOCTYPE html> www (řádek 1)

... TADY TO TŘEBA MNOHOKRÁT PROJDE V POŘÁDKU ...

GET http://gymnastikazizkov.profitux.cz/ZavisleContr...ta&value=1&applyto=text&applytoid=frmmyForm-text
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData3&presenter=Homepage&ident=hodnota&value=1&applyto=text&applytoid=frmmyForm-text
200 OK 1.53s
jquery.min.js (řádek 141)
GET http://gymnastikazizkov.profitux.cz/ZavisleContr...ue=1&applyto=pristup&applytoid=frmmyForm-pristup
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData&presenter=Homepage&ident=pristup&value=1&applyto=pristup&applytoid=frmmyForm-pristup
200 OK 2.72s
jquery.min.js (řádek 141)
GET http://gymnastikazizkov.profitux.cz/ZavisleContr...ue=1&applyto=hodnota&applytoid=frmmyForm-hodnota
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData2&presenter=Homepage&ident=pristup&value=1&applyto=hodnota&applytoid=frmmyForm-hodnota
200 OK 2.73s
jquery.min.js (řádek 141)
GET http://gymnastikazizkov.profitux.cz/ZavisleContr...up&value=1&applyto=text&applytoid=frmmyForm-text
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData3&presenter=Homepage&ident=pristup&value=1&applyto=text&applytoid=frmmyForm-text
200 OK 2.73s
jquery.min.js (řádek 141)
GET http://gymnastikazizkov.profitux.cz/ZavisleContr...ue=2&applyto=pristup&applytoid=frmmyForm-pristup
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData&presenter=Homepage&ident=pristup&value=2&applyto=pristup&applytoid=frmmyForm-pristup
200 OK 1.25s
jquery.min.js (řádek 141)
pristupHandler is not defined
[Zastavit při této chybě] <!DOCTYPE html>
www (řádek 1)
GET http://gymnastikazizkov.profitux.cz/ZavisleContr...ue=1&applyto=pristup&applytoid=frmmyForm-pristup
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData&presenter=Homepage&ident=pristup&value=1&applyto=pristup&applytoid=frmmyForm-pristup
200 OK 1.24s
jquery.min.js (řádek 141)
pristupHandler is not defined
[Zastavit při této chybě] <!DOCTYPE html>
www (řádek 1)
GET http://gymnastikazizkov.profitux.cz/ZavisleContr...ta&value=2&applyto=text&applytoid=frmmyForm-text
GET http://gymnastikazizkov.profitux.cz/ZavisleControly/www/?do=changeData3&presenter=Homepage&ident=hodnota&value=2&applyto=text&applytoid=frmmyForm-text
200 OK 1.88s
jquery.min.js (řádek 141)
textHandler is not defined

A opravdu při vyhodnocování ve skrytých polích nejsou někdy poslední data zapsaná. Přitom když Firebug přepnu na sledování html, tak tam samozřejmě všechna skrytá pole stále jsou. Tušíte někdo, jak je možné, že když si klikám sem tam stále v jednom selectboxu a provádí se tedy stále stejný javascrit, občas prostě nenajde nějaký input podle name? Také už pak neproběhne volání ostatních handlerů, takže js zřejmě spadl. Léta jsem programoval desktopy, javascript vídám až v poslední době, tohle mi přijde jako nějaký problém s paralelním zpracováním. Je to možné? Že by se hodnota do skrytého divu cpala ve chvíli, kdy s ním zrovna pracuje jquery? Z časového sledu výpisu v konzoli by mi to tak také přišlo, mám tedy zapsání hodnot do skrytých inputů někam přesunout? Vygenerovaný js dle Firebugu vypadá takto:

onchange="$.get(&quot;?do=&quot;+&quot;changeData3&quot;+&quot;&amp;presenter=&quot;+&quot;Homepage&quot;, {&quot;ident&quot;: this.name, &quot;value&quot;: this.value, &quot;applyto&quot;: &quot;text&quot;, &quot;applytoid&quot;: &quot;frmmyForm-text&quot;}, function(data) {$(&quot;#&quot;+&quot;frmmyForm-text&quot;).replaceWith(data);}, &quot;html&quot;);textHandler.value = &quot;changeData3&quot;;textIdent.value = this.name;textValue.value = this.value;textApplyTo.value = &quot;text&quot;;textApplyToId.value = &quot;frmmyForm-text&quot;;"

respektive za běhu takto:

function onchange(event) {
$.get("?do=changeData&presenter=Homepage", {ident: this.name, value: this.value, applyto: "pristup", applytoid: "frmmyForm-pristup"}, function (data) {$("#frmmyForm-pristup").replaceWith(data);}, "html");
pristupHandler.value = "changeData";
pristupIdent.value = this.name;
pristupValue.value = this.value;
pristupApplyTo.value = "pristup";
pristupApplyToId.value = "frmmyForm-pristup";
$.get("?do=changeData2&presenter=Homepage", {ident: this.name, value: this.value, applyto: "hodnota", applytoid: "frmmyForm-hodnota"}, function (data) {$("#frmmyForm-hodnota").replaceWith(data);}, "html");
hodnotaHandler.value = "changeData2";
hodnotaIdent.value = this.name;
hodnotaValue.value = this.value;
hodnotaApplyTo.value = "hodnota";
hodnotaApplyToId.value = "frmmyForm-hodnota";
$.get("?do=changeData3&presenter=Homepage", {ident: this.name, value: this.value, applyto: "text", applytoid: "frmmyForm-text"}, function (data) {$("#frmmyForm-text").replaceWith(data);}, "html");
textHandler.value = "changeData3";
textIdent.value = this.name;
textValue.value = this.value;
textApplyTo.value = "text";
textApplyToId.value = "frmmyForm-text";
}
function (data) {
$("#frmmyForm-hodnota").replaceWith(data);
}
function (data) {
$("#frmmyForm-text").replaceWith(data);
}
function onchange(event) {
$.get("?do=changeData&presenter=Homepage", {ident: this.name, value: this.value, applyto: "pristup", applytoid: "frmmyForm-pristup"}, function (data) {$("#frmmyForm-pristup").replaceWith(data);}, "html");
pristupHandler.value = "changeData";
pristupIdent.value = this.name;
pristupValue.value = this.value;
pristupApplyTo.value = "pristup";
pristupApplyToId.value = "frmmyForm-pristup";
$.get("?do=changeData2&presenter=Homepage", {ident: this.name, value: this.value, applyto: "hodnota", applytoid: "frmmyForm-hodnota"}, function (data) {$("#frmmyForm-hodnota").replaceWith(data);}, "html");
hodnotaHandler.value = "changeData2";
hodnotaIdent.value = this.name;
hodnotaValue.value = this.value;
hodnotaApplyTo.value = "hodnota";
hodnotaApplyToId.value = "frmmyForm-hodnota";
$.get("?do=changeData3&presenter=Homepage", {ident: this.name, value: this.value, applyto: "text", applytoid: "frmmyForm-text"}, function (data) {$("#frmmyForm-text").replaceWith(data);}, "html");
textHandler.value = "changeData3";
textIdent.value = this.name;
textValue.value = this.value;
textApplyTo.value = "text";
textApplyToId.value = "frmmyForm-text";
}

Editoval Martin (7. 4. 2011 2:30)

Martin
Člen | 171
+
0
-

Zpracování už jinak docela funguje – viz výpisy po kliku na Odeslatukázce. Ale nakonec, ač nerad, přecijen asi podědím od AppControlu (čímž se vyřeší i místo pro extension, jen to pak nebude tak malá změna pro uživatele komponenty), než abych v kódu používal takové hrůzy, jaké se mi tam zatím vyskytují – viz kód:

	public function valuesSubmitted($form)
	{
            //Zde z values vyberuj postupně pro všechny kontroly handler a pokud je v poli (aby mi tam někdo něco nepodstrčil), tak zavolám callback s parametry:
            $values = $form->getValues();
            $iterator = $form->getControls();
            foreach ($iterator as $name => $control) {
                $handler = $name.'Handler';
                if (array_key_exists($handler, $values) && $values[$handler] != 'NULL')
                {
                    $method = 'handle'.$values[$handler];
                    $this->$method($values[$name.'Ident'],$values[$name.'Value'],$values[$name.'ApplyTo'],$values[$name.'ApplyToId'], FALSE);
                }
            }
            //Odstraním hodnoty skrytých polí:
            $values = $form->getValues();
            $iterator = $form->getControls();
            foreach ($iterator as $name => $control) {
                $handler = $name.'Handler';
                if (array_key_exists($handler, $values))
                {
                    unset($values[$handler]);
                    unset($values[$name.'Ident']);
                    unset($values[$name.'Value']);
                    unset($values[$name.'ApplyTo']);
                    unset($values[$name.'ApplyToId']);
                }
            }

//            Zde už je výsledek ve $values použitelný

            Nette\Debug::barDump($values);
            echo Nette\Debug::Dump($values, TRUE);
		$this->template->anyVariable = 'any value';
	}
Filip Procházka
Moderator | 4668
+
0
-

Ty nepoužíváš FormContainer -y, žene? Protože prostým pojmenováním se dostaneš pouze na přímé potomky formuláře.

$form = new AppForm();
$form->addText('name', 'Jmeno');
$address = $form->addContainer('address');
$address->addContainer('zip', 'PSČ');

jak napsáním stringu svážu nějakou komponentu, se ‚zip‘? Takhle to jde mnohem lépe:

$form['pristup']->addAjax('Homepage', 'changeData2', $form['address']['zip']);
Martin
Člen | 171
+
0
-

Dík, jasně, už rozumím. FormContainery aktuálně nepoužívám jen proto, že v právě dokončovaném projektu, kde potřebuji kompnentu se selectboxem měnícím sama sebe, jsem chtěl vše před finálním svázáním se styly vykreslovat pomocí ConvencionalRendereru a přitom mám nouzi o místo v okýnku.

Ale to občasné nenalezení inputu javascriptem s tím asi nesouvisí, nebo se mýlím?

Editoval Martin (7. 4. 2011 8:54)

Martin
Člen | 171
+
0
-

Tak jsem zavolání …hanler = „..“ dal dovnitř callbacku volaného po návratu hodnot pomocí jquery. Díky tomu javascript provede vždy alespoň požadovanou změnu vzhledu inputu. Ale stále platí, že někdy prostě nenajde příslušný skrytý input podle jména, takže se pak validace formuláře po odeslání provádí se starými daty (vytvoří se nesprávná kontrolní struktura formuláře). Chyba se teď v konzoli Firebugu objevuje hezčí a vybarvená od jquery. Mohu někoho, kdo ovládá javascript lépe než já, poprosit o připojení se třeba Firefoxem s Firebugem na ukázku a shlédnutí chyby v konzoli, až se objeví? Stačí přepínat první (horní) select cca po 3–5 sec nahoru a dolu, při cca 2. až 10. přepnutí se chyba v konzoli objeví.

A tušíte někdo, proč, když se mi konečně po několikerém proběhnutí skript zastavil na breakpointu, při krokování ovšem proběhl bez chyb, v konzoli jsem pak viděl hlášku:

"Příkazový řádek Firebugu nepodporuje '$0'"
"Příkazový řádek Firebugu nepodporuje '$1'"

?

Editoval Martin (7. 4. 2011 9:38)

Martin
Člen | 171
+
0
-

Hmmm, tak ještě jeden poznatek, a teď už fakt nevím, co s tím. Když jsem se na stejnou ukázku připojil z Internet Exploreru, probíhá mi ajaxová odezva nepostehnutelně rychle (ve Firefoxu 1–5 sec). A, mám-li věřit ladění skriptů v IE8, zcela bez chyb! Můžete to kdokoli vyzkoušet z Firefoxu? V něm se mi nakonec podařilo chybu shlédnout, ale nejsem z toho moc moudrý: Obrázek chyby , obrázek html (nenalezený input zjevně je přítomen) , při dalším překliknutí je tento skrytý input bez problémů nalezen, ale i podle jinak nastavených breakpointů jako by to byl jiný skript .

Editoval Martin (7. 4. 2011 10:28)

Martin
Člen | 171
+
0
-

Tak zatím jsem to vyřešil pomocí jquery:

$("#'.$applyToHandlerId.'").val("'.$handle.'");
$("#'.$applyToHandlerIdent.'").val(this.name);
$("#'.$applyToHandlerValue.'").val(this.value);
$("#'.$applyToHandlerApplyTo.'").val("'.$applyTo.'");
$("#'.$applyToHandlerApplyToId.'").val("'.$apply_to.'");

To, zdá se, funguje spolehlivě. Ukázku zatím nechávám bez této změny, kdyby se někomu chtělo přijít na to, proč js někdy nenašel skrytá pole.

Teď už to jen zkompletuji, vyčistím, pravděpodobně vytvořím potomka AppForm a v případě zájmu přidám do komponent. A použiju výše uvedená doporučení, jen pak musím vše předělat na identifikaci podle Id.

Editoval Martin (7. 4. 2011 11:57)

Martin
Člen | 171
+
0
-

Zdravím. Můžete se někdo znalejší ještě podívat na související problém se svázáním handlerů komponenty a signálů presenteru ?