Hi,
I am using the wonderful Uniform plugin from @mzur on a new site. On a page, an editor can add any number of instances of the same form. Currently when there is an error the error is displayed on all instances of the form, rather than just for the one that is being submitted.
I have found this answer: I have multiple static forms on one page. When one fails the error messages are also displayed for the other forms. Why? - but that assumes I know how many forms are on the page.
Is there a solution for handling an unknown number of instances of the same form on a page? Thanks for any help
IMO,
the principle stays the same: you’re creating forms with unique string ID for a session key.
// Instead of
$contactForm = new Form(/* settings */, 'contact-form');
// You'll do something like
$forms = [];
$formDefinitions = []; // get all required forms from blocks or structure or whatever
foreach($formDefinitions as $instance) {
// instance key is whatever: manually entered by editor, ID of block…
$forms[$instanceKey] = new Form(/* settings */, $instanceKey);
}
Something like that. I haven’t tested it, but it’s basically replacing a two forms in distinct variables with XY forms in an array of forms.
Hi Adam,
Thanks for the pointer, I think I am getting closer. The forms each have an autoid
field, which is also submitted as a hidden field, which is perfect for differentiating between them. I now have this code in my controller:
<?php
use Uniform\Form;
return function ($kirby, $page)
{
$forms = [];
$formDefinitions = $page->keyTasks()->toStructure()->toArray();
foreach($formDefinitions as $instance) {
$instanceKey = $instance['autoid'];
$forms[$instanceKey] = new Form(/* settings */, $instanceKey);
}
if ($kirby->request()->is('POST')) {
$form->emailAction([
'to' => 'some@email.com',
'from' => 'another@email.com',
])
;
}
return compact('form');
};
?>
And this on my form on the page:
<?php if ($form->success()): ?>
<?php else: ?>
<?php snippet('uniform/errors', ['form' => $form]); ?>
<?php endif; ?>
When I load the page I get the error “compact(): Undefined variable: form” triggered by this line in the controller:
return compact('form');
I am not sure what I need to change this to to get it working - I guess I need a change on the page as well, to the part that handles the success message
As the error says, you never defined the $form
variable which you are using in the if
statement and which you trying to return.
The if statement would probably have to go within the foreach loop, $form
should then be $forms[$instanceKey]
. You would then need to return the $forms
array and loop through it in your template.
Thank you! I am getting there, controller now looks like:
<?php
use Uniform\Form;
return function ($kirby, $page)
{
$forms = [];
$formDefinitions = $page->keyTasks()->toStructure()->toArray();
foreach($formDefinitions as $instance) {
$instanceKey = $instance['autoid'];
$forms[$instanceKey] = new Form(/* settings */, $instanceKey);
if ($kirby->request()->is('POST')) {
$forms[$instanceKey]->emailAction([
'to' => 'some@email.com',
'from' => 'another@email.com',
])
;
}
}
return compact('forms');
};
?>
And I have this on my page:
<?php
$taskautoid = $taskautoid->toString();
$form = $forms[$taskautoid];
if ($form->error()):
snippet('uniform/errors', ['form' => $form]);
endif; ?>
Now when I submit a form which doesn’t pass validation, the error is shown on the correct form and nowhere else. Super.
However when I submit a form successfully, I get an error displaying on the next form in the structure. I am really not sure how that is happening!
Can you share the entire code? It’s pretty hard to judge otherwise.
My quick guess would be that you have to not Only ensure that the correct form validation is tripped when it’s wrong, but also that all the other forms are not tripped when one is successfully submitted.
Hi,
Thanks for all your help, I really appreciate it. The current behaviour is:
- When a form doesn’t pass validation, the correct error message is displayed on the correct form
- When a form is successfully submitted, an error message is displayed on the next form in the structure
These are my files:
section.php (controller)
<?php
use Uniform\Form;
return function ($kirby)
{
$forms = [];
$formDefinitions = $page->keyTasks()->toStructure()->toArray();
foreach($formDefinitions as $instance) {
$instanceKey = $instance['autoid'];
$forms[$instanceKey] = new Form([
'filefield' => [
'rules' => [
'file',
'mime' => ['application/pdf','application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
'filesize' => 5000,
],
'message' => [
'Please choose a file.',
'Please choose a PDF or Word document.',
'Please choose a file that is smaller than 5 MB.',
],
],
'information' => [],
'link' => [
'rules' => ['url'],
'message' => 'Please enter a valid url',
],
'taskdetails' => [],
'taskautoid' => [],
'task' => [],
'prefix' => [],
], $instanceKey);
if ($kirby->request()->is('POST')) {
$forms[$instanceKey]
->emailAction([
'to' => 'some@email.com',
'from' => 'another@email.com',
]);
}
}
return compact('forms');
};
?>
submission-form.php (the snippet that the structure uses to display the forms.)
<div>
<form enctype="multipart/form-data" method="POST">
<input type='hidden' name='taskdetails' value='<?= $taskdetails ?>'/>
<input type='hidden' name='taskautoid' value='<?= $taskautoid ?>'/>
<input type='hidden' name='task' value='<?= $task ?>'/>
<?php
// This generates a random number, to be used as part of the prefix to allow multiple uploads of files with the same name
$random = Str::random(6,'alphaNum');
$prefix = $prefix . $random . '-';
?>
<input type='hidden' name='prefix' value='<?= $prefix ?>'/>
<?php echo csrf_field() ?>
<?php if($fileUpload == true): ?>
<div class="mb-4">
<label class="block mb-1 text-blue" for="file">Select file <span class="text-red">*</span></label>
<input id="filefield" name="filefield" type="file" required>
<small class="block">This should be a PDF or Word document, and no larger than 5mb</small>
</div>
<?php endif ?>
<?php if($textBox == true): ?>
<div class="mb-4">
<label class="block mb-1 text-blue" for="information">Information <span class="text-red">*</span></label>
<textarea class="block w-full border-grey-300 rounded-[20px] py-4 px-6" id="information" name="information" rows="3" id="information" name="information" required></textarea>
</div>
<?php endif ?>
<?php if($linkBox == true): ?>
<div class="mb-4">
<label class="block mb-2 text-blue" for="link">Link <span class="text-red">*</span></label>
<input class="block w-full border-grey-300 rounded-[20px] py-4 px-6" id="link" name="link" type="url" placeholder="https://example.com" required>
</div>
<?php endif ?>
<div>
<button class="inline-flex items-center p-2 px-4 font-bold text-white rounded-full bg-blue" type="submit" name="complete" value="complete">Click here when you have completed this task</button>
</div>
</form>
<?php
$taskautoid = $taskautoid->toString();
$form = $forms[$taskautoid];
if ($form->error()): ?>
<div class="max-w-md px-4 py-2 mt-3 mb-6 text-base rounded-md text-red bg-red bg-opacity-10"><?php snippet('uniform/errors', ['form' => $form]); ?></div>
<?php endif; ?>
</div>
For instance currently, if I successfully submit a form with a file upload, the next form in the structure displays the error Please choose a PDF or Word document
Ok so not entirely sure this counts as a solve, but I put in a little if
statement to check the returned form’s autoid against the instance, and only show the error message if it is a match.
Thanks for the help on here, got there in the end!