CheckBox/CheckBoxList, input mimo createComponent
- Bernard Williams
- Člen | 207
Nazdárek,
narazil jsem na několik problému, které se mi nedaří vyřešit.
- Nechápu, proč u Checkboxu není metoda setValue(). Absence nastavení hodnoty Checkboxu snižuje použitelnost tohoto prvku o několik desítek procent. Např. v admin sekcí se bez tohoto prvku prakticky neobejdete – zaškrtnutí položek, které uživatel chce změnit/vymazat atd. Jak jinak to řešit?
- Na fóru jsem nalezl, že problém 1) řeší tzv CheckBoxList. Bohužel s tímto novým prvkem jsem narazil na další problém. Jak je můžu ručně vykreslit jednotlivé zaškrtávací políčka? Jak můžu umístit přesně tam, kam chci? Řešení přes getControls() se mi na CheckBoxList zatím nepodařilo napasovat.
- Poslední problém nastal v případě, kdy nějaký prvek formuláře nevytvořím hned v createComponent, ale až třeba v pohledu. Obsah těchto prvků se vůbec neodešle – odešlou se jen obsahy prvků, které byly vytvořeny v createComponent. Př:
protected function createComponent($name) {
switch ($name) {
case 'smazatFotkyForm':
$form = new AppForm($this, $name);
$form->addSubmit('smazat', 'Smazat vybrané');
$form->addText('text', 'neco');
$form->onSubmit[] = array($this, 'smazatFotkyFormSubmitted');
return;
default:
parent::createComponent($name);
}
}
Z takové formuláře se prvek text odešle – to je v pořádku. Když ale v pohledu přidám k formuláři další prvek – např. text2, tak už se jeho obsah neodešle.
$form = $this->getComponent('smazatFotkyForm');
$form->addText('text2', 'neco2');
Je to chyba nebo je to snad záměr?
Děkuji
Bernard
- Honza Kuchař
- Člen | 1662
- Je to záměr. Form není hloupý generátor html kódu, proto musí vědět už při vytváření, které políčka má ve formuláři.
- Bernard Williams
- Člen | 207
honzakuchar: Jde to nějak obejít? Když potřebuji vytvářet prvky formuláře až v pohledu..
- Panda
- Člen | 569
2. bod by mělo jít vyřešit nějak takto (kód pro šablonu):
{foreach $form['checkboxlist']->getItems() as $key => $label}
{$form['checkboxlist']->getControl($key)} {$label}
{/foreach}
3. bod: formulář samozřejmě upravit lze, ale musíš to udělat před
zpracováním signálů, tedy ne v metodě render<action>()
,
ale v metodě action<action>()
.
- Bernard Williams
- Člen | 207
Myslím, že v té třídě CheckboxList je asi chybka. S definicí:
$items = array(
1 => 'item1',
2 => 'item2',
);
$form->addCheckboxList('demo', 'Choices', $items)
->addRule('CheckboxList::validateChecked', 'Check something!');
Mi kód:
foreach ($form['demo']->getItems() as $key => $label) {
echo $form['demo']->getControl($key).' ['.$label.']';
}
Vrátí tohle:
<input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-0" value="1" /><label for="frmsmazatFotkyForm-demo-0">item1</label> [item1]
<input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-1" value="2" /><label for="frmsmazatFotkyForm-demo-1">item2</label> [item2]
Místo předpokládaného výstupu:
<input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-0" value="1" /> [<label for="frmsmazatFotkyForm-demo-0">item1</label>]
<input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-1" value="2" /> [<label for="frmsmazatFotkyForm-demo-1">item2</label>]
Kdyby nebyl na první pohled patrný rozdíl, tak $label
z foreach cyklu obsahuje item2
místo
<label for="frmsmazatFotkyForm-demo-1">item2</label>
a
control obsahuje taky label místo samotného controlu.
- Panda
- Člen | 569
Bernard Williams napsal(a):
Myslím, že v té třídě CheckboxList je asi chybka. S definicí:
$items = array( 1 => 'item1', 2 => 'item2', ); $form->addCheckboxList('demo', 'Choices', $items) ->addRule('CheckboxList::validateChecked', 'Check something!');
Mi kód:
foreach ($form['demo']->getItems() as $key => $label) { echo $form['demo']->getControl($key).' ['.$label.']'; }
Vrátí tohle:
<input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-0" value="1" /><label for="frmsmazatFotkyForm-demo-0">item1</label> [item1] <input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-1" value="2" /><label for="frmsmazatFotkyForm-demo-1">item2</label> [item2]
Místo předpokládaného výstupu:
<input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-0" value="1" /> [<label for="frmsmazatFotkyForm-demo-0">item1</label>] <input type="checkbox" name="demo[]" id="frmsmazatFotkyForm-demo-1" value="2" /> [<label for="frmsmazatFotkyForm-demo-1">item2</label>]
Kdyby nebyl na první pohled patrný rozdíl, tak
$label
z foreach cyklu obsahujeitem2
místo<label for="frmsmazatFotkyForm-demo-1">item2</label>
a control obsahuje taky label místo samotného controlu.
Pardon, ve zdrojáku jsem si nevšiml, že metoda
CheckboxList::getControl($key)
vrací checkbox i s labelem. Pokud
to chceš rozdělit, tak vytvoř zhruba následujícího potomka třídy
CheckboxList
:
<?php
class MyCheckboxList extends CheckboxList
{
private $baseLabel;
protected function getBaseLabel()
{
if ($this->baseLabel === NULL)
$this->baseLabel = /*Nette\Web\*/Html::el('label');
return $this->baseLabel;
}
public function getControl($key = NULL)
{
if ($key === NULL) {
$container = clone $this->container;
$separator = (string) $this->separator;
} elseif (!isset($this->items[$key])) {
return NULL;
}
$control = parent::getControl();
$control->name .= '[]';
$id = $control->id;
$counter = -1;
$values = $this->value === NULL ? NULL : (array) $this->getValue();
$label = $this->getBaseLabel();
foreach ($this->items as $k => $val) {
$counter++;
if ($key !== NULL && $key != $k) continue; // intentionally ==
$control->id = $label->for = $id . '-' . $counter;
$control->checked = (count($values) > 0) ? in_array($k, $values) : false;
$control->value = $k;
if ($val instanceof /*Nette\Web\*/Html) {
$label->setHtml($val);
} else {
$label->setText($this->translate($val));
}
if ($key !== NULL) {
return (string) $control;
}
$container->add((string) $control . (string) $label . $separator);
}
return $container;
}
public function getLabel($key = NULL)
{
if ($key === NULL)
return parent::getLabel();
$id = $this->getHtmlId();
$counter = -1;
$label = $this->getBaseLabel();
foreach ($this->items as $k => $val) {
$counter++;
if ($key != $k) continue;
$label->for = $id . '-' . $counter;
if ($val instanceof /*Nette\Web\*/Html) {
$label->setHtml($val);
} else {
$label->setText($this->translate($val));
}
return (string) $label;
}
}
}
?>
Kód pak bude následující:
foreach ($form['demo']->getItems() as $key => $label) {
echo $form['demo']->getControl($key).' ['. $form['demo']->getLabel($key) .']';
}
PS: Poslední dobou mi to nějak nepálí, takže pokud tam zas bude nějaká bota, tak prosím moc nekamenovat.
Editoval Panda (26. 8. 2009 14:10)
- Bernard Williams
- Člen | 207
Panda: Děkuju, getControl jsem si dokázal upravit, ale s tím getLabel jsem měl problém – ještě jednou díky.. ale! Máš tam chybku :-) Takto upravený getLabel hází chyby. Chybí ti tam $control = parent::getControl(); takže výsledná metoda třídy MyCheckboxList by měla vypadat takto:
public function getLabel($key = NULL)
{
$control = parent::getControl();
$id = $control->id;
$counter = -1;
$label = /*Nette\Web\*/Html::el('label');
foreach ($this->items as $k => $val) {
$counter++;
if ($key != $k) continue;
$label->for = $id . '-' . $counter;
if ($val instanceof /*Nette\Web\*/Html) {
$label->setHtml($val);
} else {
$label->setText($this->translate($val));
}
return (string) $label;
}
}
Ale to už jsou detaily.. Takže do třetice: Moc děkuju za pomoc.
- Panda
- Člen | 569
Bernard Williams napsal(a):
Panda: Děkuju, getControl jsem si dokázal upravit, ale s tím getLabel jsem měl problém – ještě jednou díky.. ale! Máš tam chybku :-) Takto upravený getLabel hází chyby. Chybí ti tam $control = parent::getControl();
Děkuji za upozornění, ještě jsem to ve svém původním příspěvku
kousek upravil – ten $control tam v podstatě vůbec není potřeba,
volání $control->id
lze nahradit za
$this->getHtmlId()
, což bude z hlediska výkonu mnohem lepší
(nedochází k zbytečnému klonování objektů, viz FormControl::getControl()).
Navíc jsem umožnil volání getLabel
bez parametru
$key
(vrátí popisek celé sady checkboxů) a přidal kód, aby se
základní objekt pro label vytvořil jen při prvním použití, což by mělo
mít lehký pozitivní dopad na výkon při vykreslování většího
počtu prvků.
//Doplnění: tak jsem ještě řešení kousek poupravil.
Editoval Panda (26. 8. 2009 14:15)