Znovunacteni dat formulare po Ajax submitu

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

Zacinam se snippety a ajaxovanymi formulari. Predelavam stavajici formulare na sumbmit pres ajax (snippety a nette.ajax.js). Submit s updatem tabulky jsem rozchodil.

Ted resim situaci, ze bych potreboval po DB update znovu nacist data z tabulky a formular prekreslit (zaslat snippet). Provedene zmeny mohou mit dopady na obsah poli formulare (napr. odvozene readonly inputy via db procedura) nebo jineho formulare. Toto mam dnes reseno pomoci redirectu, kdy se data znovu nactou z DB a vyrendruji. Jak to nejlepe resit s AJAXem & snippety na vybrane formulare, abych neposilal celou stranku?

Diky

public function renderAccount($userId)
{
    if ($this->isAjax()) {
        $this->redrawControl('flashes');
        $this->redrawControl('accountForm');
    }
}

public function accountFormSucceeded($form, $values)
{
    $userId = $values[UserManager::COLUMN_ID];
    $this->saveUser($userId, $values);

    if ($this->isAjax()) {
	  		// jak vynutit redraw formulare s novymi hodnotami? Mohou byt upraveny Db procedurou nebo jinym formularem
    } else {
        $this->redirect(':Core:Administration:account', $userId);
    }
}
chaky
Člen | 22
+
0
-

Jsem sice take zacatecnik, nicmene podle mne by melo stacit to, ze do snippet bloku uzavres vse co chces aby se updatovalo a z toho accountFormSucceeded() zavolas v presenteru redrawControl() bez jakehokoliv dalsiho parametru – tim se provede aktualizace vsech zmenenych snippetu.

BTW: nedavno jsem si se snippety zpusobil takovou pasticku, ktera souvisela s tim, ze jsem zacal v hojne mire a nekdy bez rozmyslu pouzivat makra n:if a n:snippet. Nechtel jsem prenaset obsah cele tabulky, takze jsem v ni mel radek <tr n:if=„$cond“ n:snippet=„name“> … jenomze kdyz pri prvnim vytvareni dokumentu nebylo splneno $cond, tak nevzniknul ani ten snippet a prestoze treba po odeslani formulare uz bylo $cond splneno, tak redrawControl(‚name‘) nemel co updatovat – za snippet jsem pak tedy musel oznacit celou tabulku.

Honza.Mottl
Člen | 104
+
0
-

Diky. Clovek se obcas divi co se mu podari vyrobit :)

U formulare mi redrawControl() nestaci. Preklesli se formular vytvoreny na zacatku zpracovani a ten obsahuje puvodni hodnoty zaslane postem. Ja potrebuji znovu nacist data z tabulky a nastavit je do formulare. To znamena zmenit hodnoty v inputech formulare. To z onSuccess funkce nejde, protoze parametr $form nedovoluje volani referenci.

Potreboval bych zmenit formular a nebo znovu vytvorit komponentu, coz nevim jak spravne udelat.

Jine reseni by bylo predat rizeni na klienta a ten by spustil novy ajaxovy request. Ale to se i zda dost pres ruku.

Honza.Mottl
Člen | 104
+
0
-

Zda se, ze jsem po boji nasel reseni. Proste jsem komponentu formulare zrusil a ona se sama vytvorila :)

public function accountFormSucceeded($form, $values)
{
    $userId = $values[UserManager::COLUMN_ID];
    $this->saveUser($userId, $values);

    if ($this->isAjax()) {
       $this->template->userRecord = $this->userManager->getUser($userId); // nacteni aktualnich dat
       $this->removeComponent($this->getComponent('accountForm'));  // zruseni formulare, pri redraw se vytvori s aktualnimi daty
       $this->redrawControl('accountForm');
       $this->redrawControl('flashes');
    } else {
        $this->redirect(':Core:Administration:account', $userId);
    }
}
Rob Bob
Člen | 60
+
+1
-

zavolej setDefaults() na nastavení hodnot formuláře v renderAccount(), render se zavolá až po zpracování formuláře a nastavíš tam tak už aktuální data

Editoval Rob Bob (7. 9. 2017 9:02)

Honza.Mottl
Člen | 104
+
0
-

Diky, ale bohuzel to nezabralo (uzivam Nette 2.3). Duvodem je podle meho nazoru, ze formular ziskavam hodnotou a pak si menim pouze svou kopii. Existuje moznost jak dostat formular referenci?

public function renderAccount($userId)
{
    if ($userId)
    {
        if (!is_numeric($userId)) {
            throw new BadRequestException('Účet nebyl nalezen: '.$userId, Http\IResponse::S404_NOT_FOUND);
        } else if (!($userRecord = $this->userManager->getUser($userId))) {
            throw new BadRequestException('Účet nebyl nalezen: '.$userId, Http\IResponse::S404_NOT_FOUND);
        } else {
            $this->template->mode = 'edit';
            $this->template->userRecord = $userRecord;
        }
    } else {
        // novy ucet
        $this->template->mode = 'edit';
    }

	    // pokus o nastaveni hodnot pri redraw. Bohuzel to nezabralo. Zmeni se zrejme jen kopie formulare
    $form = $this->getComponent('accountForm');
    if (isset($form) && isset($this->template->userRecord)) {
        $form->setDefaults($this->template->userRecord);
    }
}

public function accountFormSucceeded(Form $form, $values)
{
    $userId = $values[UserManager::COLUMN_ID];
    $this->saveUser($userId, $values);

    if ($this->isAjax()) {
	    $this->template->userRecord = $this->userManager->getUser($userId); // nacteni aktualnich dat
        //$this->removeComponent($this->getComponent('accountForm'));  // Toto funguje
        $this->redrawControl('flashes');
        $this->redrawControl('accountForm');
    } else {
        $this->redirect(':Core:Administration:account', $userId);
    }
}
Rob Bob
Člen | 60
+
0
-

Tohle musí fungovat, takže problém bude někde jinde. Ukaž ještě šablonu a createComponentXXX metodu. Co ti přesně přijde jako odpověd (sekce ‚snippets‘)?

Honza.Mottl
Člen | 104
+
0
-

Snippety chodi dobre, na Jsonove odpovedi jsem se v Chromium/DeveloperTools/Network dival . A spravne se zupdatuji do stranky.

Udelal jsem si ladici label, abych mel jistotu ze se mi data spravne zobrazuji. Pro ladici ucely jsem jednonu sloupci konkatenoval na konec ‚|‘. Pak jsem vypsal z renderAccount zdrojovou hodnotu z UserRecord a hodnotu po nastaveni do formulare. Vysledek je:

Ajax, UserRecord=hodnota|, FormVal=hodnota

Takze $form->setDefaults($this->template->userRecord, true) tam ty hodnoty vubec nenastavilo. Takze bud delam neco spatne, nebo Nette odmita do komponenty formulare zasahovat. Kdyz formular zrusim $this->removeComponent, tak je vse OK, protoze se komponenta znovu vytvori s novymi hodnotami ve createComponentAccountForm().

{snippet accountFormSnippet}
    <label>{$testLabel}</label>
    {include $formPath, form => accountForm, class => ajax}
{/snippet}



public function renderAccount($userId)
{
    $this->template->testLabel = $this->testLabel;

    if ($userId)
    {
        if (!is_numeric($userId)) {
            throw new BadRequestException('Účet nebyl nalezen: '.$userId, Http\IResponse::S404_NOT_FOUND);
        } else if (!($userRecord = $this->userManager->getUser($userId))) {
            throw new BadRequestException('Účet nebyl nalezen: '.$userId, Http\IResponse::S404_NOT_FOUND);
        } else {
            $this->template->mode = 'edit';
            $this->template->userRecord = $userRecord;
        }
    } else {
        // novy ucet
        $this->template->mode = 'edit';
    }


    if ($this->isAjax()) {
        // pokus o nastaveni hodnot pri redraw
        $form = $this['accountForm'];  //$this->getComponent('accountForm');
        if (isset($form) && isset($this->template->userRecord)) {
            $form->setDefaults($this->template->userRecord, true);
            // V user record jsou spravna data
            $this->template->testLabel .= 'UserRecord='.$this->template->userRecord['text_objednavka_vystavil'].', ';
            // do formulare se ale nenastavila
            $this->template->testLabel .= 'FormVal='.$form->getValues()['text_objednavka_vystavil'];
        }
    }
}

public function accountFormSucceeded(Form $form, $values)
{
    $userId = $values[UserManager::COLUMN_ID];

    // pro ladici ucely jsem zmenil hodnotu jednoho sloupce a tu chci propasirovat na klienta
    $values['text_objednavka_vystavil'] .='|';
    $this->template->userRecord = $values;
    $this->saveUser($userId, $values);

    if ($this->isAjax()) {
        $this->testLabel = 'Ajax, ';
        //$this->removeComponent($this->getComponent('accountForm')); // kdyz to odkomentuji, tak to funguje
        $this->redrawControl('flashes');
        $this->redrawControl('accountFormSnippet');
    } else {
        $this->redirect(':Core:Administration:account', $userId);
    }
}
Rob Bob
Člen | 60
+
0
-

Ten formulář je v includované šabloně, budeš asi muset použít snippetArea

https://doc.nette.org/…ication/ajax#…

Honza.Mottl
Člen | 104
+
0
-

Obsah snippetu se zasila spravne, snippet je definovan na nejvyssi urovni. S includem to nesouvisi. Ten problem je navozen jiz v labelu <label>{$testLabel}</label>. $form->setDefaults nenastavi hodnoty $this->template->userRecord do formulare.

Obsah labelu je: Ajax, UserRecord=hodnota|, FormVal=hodnota

V kodu je to:

public function renderAccount($userId)
{
	...

    if ($this->isAjax()) {
        // pokus o nastaveni hodnot pri redraw
        $form = $this['accountForm'];  //$this->getComponent('accountForm');
        if (isset($form) && isset($this->template->userRecord)) {
            $form->setDefaults($this->template->userRecord, true);
            // V user record jsou spravna data se znakem | na konci
            $this->template->testLabel .= 'UserRecord='.$this->template->userRecord['text_objednavka_vystavil'].', ';
            // do formulare se ale nenastavila a znak | na konci chybi
            $this->template->testLabel .= 'FormVal='.$form->getValues()['text_objednavka_vystavil'];
        }
    }
}
Rob Bob
Člen | 60
+
+2
-

Vlastně už vím v čem je problém. Toto je kód setDefaults

public function setDefaults($values, $erase = false)
     {
         if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
             $this->setValues($values, $erase);
         }
         return $this;
     }

$form->isSubmitted() bude v tomto případě true, musíš použít $form->setValues(), jestli tam chceš změnit/vložit nějaké dopočítané hodnoty. Jinak ve formuláři budeš mít po proběhlém zpracování formuláře $form->getValues() vždy ty které byly vyplněny na straně klienta. (Neproběhne redirect, po kterém by bylo $form->isSubmitted() false jako v případě neajaxového požadavku.)

Editoval Rob Bob (8. 9. 2017 10:57)

Honza.Mottl
Člen | 104
+
0
-

To je ono!!! Ted uz mi to funguje :) Diky moc za pomoc a za cas cos nad tim musel stravit.
V popisu API jsem funkci u formulare ani u Containeru nenasel. Ale public je.

Honza.Mottl
Člen | 104
+
0
-

Mysleno funkci $form->getValues()

Honza.Mottl
Člen | 104
+
0
-

Oprava, $form->setValues()

Rob Bob
Člen | 60
+
0
-

No je to @internal metoda, ale používám to v takových případech taky (jen když potřebuješ zobrazit po ajaxovém submitu ve formuláři upravená data) a lepší řešení jsem nenašel. Jen se to nesmí cpát do actionXXX metod, protože by sis tím přepsal data od klienta.

Editoval Rob Bob (8. 9. 2017 12:48)

Honza.Mottl
Člen | 104
+
0
-

Rozumim. Diky