WebChemistry/Multiplier dynamicky vytvořený select + generované ID
- Ajax
- Člen | 59
Ahoj,
mám problém s WebChemistry/Multiplier. Jde o to, že formulář má identické řádky (kromě ID) a taky kolonku Jméno. No a taky má obsahovat select, ve kterém je seznam jmen z ostatních řádků formuláře. Seznam do selectu si vygeneruju, ale problém nastane, když uživatel přidá řádek před add funkci multiplieru. Nevím, jak se dostat ke kolonce, kterou uživatel vyplnil v dynamicky generovaném řádku. Potřeboval bych něco jako onAddCallback. S tím souvisí i to, že potřebuju do každého řádku přidat unikátní ID do hidden pole. Zde je kód:
Továrna formuláře, $this->config jsou data z CSV, $this->names je pole, které si vygeneruju foreachem a které bych potřeboval doplnit o input, který mi dá uživatel v poli name (pole je vygenerované přes addCreateButton). Také bych potřeboval poslední požité ID, které může být taky dynamické.
class RegisterConfigFormFactory
{
public function create() {
$form = new Form;
$multiplier = $form->addMultiplier('registerConfigForm', function (Nette\Forms\Container $container, Nette\Forms\Form $form) {
$container->addText('item_id', 'ID')
->setRequired('Prosím, vyplňte jméno');
$container->addText('name', 'Jméno')
->setRequired('Prosím, vyplňte jméno');
$container->addSelect('parent_id', 'Rodič', $this->names)
->setPrompt('Vyberte rodiče');
});
$multiplier->setValues($this->config);
$multiplier->addCreateButton('Přidat');
$multiplier->addRemoveButton('Odstranit');
$form->addSubmit('save', 'Uložit');
return $form;
}
public function setConfiguration(array $config) {
$names = [];
foreach($config as $seq => $row) {
$names[$row['item_id']] = $row['name'];
}
// Zde bych potřeboval obsah všech inputu z names, i těch přidaných pomocí createButton
$this->names = $names;
$this->config = $config;
}
}
Presenter:
public function createComponentRegisterConfigForm() {
$this->redrawControl();
$form = $this->registerConfigFormFactory->create();
$form->onSuccess[] = function(Form $form, $values) {
dd($values);
$this->redrawControl();
};
return $form;
}
Šablona:
{form registerConfigForm, class => 'ajax'}
<ul class="errors" n:if="$form->hasErrors()">
<li n:foreach="$form->errors as $error">{$error}</li>
</ul>
<table id="configItemsTab">
<thead>
<tr>
<th>ID</th>
<th>Jméno</th>
<th>Rodič</th>
<th></th>
</tr>
</thead>
<tbody>
<tr n:multiplier="registerConfigForm">
<td>{input item_id , class => 'item_id'}</td>
<td>{input name}</td>
<td>{input parent_id}</td>
<td>{btnRemove 'class' => 'ajax'}</td>
</tr>
</tbody>
</table>
{btnCreate registerConfigForm class => ajax}
{input 'save', 'class' => 'ajax'}
{/form}
Je to takové kostrbaté, snad to pochopíte.. Dá se toho nějak dosáhnout?
Editoval Ajax (28. 3. 2018 17:14)
- Martk
- Člen | 661
Neměl jsem čas na hledání optimálního řešení, klidně se poděl o svůj návrh, ale asi takto:
protected $config = [
'foo' => 'foo',
'bar' => 'bar',
];
private $filled = false;
protected function fillConfig(Nette\Application\UI\Form $form) {
if (!$this->filled) {
$values = $form->getValues();
foreach ($values['multiplier'] as $value) {
$this->config[] = $value['name'];
}
$this->filled = true;
}
}
protected function createComponentMultiplier() {
$form = new Nette\Application\UI\Form();
$form['multiplier'] = $multiplier = new Multiplier(function (Nette\Forms\Container $container) {
$container->addText('name', 'Name');
$container->addSelect('select', 'Select', $this->config);
});
$form['multiplier']->onCreate[] = function (Nette\Forms\Container $container) {
if ($container->getForm()->isSubmitted()) {
$this->fillConfig($container->getForm());
}
$container['select']->setItems($this->config);
};
$multiplier->addRemoveButton('Remove');
$multiplier->addCreateButton('Create');
$form->addSubmit('send');
return $form;
}
Musíš si stáhnout nejnovější dev verzi
- Ajax
- Člen | 59
WOW! To jsem nečekal. Děkuju moc!!
Select funguje, ale ID nějak nemůžu rozchodit. Když jsem dal
$form['registerConfigForm']->onCreate[] = function (Nette\Forms\Container $container) {
$container['parent_id']->setItems($this->names);
$container['item_id']->setValue('9999');
};
Tak to naplní všechny, kromě posledního (přidávaného) řádku. Přitom
setItems()
hned vedle funguje dobře a podle očekávání. Kde
je chyba?
Jen jedna poznámka, nestálo by za to, aby add
button
nevalidoval formulář? Nebo aspoň dát možnost
zavolat setValidationScope(FALSE)
- Martk
- Člen | 661
Jestli máš podobný kód jako já, tak to bude tím, že se odesílají jen předchozí inputy, ten nový ještě ne, ale jeho hodnotu v průběhu kódu znáš, takže jí můžeš snadno přidat, podle kódu je to hodnota ‚9999‘.
protected function fillConfig(Nette\Application\UI\Form $form) {
if (!$this->filled) {
$values = $form->getValues();
foreach ($values['multiplier'] as $value) {
$this->config[] = $value['name'];
}
$this->config[] = $myDefaultValue;
$this->filled = true;
}
}
Defaultně je setValidationScope jen u remove buttonu, protože se tam nic nepotřebuje validovat. U add buttonu můžeš snadno upravovat co potřebuješ:
$multiplier->addCreateButton('Create', 1, function (SubmitButton $submitter) {
$submitter->setValidationScope(false);
});
- Ajax
- Člen | 59
No, o to nejde jak tu hodnotu zjistit, problem je, že nejde nastavit. Ty
devítky byl jen příklad. Můj úkol je nastavit přidávanému novému
řádku do inputu item_id
unikátní hodnotu. Myslel jsem, že
stačí zavolat v onCreate
callbacku
$container['item_id']->setValue($uniqueId);
, ale to mi
nefunguje. Nastaví to všechny řádky kromě toho nového…
ValidationScope funguje, to jsem přehlédl, děkuji.
- Ajax
- Člen | 59
To je právě problém, já tu hodnotu neznám, musím ju nastavit jako
max($usedIds) + 1
, takže mám
protected function fillConfig(Nette\Forms\Form $form) {
if (!$this->filled) {
$this->names = [];
$this->ids = [];
$values = $form->getValues();
foreach ($values['registerConfigForm'] as $value) {
$this->names[$value['item_id']] = $value['name'];
$this->ids[] = $value['item_id'];
}
$this->filled = true;
}
}
no a teď bych ho potřeboval nastavit max($this->ids) + 1
poli v přidávaném řádku.