Jak v nette zprovoznit odeslání formuláře pomocí ajaxu

- andros
 - Člen | 145
 
Ahoj, mohl by mi prosím, někdo poradit funkční příklad odeslání
formuláře ajaxem ? Rád bych si to vyzkoušel na první aplikaci. Našel jsem
tento návod: https://pla.nette.org/…ivajici-ajax
Tento návod využívá js soubor jquery.ajaxform.js (https://componette.org/search/?…)
, odkaz ale na tento soubor již neukazuje.

- petr.jirous
 - Člen | 128
 
použij https://componette.org/…tte.ajax.js/ a pak už jenom stačí formuláři dát třídu ajax

- andros
 - Člen | 145
 
Nějak se mi nedaří přemluvit formulář, aby fungoval ajaxově. Co potřebuju: v detailu produktu mám formulář pro vložení zboží do košíku. Bez ajaxu vše funguje.
v šabloně mám nalinkovaný soubor nette.ajax.js
<script type="text/javascript" src="{$basePath}/js/nette.ajax.js"></script>
v js souboru mám inicializaci:
$(function () {
    $.nette.init();
});
V šabloně presenteru potřebuju pro začátek znovu vykreslit jet flash zprávu, takže jsem ji obalil do snipetu:
{snippet flash}
    <div class="row">
        <div class="col-lg-12">
            {foreach $flashes as $flash}
                <div class="alert alert-dismissible alert-{$flash->type}">
                    <button type="button" class="close" data-dismiss="alert">×</button>
                    {$flash->message}
                </div>
            {/foreach}
        </div>
    </div>
    {/snippet}
a v presenteru mám metody pro formulář:
protected function createComponentAddToBasketForm()
    {
        $form = new Form;
        $form->getElementPrototype()->class('ajax');
        $form->addText('quantity', 'Počet ks:');
        $form->addHidden('prod_id');
        $form->addHidden('guest_id');
        $form->addHidden('name');
        $form->addHidden('price');
        $form->setDefaults([
            'quantity' => 1,
            'prod_id' => $this->product['id'],
            'name' => $this->product['name'],
            'price' => $this->product['d1']
        ]);
        $form->addSubmit('send', 'Do košíku');
        $form->onSuccess[] = [$this, 'AddToBasketFormSucceeded'];
        return $form;
    }
    public function AddToBasketFormSucceeded($form, $values)
    {
        $this->productManager->insertProduct([
            'quantity' => $values->quantity,
            'prod_id' => $values->prod_id,
            'guest_id' => $this->getHttpRequest()->getCookie('guest'),
            'name' => $values->name,
            'price' => $values->price
        ]);
        $this->flashMessage('Přidali jste zboží do košíku', 'success');
        if (!$this->isAjax())
            $this->redirect('Product:default', array("id" => $values->prod_id));
        else {
            $this->redrawControl('flash');
        }
    }
Po odeslání formuláře se mi vůbec neprovede zpracování formuláře (
vložení dat do databáze) a flash zpráva se nezobrazí.
Laděnka říká že tam něco ajaxového proběhlo
http://prntscr.com/e036ox
Ale provede se to samé, jako při načtení stránky.
Kde dělám chybu ?
Pokud odstraním z formuláře class ajax vše funguje jak má

- iNviNho
 - Člen | 352
 
Skús pozrieť v chrome cez developer consolu network, či naozaj po stlačení submit tlačídla sa posiela niečo na server.
Mal by si tam vidieť tvoj link a za nim niečo ako URL&do=addToBasketForm…
Taktiež ešte skontroluj či po submitnutí ti nevyhodí v console nejaký error.
Editoval iNviNho (25. 1. 2017 12:56)

- andros
 - Člen | 145
 
class ajax přidávám v továrničce formuláře:
$form->getElementPrototype()->class('ajax');
pokud ho přidám přímo do formuláře přímo na button, udělá se klasický redirect
Konsole žádnou chybu nevyhodí
v Network se po kliknutí pošle na server url adresa aktuální stránky, bez
dalších parametrů, takže jako kdyby se stránka načetla znova

- CZechBoY
 - Člen | 3608
 
Včera/dneska jsem psal, že je potřeba to mít v action metodě :-) prácí s šablonou samozřejmě nechej v render metodě.
private $product;
public function actionDefault()
{
	$this->product = $this->productManager->getProduct();
}
public function renderDefault()
{
	$this->template->product = $this->product;
}
				
- andros
 - Člen | 145
 
I když to přesunu do metody actionDefault, problém je pořád stejný
Celý presenter vypadá takto:
<?php
namespace FrontModule;
use Nette\Application\UI\Form;
use App\Model\CategoryManager;
use App\Model\ProductManager;
class ProductPresenter extends BasePresenter
{
    private $productManager;
    private $categoryManager;
    private $product;
    /**
     * @var $categoryId
     *
     */
    private $categoryId;
    private $categories;
    public function __construct(ProductManager $productManager, CategoryManager $categoryManager )
    {
        parent::__construct();
        $this->productManager = $productManager;
        $this->categoryManager = $categoryManager;
    }
    public function renderDefault($id)
    {
        $this->template->product = $this->product;
        /**
         * ID defaultní kategorie produktu (pokud neexistuje defaultní kategorie , použije se první nalezená
         */
        $this->template->categoriesBreadcrumb = $this->categories;
        $this->template->stock = $this->product->ref('stock', 'stock_id')->name;
        $this->template->stock_label = $this->product->ref('stock', 'stock_id')->label_type;
        $this->template->producer = $this->product->ref('prod_producer', 'producer_id')->name;
        $this->template->images = $this->product->related('prod_images');
        $this->template->image_default = $this->product->related('prod_images')->where('default_img', '1')->fetch();
    }
    public function actionDefault($id)
    {
        $this->product = $this->productManager->getProduct()
            ->where('active',1)
            ->get($id);
        if (!$this->product) {
            $this->error('Produkt nebyl nalezen!');
        }
        $this->categoryId = $this->product->related('prod_cat')->where('default','1')->fetch();
        if (!$this->categoryId) {
            $this->categoryId = $this->product->related('prod_cat')->limit(1)->fetch();
        }
        $this->categories = $this->getCategoriesParentName($this->categoryId->category_id);
        krsort($this->categories);
    }
    protected function createComponentAddToBasketForm()
    {
        $form = new Form;
        $form->getElementPrototype()->class('ajax');
        $form->addText('quantity', 'Počet ks:');
        $form->addHidden('prod_id');
        $form->addHidden('guest_id');
        $form->addHidden('name');
        $form->addHidden('price');
        $form->setDefaults([
            'quantity' => 1,
            'prod_id' => $this->product['id'],
            'name' => $this->product['name'],
            'price' => $this->product['d1']
        ]);
        $form->addSubmit('send', 'Do košíku');
        $form->onSuccess[] = [$this, 'AddToBasketFormSucceeded'];
        return $form;
    }
    public function AddToBasketFormSucceeded($form, $values)
    {
        $this->productManager->insertProduct([
            'quantity' => $values->quantity,
            'prod_id' => $values->prod_id,
            'guest_id' => $this->getHttpRequest()->getCookie('guest'),
            'name' => $values->name,
            'price' => $values->price
        ]);
        $this->flashMessage('Přidali jste zboží do košíku', 'success');
        if (!$this->isAjax())
            $this->redirect('Product:default', array("id" => $values->prod_id));
        else {
            $this->redrawControl('flash');
        }
    }
}
				
- CZechBoY
 - Člen | 3608
 
- Nástroje pro vývojáře (třeba přes pravej klik někam do stránky, poslední položka Revize prvku)
 - záložka Network/Síť
 - vyfiltruj XHR
 - klikni na tlačítko ve formuláři
 - měl by se ti tam objevit jeden http požadavek, klikni na něj
 - zkopíruj http hlavičky i parametry pro požadavek i odpověď
 - přepni na záložku Response/Odpověď a pak sem napiš jestli to je json (pošli) nebo html
 

- andros
 - Člen | 145
 
Takže:
Request URL:http://localhost/playhracky3/www/product/10230
Request Method:GET
Status Code:200 OK
Remote Address:127.0.0.1:80
Response Headers
view source
Cache-Control:no-store, no-cache, must-revalidate
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:6645
Content-Type:text/html; charset=utf-8
Date:Wed, 25 Jan 2017 13:29:31 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive:timeout=5, max=100
Pragma:no-cache
Server:Apache/2.2.31 (Win32) DAV/2 mod_ssl/2.2.31 OpenSSL/1.0.2e mod_fcgid/2.3.9 mod_wsgi/3.4 Python/2.7.6 PHP/7.0.9 mod_perl/2.0.8 Perl/v5.16.3
Set-Cookie:PHPSESSID=9dtm5fd55auqrscdlt212edqm0; expires=Wed, 08-Feb-2017 13:29:31 GMT; Max-Age=1209600; path=/; HttpOnly
Vary:X-Requested-With,Accept-Encoding
X-Frame-Options:SAMEORIGIN
X-Powered-By:Nette Framework
X-Tracy-Ajax:1
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:cs-CZ,cs;q=0.8
Connection:keep-alive
Cookie:Phpstorm-f1db6934=37031b54-37ac-4adb-97c5-b4368090fd7c; guest=58813b0babe94; PHPSESSID=9dtm5fd55auqrscdlt212edqm0
Host:localhost
Referer:http://localhost/playhracky3/www/product/10230
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
X-FireLogger:1.3
X-Requested-With:XMLHttpRequest
X-Tracy-Ajax:59591ff4e7
V záložce response je html celé stránky.

- andros
 - Člen | 145
 
připadá mi, že je to podobný problém jako tady: https://forum.nette.org/…lar-s-ajaxem

- andros
 - Člen | 145
 
zkusil jsem místo formuláře v šabloně vypsat formulář
{control addToBasket}
a konzole vyhodi chybu:
Uncaught ReferenceError: Nette is not defined
at Object.before (nette.ajax.js:318)
at Function.<anonymous> (nette.ajax.js:42)
at Function.each (jquery.js:371)
at Object.fire (nette.ajax.js:40)
at Object.settings.beforeSend (nette.ajax.js:215)
at Function.ajax (jquery.js:8614)
at nette.ajax (nette.ajax.js:225)
at HTMLInputElement.requestHandler (nette.ajax.js:48)
at HTMLFormElement.dispatch (jquery.js:4737)
at HTMLFormElement.elemData.handle (jquery.js:4549)

- andros
 - Člen | 145
 
Tak po mnoha pokusech pokus – omyl jsem nakonec se mi to nakonec povedlo rozhýbat :)
Chyby jsem tam měl dvě
ve formuláři jsem měl
<button class="btn btn-primary">
</button>
Ono to chce ale
<button n:name=send class="btn btn-primary">
</button>
a nenačítal jsem scrip netteForms.min.js bez kterého se to neobejde. Protože ve formuláři nemám validaci, mysel jsem že je tento script zbytečný. Ovšem nette.ajax.js se bez něj prostě neobejde

- andros
 - Člen | 145
 
Když už mi funguje odesílání formuláře ajaxem, snažím se přidat spinner, aby bylo vidět, že se něco děje, než se požadavek zpracuje.
v @layout.latte jsem přidal před inicializaci $.nette.init();
<script src="{$basePath}/js/extensions/spinner.ajax.js"></script>
do css jsem dal
#ajax-spinner {
    position: fixed;
    width: 32px;
    height: 32px;
    /* - use if you use bacground image, no ico */
    background: url('../img/ajax-loader.gif') no-repeat;
    z-index: 123456;
    color: green;
}
Ale spinner se ne a ne objevit :)
Když to spinner.ajax.js přidám na zkoušku alert (např.)
start: function () {
            this.counter++;
            if (this.counter === 1) {
                this.spinner.show(this.speed);
                alert('test');
            }
        },
Tak po kliknutí na tlačítko formuláře se mi alert okno zobrazí, takže by to mělo fungovat. Ale nastylovaný spinner se nezobrazí.
Poradíte mi prosím někdo ?

- novasol
 - Člen | 1
 
Jen doplňující informaci, snad to někomu pomůže. Po pěti hodinách jsem zjistil, že hned pod namespace v presenteru používám
use Nette\Forms\Form;
namísto správného
use Nette\Application\UI\Form;
Dejte si na to pozor! Jinak Vám AJAX pojede, ale nebude se volat callback v presenteru a pokaždé bude response komplet stránka, resp. funkce renderDefault() !
Editoval novasol (17. 5. 2018 21:24)