public function doEventForm($data, Form $form)
{
if ($data['Title'] != 'potato')
{
$form->sessionError('There\'s an error in the form');
}
return $this->redirectBack();
}
Does set the form to invalid but seems to wipe the data. If I take the $form->sessionError() out, the form reloads with data but of course no error.
It was my assumption that after a failed submit the data that was sent should persist.
When building the form I do:
$res = $form->getSessionValidationResult();
if (is_null($res))
{
# First load
if ($this->ExistingID)
{
# Populate the form with existing event (edit or duplicate)
$event = Event::get_by_id('Event', $this->ExistingID);
$form->loadDataFrom($event);
}
}
else if ( ! $res->isValid())
{
# No valid, load from session via Form->restoreFormState()
}
What have I done wrong?
Similar battle with setting a message for a field. In the end I did:
public function doEventForm($data, Form $form)
{
//$validator = $form->getValidator();
if ($data['Title'] != 'potato')
{
$result = ValidationResult::create();
$result->addFieldError('Title', 'that is not potato.');
$form->setSessionValidationResult($result, true);
$form->sessionError('There\'s an error in the form');
}
return $this->redirectBack();
}
@robbieaverill quoted in the issue above from the SS4 changelog:
Removed addErrorMessage(). Use sessionMessage() or sessionError() to add a form level message, throw a ValidationException during submission, or add a custom validator.
@Greg_808 - He is using the same non existent function $Form->addErrorMessage
[Emergency] Uncaught BadMethodCallException: Object->__call(): the method ‘addErrorMessage’ does not exist on 'SilverStripe\Forms\Form
POST /manage/EventForm/
Line 54 in /var/www/html/vendor/silverstripe/framework/src/Core/CustomMethods.php
With the form repopulating I got that to work by manually adding $form->setSessionData($data);.
That uses a slightly different session though than the lesson. FormInfo. versus FormData. from the lesson. Seems odd to have to do that manually though?
I’m still stuck on how to invalidate the form and add a message or CSS class to the error’ed field.
# doEventForm()
if ($data['Title'] != 'spud')
{
$form->sessionMessage('Title is not spud','bad'); # Not sessionError any more
$validator = $form->getValidator();
$validator->validationError('Title', 'Still not spud', 'bad');
return $this->redirectBack();
}
Can you just not do this on submission like I’m trying? Have to sub class every field and wrote a custom validate() method on it? If that’s the case, how would you send data to that fields validate method that is from a different field? For example, the $ID value to tell if it’s an edit or create.
I came across this and below is the approach I took which was to re-create the addErrorMessage that has been removed. Create your own session array of form validation errors and then use setFieldMessage to add error messages to your form when the page is reloaded after validation errors. This is cut down code from a live project:
//Product Enquiry Form
public function ProductEnquiryForm(){
$fields = FieldList::create();
$fields->push(TextField::create('Name', '')
->setAttribute("tabindex", "1")
->setAttribute("placeholder", "Name...")
->setAttribute("class", "form-control")
->setAttribute("autocomplete", "name")
);
$actions = FieldList::create(FormAction::create('doProductFormSubmit', 'Send'));
$form = new Form($this, 'ProductEnquiryForm', $fields, $actions);
//validation messages
$errors = $this->getRequest()->getSession()->get("FormData.{$form->getName()}.errors");
if(!empty($errors)){
foreach($errors as $key => $value ){
$form->setFieldMessage($key, $value, 'error');
}
}
$data = $this->getRequest()->getSession()->get("FormData.{$form->getName()}.data");
return $data ? $form->loadDataFrom($data) : $form;
}
public function doProductFormSubmit($data, $form){
$session = $this->getRequest()->getSession();
//Error Validation
$errors = array();
if(strlen($data['Name']) < 2){
$errors['Name'] = 'Please enter your name.';
}
//add more validation rules....
if(!empty($errors)){
//set errors...
$session->set("FormData.{$form->getName()}.errors", $errors);
$session->set("FormData.{$form->getName()}.data", $data);
return $this->redirectBack();
}
//if all is good then clear session data
$session->clear("FormData.{$form->getName()}.errors");
$session->clear("FormData.{$form->getName()}.data");
//Do rest of your form processing i.e. sending emails etc...
}
Others may have a better way of doing this but it is working for me. Hope it helps…
I can work with that if there’s no other more uhm, “SilverStripe-y” way.
Doesn’t this seem like a bug?
I guess what we’re meant to be doing is creating a custom validator for each field and running it’s validate() method. Less overhead than subclassing the whole Field but still, bit laborious for simple things.
CompositeField doesn’t take a validator though so it wouldn’t get it done anyway.
Ugh. A CompositeField can’t even have a message set on it. Form::setFieldMessage only sets them on fields returned with dataFieldByName. The functions comment " Set message on a given field name. This message will not persist via redirect." doesn’t tell you that.
Any way to set a message on a CompositeField?
Edit: Can set a message on it if you get the field from the FieldList with fieldByName() then setMessage().