Contributte\Form-multiplier a závislý selectbox

LuKo
Člen | 116
+
0
-

Ahoj,

snažím se nakombinovat Form-multiplier a závislé selectboxy. Ve formuláři lze přidávat řádky dle potřeby, na každém řádku lze vybrat kategorii a případně i odpovídající podkategorii.

final class NewOrderFormFactory
{
    use Nette\SmartObject;

    public function __construct(private FormFactory $factory, private ListManager $listManager) { }

    public function create(): Form
    {
        $form = $this->factory->create();

		// ...

        $multiplier = $form->addMultiplier('multiplier', function (Nette\Forms\Container $container, Nette\Forms\Form $form) {

            $category = $container->addSelect('category_id', 'Kategorie:', $this->listManager->getCategories());

            $category_sub = $container->addSelect('category_sub_id', 'Podkategorie:')
                ->setHtmlAttribute('data-items', $this->listManager->getSubcategories())
                ->setHtmlAttribute('data-depends', $category->getHtmlName()); // ERROR: Component 'category_id' is not attached to 'Nette\Forms\Form'.

            $form->onAnchor[] = fn() =>
                $category_sub->setItems($category->getValue() ?  $this->listManager->getSubcategories($category->getValue()) : []);

        }, 1, 10);

        // ...

        $form->addSubmit('send', 'Uložit');

        return $form;
    }

}

Řádek $category->getHtmlName() v Multiplieru vrací: Component 'category_id' is not attached to 'Nette\Forms\Form'. Nějak jsem se v tom zasekl a nemohu se hnout dále. Asi to bude jen nějaké přehlédnutí, každopádně byl bych rád za jakékoli nakopnutí správným směrem.

Předem díky za jakýkoli postřeh.

m.brecher
Generous Backer | 840
+
-2
-

@LuKo

is not attached to ‚Nette\Forms\Form‘

To znamená, že se snažíš použít ten prvek předčasně ještě v době, kdy není připojen do hierarchie komponent – to bude v události Anchor. Zkus přesunout ten kód do callbacku onAnchor, nějak takhle:

$form = $this->factory->create();

		// ...

        $multiplier = $form->addMultiplier('multiplier', function (Nette\Forms\Container $container, Nette\Forms\Form $form) {

            $category = $container->addSelect('category_id', 'Kategorie:', $this->listManager->getCategories());

            $category_sub = $container->addSelect('category_sub_id', 'Podkategorie:')
                ->setHtmlAttribute('data-items', $this->listManager->getSubcategories());

            $form->onAnchor[] = function()use($category_sub){
				$category_sub->setHtmlAttribute('data-depends', $category->getHtmlName());
                $category_sub->setItems($category->getValue() ?  $this->listManager->getSubcategories($category->getValue()) : []);
};

        }, 1, 10);

        // ...

        $form->addSubmit('send', 'Uložit');

        return $form;

Píšu z hlavy, tak si to musíš doladit ;).

Editoval m.brecher (28. 3. 2023 1:23)

Pepino
Člen | 253
+
0
-

onAnchor je potřeba volat až mimo multiplier

LuKo
Člen | 116
+
0
-

onAnchor uvnitř Multiplieru mě napadl jako první, ale tam se nezavolá. Zkusil jsem to tedy trochu méně elegantně vyřešit mimo Multiplier:

    public function create(): Form
    {
        $form = $this->factory->create();

        $multiplier = $form->addMultiplier('multiplier', function (Nette\Forms\Container $container, Nette\Forms\Form $form) {
            $category = $container->addSelect('category_id', 'Kategorie:', $this->listManager->getCategories());
            $category_sub = $container->addSelect('category_sub_id', 'Podkategorie:')
                ->setHtmlAttribute('data-items', $this->listManager->getSubcategories());
        }, 1, 10);

        $form->onAnchor[] = function($form) {
            foreach ($form['multiplier']->getComponents() as $item) {
                if(!($item instanceof Submitter)) {
                    $item['category_sub_id']
                        ->setHtmlAttribute('data-depends', $item['category_id']->getHtmlName())
                        ->setItems($item['category_id']->getValue() ? $this->listManager->getSubcategories($item['category_id']->getValue()) : []);
                }
            }
        };

        $form->addSubmit('send', 'Uložit');

        return $form;
    }

Toto již funguje dle očekávání. Jen si nejsem jistý, zda to nelze řešit nějak elegantněji, bez té podmínky if(!($item instanceof Submitter)).

Pepino
Člen | 253
+
0
-

@LuKo funkce getComponents prijma jako parametr typ polozek ktere ma vratit

Martk
Člen | 660
+
0
-

https://github.com/…ltiplier.php#L71 první parametr je vytvořený container.

LuKo
Člen | 116
+
+3
-

Vida, to jsem přehlédl. Nyní je tedy finální verze:

    public function create(): Form
    {
        $form = $this->factory->create();

		// ...

        $multiplier = $form->addMultiplier('multiplier', function (Nette\Forms\Container $container, Nette\Forms\Form $form) {
            $container->addSelect('category_id', 'Kategorie:', $this->listManager->getCategories());
            $container->addSelect('category_sub_id', 'Podkategorie:')
                ->setHtmlAttribute('data-items', $this->listManager->getSubcategories());
        }, 1, 10);

        $multiplier->onCreate[] = function (Nette\Forms\Container $container) {
            $container['category_sub_id']
                ->setHtmlAttribute('data-depends', $container['category_id']->getHtmlName())
                ->setItems($container['category_id']->getValue() ? $this->listManager->getSubcategories($container['category_id']->getValue()) : []);
        };

        // ...

        $form->addSubmit('send', 'Uložit');

        return $form;
    }

Případně je také možná mírně rozepsanější verze:

        $multiplier->onCreate[] = function (Nette\Forms\Container $container) {
            $category = $container->getComponent('category_id');
            $category_sub = $container->getComponent('category_sub_id');

            $category_sub
                ->setHtmlAttribute('data-depends', $category->getHtmlName())
                ->setItems($category->getValue() ? $this->listManager->getSubcategories($category->getValue()) : []);
        };

Již to plně funguje, uvádím to sem jen pro případ, kdyby někdy někdo řešil něco podobného ;-)

Díky za cenné rady.