contributte / forms-multiplier

:repeat: Form multiplier & replicator for Nette Framework

Home Page:https://contributte.org/packages/contributte/forms-multiplier.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to iterate containers after default values?

BigOHenry opened this issue · comments

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

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

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.

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

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?

Try this after update to the latest version

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

};

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()));
 };

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

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);
}

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'],
			]
		);

This is for 2 replicators with each 2 containers:
multiplier

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