Překreslení snippetu, form nedrží předanou hodnotu
- Danny
- Člen | 146
Zdravím,
mám 2 komponenty a při volání eventu se z jedné komponenty se do druhé
předají do Multiselectu informace, to funguje správně. Problém je ten že
si ten Multiselect nedrží informace co v něm momentálně je.
Takže přidám 1 položku, refreshnu snippet, položku vidím, přidám další položku a ta co tam byla předtím zmizí, i když se před vložením snažím zjistit aktuální položky v multiselectu tak tam stejně není.
Grid z kterého se vybírají položky a vrací $items
protected function createComponentSelectContractsGrid()
{
$component = $this->IContractGridComponent->create();
$component->onChange[] = function ($items) {
if ($this->isAjax()) {
// druhá komponenta
/** @var AddContractComponent $component */
$component = $this['addContract'];
// tohle mi nevrátí aktuální stav po druhém přidání multiselectu
$items = $component['form']['contracts']->getValue();
foreach($item as $i) {
$items[] = $i->getId();
}
// multiselect - radši setuju obojí
$component['form']['contracts']->setValue($items);
$component['form']['contracts']->setDefaultValue($items);
$component->redrawControl();
}
};
return $component;
}
protected function createComponentAddContract()
{
return $this->IAddContractFactory->create();
}
Takto vypadá snippet který se překresluje
{snippet contract}
{var $form = $control['form']}
<div class="form-group">
<label class="col-lg-3 control-label">{$form['contracts']->caption}</label>
<div class="col-lg-9">
<div class="input-group">
<span class="input-group-btn">
<button type="button" data-toggle="modal" data-target="#contractGridModal" class="btn btn-default btn-icon bg-teal legitRipple"><i class="icon-folder-search"></i></button>
</span>
<select n:name="contracts" class="form-control select"></select>
</div>
</div>
</div>
{/snippet}
Děkuji
Editoval Danny (19. 2. 2020 9:24)
- Danny
- Člen | 146
SetItems mi nasetuje položky které je možné ze multiselectu vybrat ne? Já potřebuji aby mi to nasetovalo že z X položek(který už tam mám) se vybere/zaškrtne v multiselectu Y položek.
Aby ta množina co vše lze z multiselectu vybrat zůstala, jen se mi samo nasetovalo že uživatel vybral 2–3 položky z toho seznamu v multiselectu
Editoval Danny (19. 2. 2020 9:45)
- Polki
- Člen | 553
Cau pokud mas spousteci akci na prekresleni v submitu formu AddContract a
prekreslujes form SelectContractGrid, nebo jeho cast, tak ti to ani fungovat
nemuze. Ajax je stejny jako klasicky request, coz ma za nasledek to, ze se ta
komponenta vytvori nova a uplne prazdna.
Nezmeni se jen obsah te odeslane, jelikoz jeji data se odeslaly na server a
nastavily do values.
Reseni je bud si se submitovanym formem na server posilat i data, ktera ma mit druhy formular a potom to plnit v sablone (protoze sablona vola metodu createComponent takze vrati novou instanci) nebo to plnit v te metode crateComponent, nebo udelat jeden nadrazeny form, ktery bude spojovat dohromady tyto dva a odesilat je v sobe naraz. Pak ten problem zmizi.
- Danny
- Člen | 146
@Polki
Díky za reakci. Je to obráceně, mám grid v kterém se udělá přes
tento handle
public function handleSelect($id) {
$item = $this->contractDao->find($id);
$this->onChange($item);
if ($this->getPresenter()->isAjax()) {
$this['grid']->reload();
} else {
$this->redirect('this');
}
}
Vrací item v eventu onChange a ten se setuje do AddContract viz co jsem posílal nahoře.
protected function createComponentSelectContractsGrid()
{
$component = $this->IContractGridComponent->create();
$component->onChange[] = function ($items) {
if ($this->isAjax()) {
// druhá komponenta
/** @var AddContractComponent $component */
$component = $this['addContract'];
// tohle mi nevrátí aktuální stav po druhém přidání multiselectu
$items = $component['form']['contracts']->getValue();
foreach($item as $i) {
$items[] = $i->getId();
}
// multiselect - radši setuju obojí
$component['form']['contracts']->setValue($items);
$component['form']['contracts']->setDefaultValue($items);
$component->redrawControl();
}
};
return $component;
}
Tzn že se mi neprovádí žádný submit ale je to pouze handle metoda s eventem.
Ono to právě funguje, ale jenom na jedno překreslení, pokud z toho gridu pošlu do AddContract ten item/items do multiselectu a odešlu formulář, tak se mi tam ta hodnota zachová, ale pokud budu setovat 2× po sobe (bez odeslání) tak se mi tam ta předchozí hodnota neuchová, čemuž moc nerozumim. Nicméně varianta ukládání na server a tahání z5 do šablona pro mě v tuhle chvíli není úplně vhodná. Udělat z toho jeden fo se mi taky moc nechce, mám to rozdělené do komponent právě z důvodu znovupoužitelnosti.
- Polki
- Člen | 553
Tak jestli to delas pres klasicky handle, tak se vlastne udela to, ze se vytvori ty formulare oba a oba prazdne takze kdyz prekreslujes cast formulare, tak vlastne prekreslujes prazdny formular.
No a nejde to udělat tak, že by se to zachovalo ty hodnoty, jelikož na server se žádné neposílají, tedy forumář se nemá čím předvyplnit
Editoval Polki (19. 2. 2020 23:50)
- Danny
- Člen | 146
A jak je možné že se mi tam drží ty data i s tou hodnotou která předala handle? Takže když ten formulář odešlu tak tam mám vše co potřebuju, jen si to nedrží tu hodnotu i po druhém zavolání handle. Navíc překresluju jenom část snippetu ve formu a ten form je obalený přes snippetArea.
- Polki
- Člen | 553
Danny napsal(a):
A jak je možné že se mi tam drží ty data i s tou hodnotou která předala handle? Takže když ten formulář odešlu tak tam mám vše co potřebuju,
No přece protože ten formulář je vykreslený na klientovi, takže se z něj překreslí jen ta část, kterou vrátila handle metoda. Tedy zbytek zůstane nastavený tak jak byl i před odesláním ne?
jen si to nedrží tu hodnotu i po druhém zavolání handle. Navíc překresluju jenom část snippetu ve formu a ten form je obalený přes snippetArea.
Bez celého kódu není moc co řešit, protože chyb může být mraky. Počítám ale, že někde máš nastavenou nějakou JS událost špatně a tím, že se překreslí snippet s hodnotami, tak se potom například odesílají do handle špatná data, překreslí se více snippetů, nebo se neodesílá ajaxem a tím pádem se překreslí celá stránka i s fomrulářem.
Tipoval bych tedy na špatné bindování událostí v JS, jelikož při překreslení snippetu se některá pravidla neaplikují na nově změněná data. Běžný problém JavaScriptu. Řešení je navěštit události přes jQuery metodu $(document).on();
- Danny
- Člen | 146
Ok posílám jak to mám řešené, zjednodušeně aby v tom nebyl bordel.
Grid, v kterém uživatel vybere položku a volá se handleSelect() kde se přes event onChange přenáší informace.
class ContractGridComponent extends BaseComponent
{
public function handleSelect($id) {
$item = $this->contractDao->find($id);
$this->onChange($item);
if ($this->getPresenter()->isAjax()) {
$this['grid']->reload();
} else {
$this->redirect('this');
}
}
/**
* @return \Ublaboo\DataGrid\DataGrid
* @throws \Ublaboo\DataGrid\Exception\DataGridException
*/
public function createComponentGrid()
{
$grid = $this->createGrid();
// stuff
// handle na vyber
$grid->addAction('select', '', 'select!')
->setAlign('right')
->setIcon('select2')
->setClass('btn btn-xs bg-success ajax')
->setTitle('Vybrat');
return $grid;
}
public function render()
{
$template = $this->template;
$template->setFile(__DIR__ . '/component.latte');
$template->render();
}
}
interface IContractGridComponent
{
/** @return ContractGridComponent */
public function create();
}
Form na přidání
class AddContractComponent extends BaseComponent {
protected function createComponentForm() {
$form = $this->create();
// ziskani existujicich kontraktu
$contracts = ...
$form->addMultiSelect('contracts', 'Navázané smlouvy', $contracts);
$form->addSubmit('send', 'Uložit');
$form->onSuccess[] = function(Form $form, ArrayHash $values) {
// zpracovani
};
return $form;
}
public function render() {
$template = $this->template;
$template->contract = $this->contract;
$template->setFile(__DIR__ . '/component.latte');
$template->render();
}
}
interface IAddContractFactory {
/** @return AddContractComponent */
public function create();
}
Presenter kde by měli komunikovat tyto 2 komponenty. Přes on change se získá hodnota z gridu, nasetuje do addCntract a refreshne její snippet.
class ContractPresenter extends BasePresenter
{
/** @var IAddContractFactory @inject */
public $IAddContractFactory;
/** @var IContractGridComponent @inject */
public $IContractGridComponent;
protected function createComponentAddContract()
{
return $this->IAddContractFactory->create();
}
protected function createComponentContractGrid()
{
$component = $this->IContractGridComponent->create();
$component->enableSelect();
$component->onChange[] = function ($item) {
if ($this->isAjax()) {
/** @var AddContractComponent $component */
$component = $this['addContract'];
$items = $component['form']['contracts']->getValue();
foreach($item as $i) {
$items[] = $i->getId();
}
$component['form']['contracts']->setValue($items);
$component['form']['contracts']->setDefaultValue($items);
$component->redrawControl('contract');
}
};
return $component;
}
}
Šablona pro AddContract component.latte
{snippetArea form}
<form class="form-horizontal" n:name="form">
// ostatni polozky
{snippet contract}
{var $form = $control['form']}
<div class="form-group">
<label class="col-lg-3 control-label">{$form['contracts']->caption}</label>
<div class="col-lg-9">
<div class="input-group">
<select n:name="contracts" class="form-control select"></select>
</div>
</div>
</div>
{/snippet}
<div class="text-right">
<button class="btn btn-success legitRipple" n:name="send">Uložit <i class="icon-check position-right"></i></button>
</div>
{/snippetArea}