Closed mzur closed 5 years ago
There are already news?
Nope. Do you have a specific use case?
Add dynamically family members to an youth hostel apply now form.
Currently I have five fixed fields as workaround.
// family
'familyFirstName-0' => [],
'familyFirstName-1' => [],
'familyFirstName-2' => [],
'familyFirstName-3' => [],
'familyFirstName-4' => [],
'familyLastName-0' => [],
'familyLastName-1' => [],
'familyLastName-2' => [],
'familyLastName-3' => [],
'familyLastName-4' => [],
'familyBirthday-0' => [],
'familyBirthday-1' => [],
'familyBirthday-2' => [],
'familyBirthday-3' => [],
'familyBirthday-4' => [],
'familyGender-0' => [],
'familyGender-1' => [],
'familyGender-2' => [],
'familyGender-3' => [],
'familyGender-4' => [],
'familyBed-0' => [],
'familyBed-1' => [],
'familyBed-2' => [],
'familyBed-3' => [],
'familyBed-4' => [],
Have you looked into array form fields? You can have as many fields as you want e.g. with familyFirstName[]
or familyBed[]
. I haven't had a use case where array form fields couldn't be used instead of something like the wildcard form fields mentioned above, that's why this issue is still dormant.
The problem is to access the old()
and error()
method dynamically. I have found a solution, but this is quite hacky. What do you think?
<?php
$familyFirstName = !empty($formConference->old('familyFirstName')) ? $formConference->old('familyFirstName') : array_fill_keys(range(0, 4), '');
?>
<?php for ($i = 0; $i < 5; $i++): ?>
<div class="form-group" <?php e($formConference->error('familyFirstName'), 'has-error'); ?>>
<label for="familyFirstName-<?= $i; ?>"><?= l::get('firstName', 'firstName'); ?></label>
<input type="text" class="form-control" id="familyFirstName-<?= $i; ?>" name="familyFirstName[]" value="<?= $familyFirstName[$i]; ?>">
<?php snippet('forms/error', ['form' => $formConference, 'field' => 'familyFirstName']) ?>
</div>
<?php endfor; ?>
Also, the mandatory check does not work
'familyFirstName' => [
'rules' => ['required'],
'message' => 'required',
],
Dynamic JavaScript forms are also becoming difficult.
Sorry for answering so late. Here is what you could do:
Implement the form so family members can be added dynamically via JS. The form field names get unique names with incremental IDs just like you've shown.
Extend the controller so it dynamically creates the validation rules array based on the data in the POST request. Something like this:
$rules = [
'roomtype' => [
'rules' => ['required'],
'message' => 'required',
],
'firstName' => [/* ... */],
/* ... */
];
$postData = r::postData();
$familyFirstNames = array_filter($postData, function ($key) {
return str::startsWith($key, 'familyFirstName-');
}, ARRAY_FILTER_USE_KEY);
foreach ($familyFirstNames as $name => $value) {
$rules[$name] = [
'rules' => ['required'],
'message' => 'required',
];
}
$form = new Form($rules);
/* ... */
return compact('form', 'familyFirstNames', /* ... */);
If the form validation failed, you can recreate the dynamically generated form fields by looping over the familyFirstNames
array in the template.
This is definitely a use case that should be made easier with this issue. Unfortunately I'm currently too busy to take care of this.
Instead of implementing this as a new feature, write an example that shows how to dynamically generate the form fields as shown above. This should work for most use cases.
I'm trying use this solution within ajax example, but emails are not sent. Form return success, but email actions not working.
here is my code:
$rules = [
'name' => [
'rules' => ['required'],
'message' => 'Vyplňte, prosím, jméno',
],
'surname' => [
'rules' => ['required'],
'message' => 'Vyplňte, prosím, příjmení',
],
'birth' => [
'rules' => ['required'],
'message' => 'Vyplňte, prosím, rok narození',
],
'phone' => [
'rules' => ['required'],
'message' => 'Vyplňte, prosím, telefon',
],
'email' => [
'rules' => ['required', 'email'],
'message' => 'Vyplňte, prosím, platnou emailovou adresu',
],
'gdpr' => [
'rules' => ['required'],
'message' => 'Musíte souhlasit se zpracováním osobních údajů',
],
];
$people = array_filter($kirby->request()->body()->toArray(), function($key) {
return strpos($key, 'people-') === 0;
}, ARRAY_FILTER_USE_KEY);
foreach ($people as $item => $value) {
$rules[$item] = [];
}
$form = new \Uniform\Form($rules);
// Perform validation and execute guards.
$form->withoutFlashing()->withoutRedirect()->guard();
if (!$form->success()) {
// Return validation errors.
return Response::json($form->errors(), 400);
}
// If validation and guards passed, execute the action.
$form->emailAction([
'to' => 'patrik.illy@gmail.com',
'from' => 'noreply@example.com',
'subject' => 'Registrace na Rodinnou párty na zámku',
'template' => 'zameckaparty-admin',
'replyTo' => $form->data('email'),
])
->emailAction([
'to' => $form->data('email'),
'from' => 'noreply@example.com',
'subject' => 'Registrace na Rodinnou párty na zámku',
'template' => 'zameckaparty-user',
'replyTo' => 'patrik.illy@gmail.com',
]);
if (!$form->success()) {
// This should not happen and is our fault.
return Response::json($form->errors(), 500);
}
// Return code 200 on success.
return Response::json([], 200);
When I comment array_filter
and adding dynamic fields to $rules
, everything working as expected.
Thanks
Bingo! I don't remember why, but $kirby is not available. Solution below working.
$kirby = kirby();
$kirby->impersonate('kirby');
Currently the form does not process form data that is not specified in the constructor array. But there are possible use cases where form fields are added dynamically (via JS), e.g. with a shopping cart. One solution might be allowing wildcard form fields like
item-*
in the constructor array. Another idea is to use array form fields for this.