contributte / forms-multiplier

:repeat: Form multiplier & replicator for Nette Framework
https://contributte.org/packages/contributte/forms-multiplier.html
MIT License
26 stars 21 forks source link

How to iterate containers after default values? #19

Closed BigOHenry closed 6 years ago

BigOHenry commented 6 years ago

Hello, i have one problem. I need to iterate each control of Multiplier and set to label some attributes unique for each input:

foreach ($groups->getContainers() as $container) {
                        foreach ($container->getControls() as $control_name => $control) {
                            // some more logic here
                            $control->getLabelPrototype()->setAttribute('data-html', 'true');
                            $control->getLabelPrototype()->setAttribute('data-toggle', 'tooltip');
                            $control->getLabelPrototype()->setAttribute('data-placement', 'top');
                            $control->getLabelPrototype()->setAttribute('data-delay', '{"show":"1000", "hide":"0"}');
                            $control->getLabelPrototype()->setAttribute('title', $attribute_object->getAttributeInfo()->getFullInfoString());
                        }
                    }

The problem is, after this code Multiplier is broken. It display right, but if i made some changes in form values after form is send, there are no changes at values... The thing what break the Multiplier is this:

foreach ($groups->getContainers() as $container) {

}

Yes, after i set the default values to Multiplier, this empty foreach break the Multiplier.

Any idea how correctly get to label prototyte to set some attributes? Thank you very much

MartkCz commented 6 years ago

Sorry for late response.

Now you can set attributes in factory callback:

function ($container) {
    $ctrl = $container->addText();
    $ctrl->getLabelPrototype()->setAttribute();
}

I'll look at it in a few days

BigOHenry commented 6 years ago

This solution is not for me. I am creating the first empty container after that i prepare default data and set it with: if ($defaultValues) { $groups->setValues($defaultValues); }

So after that i need foreach the created containers and set some info (inserted at & by/updated at & by) to title as tooltip.

MartkCz commented 6 years ago

Have you foreach in createComponent function? Can you move it to action or render method or onAnchor presenter event?

I can create event onCreate, it will called for each created container. If advice above doesn't work, please send me full code.

Sorry again for late response, but I don't have much time

BigOHenry commented 6 years ago

Thank you for your answer. Yeah, i have foreach in createComponent (form is a solo component) and have to stay there :(

Here is my code:

// after Multiplier created (all inputs)
if ($defaultValues) {
                    $groups->setValues($defaultValues);

                    // set audit info to recurring attributes

                    foreach ($groups->getContainers() as $container) {
                        foreach ($container->getControls() as $control_name => $control) {
                            if ($control_name != 'recurring_seq' && $control_name != 'multiplier_remover' && $control_name != 'multiplier_creator') {
                                if (strpos($control_name, '__id') === false && strpos($control_name, 'dummy') === false) {
                                    $coordination = $group_controls[$control_name.'__id']->getValue();
                                    $str = explode('x', $coordination);
                                    $attribute_object = $groupObject->getAttributes()[$str[1]];

                                    if (null !== $attribute_object->getAttributeInfo()) {
                                        $control->getLabelPrototype()->setAttribute('data-html', 'true');
                                        $control->getLabelPrototype()->setAttribute('data-toggle', 'tooltip');
                                        $control->getLabelPrototype()->setAttribute('data-placement', 'top');
                                        $control->getLabelPrototype()->setAttribute('data-delay', '{"show":"1000", "hide":"0"}');
                                        $control->getLabelPrototype()->setAttribute('title', $attribute_object->getAttributeInfo()->getFullInfoString());
                                    }
                                }
                            }
                        }
                    }
                }

This code will set the info i need as tooltip, but adding or removing containers with buttons is broken.

The best option seems to me onCreate event. What do you think?

MartkCz commented 6 years ago

Try this after update to the latest version

$multiplier->onCreate[] = function (Container $container) use ($options) {

};
BigOHenry commented 6 years ago

Thank you for quick update. When i try to dump the container in onCreate event i got only empty container (without default values) but right number of containers.

$groups->onCreate[] = function (Nette\Forms\Container $container) use ($groupObject) {
                        Debugger::barDump(iterator_to_array($container->getControls()));
 };
MartkCz commented 6 years ago

Can you try latest update? I didn't test it

BigOHenry commented 6 years ago

Still looks same. Right number of containers but no default values :( Here is example of code:


$groups = $form->addMultiplier($replicator_name, function (Nette\Forms\Container $group) use ($groupObject) {
// added some inputs
}, 0);

if ($groupObject->isEditable()) {
                    $presenter = $this;

                    $groups->addCreateButton('', 1, function (Submitter $submitter) use ($presenter, $groupObject) {
                        $submitter->setHtmlAttribute('class', 'btn-success btn-sm entypo-plus ajax');
                        $submitter->setOption('group', $groupObject->getType());
                        $submitter->onClick[] = function () use ($presenter) {
                            /** @var \Nette\Application\UI\Presenter $presenter */
                            $presenter->redrawControl('headerForm');
                        };
                    });

                    $groups->addRemoveButton('', function (Nette\Forms\Controls\SubmitButton $submitter) use ($presenter, $groupObject) {
                        $submitter->setHtmlAttribute('class','btn-danger btn-sm entypo-minus ajax');
                        $submitter->setOption('group', $groupObject->getType());
                        $submitter->onClick[] = function () use ($presenter) {
                            /** @var \Nette\Application\UI\Presenter $presenter */
                            $presenter->redrawControl('headerForm');
                        };
                    });
                }

if ($defaultValues) {
                    $groups->onCreate[] = function (Nette\Forms\Container $container) use ($groupObject) {
                        Debugger::barDump(iterator_to_array($container->getControls()));
                    };

                    $groups->setValues($defaultValues);
}
MartkCz commented 6 years ago

Try this code:

if ($defaultValues) {
                    $groups->onCreate[] = function (Nette\Forms\Container $container) use ($groupObject) {
                        Debugger::barDump('second');
                    };
                    Debugger::barDump('first');
                    $groups->setValues($defaultValues);
}

Multiplier creates copies only if somebody needs iterate over controls.

My test code was:

        $form['multiplier'] = $multiplier = new Multiplier(function (Nette\Forms\Container $container) {
            $container->addText('name', 'Name');
        }, 0);

        $multiplier->addRemoveButton('Remove');
        $multiplier->addCreateButton('Create', 1, function (Submitter $submitter) {

        });

        $multiplier->onCreate[] = function (Nette\Forms\Container $container) {
            bdump(iterator_to_array($container->getControls()));
        };

        $multiplier->setDefaults(
            [
                ['name' => 'xxx'],
                ['name' => 'wsd'],
            ]
        );
BigOHenry commented 6 years ago

This is for 2 replicators with each 2 containers: multiplier

BigOHenry commented 6 years ago

With last commit it seems to work :) I will try some more implementation and testing. Thank you very much 👍