Překreslení snippetu, form nedrží předanou hodnotu

Danny
Člen | 146
+
0
-

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)

Failips
Člen | 54
+
0
-

Nechces pouzit setItems namiesto setValue?? :)

Danny
Člen | 146
+
0
-

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
+
0
-

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
+
0
-

@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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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}
Danny
Člen | 146
+
0
-

bump