Dependency select AJAX v includovaném formuláři

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

Ahoj,
mám dva dotazy – poté co se několik dní snažím skamarádit s AJAXem ve formuláři v nette. Nakonec bych potřeboval vytvořit 4 selecty (zatím jsou zkušebně dva) – kdy každý select po výběru přes ajax načte data pro select následující (ten první samozřejmě může načíst data už při vytvoření formuláře) → ve smyslu Typ->značka->model->podkategorie. Dva problémy které v tom vidím:

  1. pročetl jsem a vyzkoušel nesčetně způsobů jak zaručeně dostat ajax do formuláře v nette – díky tomu mám celý kód plný zakomentovaných pokusů a nepotřebných proměnných – tady proto uvádím snad původní jednoduchou neupravenou verzi která zobrazí vše bez chyb – nic z toho však nešlo – předpokládám, že je to tím, že mám formulář ve vlastním souboru s vlastní šablonou – je někde návod, který opravdu funguje na tuto situaci – pokud bych si mohl vybírat ideálně s jquery na obsluhu ajaxu
  2. při načítání hodnot selectu bych potřeboval mít přístup do modelu, tedy aby model dodal potřebná data do selectu – v presenteru to funguje, ale uvnitř formuláře už ne(inject modelu je asi pozdě, při konstrukci formuláře tam posílám $this,$name a ne odkaz na daný model) – co s tím?

Takže prozatím to co mi funguje a otázka je jak to rozšířit?
HomepagePresenter.php

<?php
 protected function createComponentHledaniMain($name)
        {
        $form = new \App\FrontModule\Forms\HledaniMain($this,$name);
        return $form;
        }
?>

Dále mám zmíněný formulář HledaniMain (tady bych nejraději řešil obsluhu Ajaxu – aby z formuláře byla soběstačná jednotka kterou presenter vloží a dál se o ní nestará):

<?php
class HledaniMain extends \Nette\Application\UI\Control
{

    private $select,$form;

    public function render()
    {
      $template = $this->createTemplate();
      $template->setFile(__DIR__ . '/templates/hledaniMain.latte');
      $template->registerFilter(new \Nette\Latte\Engine());
      $template->render();
    }
    private function setSelect(){
        //tady se nějakým způsobem vytvoří data do selectu, pro úplnost předpokládejme následující
		$this->select=$data;
    }
    public function createComponentHledaniMain(){
        $this->form = new \Nette\Application\UI\Form;
		$this->setSelect();
        $this->form->addSelect('kind', 'Druh', $this->select);
        $this->form->addSelect('mark', 'Vyberte druh')
            ->setPrompt('...');

        $this->form->addSubmit('search', 'Vyhledat')
               ->onClick[] = callback($this, "formSucceeded");
        return $this->form;
    }
	public function formSucceeded(\Nette\Forms\Controls\SubmitButton $button) {
       $values = $button->getForm()->getValues();
    }
}
?>

Dále taky šablona hledaniMain.latte (do budoucna bude složitější proto to celé dělám):

<?php

{form hledaniMain}
 {input kind}<br />
 {snippet mark}
     {input mark}<br />
 {/snippet}
 {input search}

{/form}
?>

Editoval argosovo (17. 12. 2014 13:49)

karelu
Člen | 14
+
+3
-

Ahoj,
zkus se podívat na řešení od Martina Zlámala, možná Ti to pomůže nasměrovat:
http://www.zeminem.cz/…t-select-box

argosovo
Člen | 54
+
+2
-

Ahoj,
po delší odmlce uvádím funkční řešení na které jsem přišel po nesčetně nefunkčních pokusech… Formulář jsem prvně rozchodil dle návodu výše – děkuji, následně jsem chtěl přesunout formulář do komponenty která mi generuje formulář a rozšiřuje \Nette\Application\UI\Control – tak aby šla formuláři nastavit šablona. Následně cokoliv jsme v šabloně obalil makrem snippet hlásilo se jako neexistující komponenta. To co se bohužel nikde nepíše, nebo spíš člověk neví, že to má hledat je, že „Všechny prvky v komponentě musí mít jméno směrované do komponenty.“ (ano, pro zkušenější nebo pro ty co si tím prošli asi naprosto jasná informace, pro začátečníka jako já minimálně dva týdny pokusů proč to pořád nejde – moje componenta se jmenuje hledaniMain takže si všímejte zejména toho, kde všude musí být tento název uveden aby to fungovalo) takže v šabloně:

<?php
{form hledaniMain}
                    {input one}
                    {snippet two}
                        {var $_form = $form = $presenter['hledaniMain']}
                        {input hledaniMain-two}
                    {/snippet}
                    {snippet three}
			            {var $_form = $form = $presenter['hledaniMain']}
                        {input hledaniMain-three}
                    {/snippet}

                    {input send}

{/form}
?>

v javascriptu:

<script>
		$(function(){
			$.nette.init();
                        $('body').on('change', 'select[name=one]', function () {
                            $.nette.ajax({
			        url: '?do=hledaniMain-invalidateTwo',
			        data: {
			            'hledaniMain-value': $('select[name=one]').val(),
			        }
			    });
			});

			$('body').on('change', 'select[name=two]', function () {
			    $.nette.ajax({
			        url: '?do=**hledaniMain-invalidateThree',
			        data: {
			            'hledaniMain-valueOne': $('select[name=one]').val(),
			            'hledaniMain-valueTwo': $('select[name=two]').val(),
			        }
			    });
			});

		});
</script>

Pro úplnost funkčního řešení Komponenty obsahující formulář s ajaxem pomocí snipettu:
V komponentě:

<?php
namespace App\FrontModule\forms;
use \Nette\Application\UI,
    Nette\ComponentModel\IContainer,
    Nette\Forms;
use Nette\Application\UI\form;
use Nette\Diagnostics\Debugger;

class HledaniMain extends \Nette\Application\UI\Control
{
    private $databaseOne = ['1', '2', '3'];
	private $databaseTwo = [
		['11', '12', '13'],
		['22', '23', '24'],
		['33', '34', '35'],
	];
	private $databaseThree = [
		[
			['111', '112', '113'],
			['121', '122', '123'],
			['131', '132', '133'],
		],
		[
			['222', '223', '224'],
			['232', '233', '234'],
			['242', '243', '244'],
		],
		[
			['333', '334', '335'],
			['343', '344', '345'],
			['353', '354', '355'],
		],
	];
    public function render()
    {

      $template = $this->createTemplate();
      $template->setFile(__DIR__ . '/templates/hledaniMain.latte');
      $template->registerFilter(new \Nette\Latte\Engine());
      $template->render();
    }

    protected function createComponentHledaniMain($name){
        $this->form = new \Nette\Application\UI\Form;
        $this->template->__form = $this->form;
       	$this->form->addSelect('one', 'One', $this->databaseOne)->setDefaultValue(1);
        $this->form->addSelect('two', 'Two', $this->databaseTwo[$this->form['one']->value])->setDefaultValue(1);
	$this->form->addSelect('three', 'Three', $this->databaseThree[$this->form['two']->value][1])->setDefaultValue(1);
	$this->form->addSubmit('send', 'Odeslat');
	$this->form->onSuccess[] = $this->success;
     return $this->form;


    }
    public function getForm(){
        return $this->form;
    }
    public function success(UI\Form $form, $vals) {
		dump($vals);
    }

    public function handleInvalidateTwo($value) {
                //$this->createComponentHledaniMain("hledaniMain");
                $this['hledaniMain']['two']->setItems($this->databaseTwo[$value]);
		$this['hledaniMain']['three']->setItems($this->databaseThree[$value][0]);
		$this->redrawControl();
    }
    public function handleInvalidateThree($valueOne, $valueTwo) {
		$this['hledaniMain']['three']->setItems($this->databaseThree[$valueOne][$valueTwo]);
		$this->redrawControl('three');
    }
}
?>

a nakonec v presenteru:

<?php
class HomepagePresenter extends BasePresenter
{
    	public function renderDefault()
	    {
        }
        protected function createComponentHledaniMain($name)
        {


        $form = new \App\FrontModule\Forms\HledaniMain($this,$name);

        return $form;
        }
?>

a kdyby náhodou tak ještě v šabloně presenteru se zavolá formulář takhle:

<?php
{control hledaniMain}
?>