A short introduction to CustomHtmlForm

Silvercart's is based on a CSS Framework called YAML. We once were so fed up with all those different browser bugs that we decided to use a CSS framework. SilverStripe's form markup did not match YAML's needs, so Sascha decided to create a module that gives full control over the markup plus some JavaScript goodies.

I want to show how CustomHtmlForm works by defining a contact form.

class ContactForm extends CustomHtmlForm {

protected $formFields = array(
'Name' => array(
'type' => 'TextField',
'title' => 'Name',
'checkRequirements' => array(
'isFilledIn' => true,
'hasMinLength' => 3
)
),
'Email' => array(
'type' => 'TextField',
'title' => 'Email address',
'value' => '',
'checkRequirements' => array(
'isFilledIn' => true,
'isEmailAddress' => true
)
),
'Message' => array(
'type' => 'TextareaField',
'title' => 'Message',
'checkRequirements' => array
(
'isFilledIn' => true,
'hasMinLength' => 3
)
)
);

protected $preferences = array(
'submitButtonTitle' => 'submit'
);

protected function fillInFieldValues() {
$member = Member::currentUser();
if ($member) {
$this->formFields['Name']['value'] = $member->Surname;
$this->formFields['Email']['value'] = $member->Email;
}
}

protected function submitSuccess($data, $form, $formData) {

$email = new Email(
'info@silvercart.org',
'rlehmann@pixeltricks.de',
'contact form request',
''
);

$email->setTemplate('MailContact');
$email->populateTemplate(
array(
'Name' => $formData['Name'],
'Email' => $formData['Email'],
'Message' => str_replace('\r\n', '<br>', nl2br($formData['Message']))
)
);

$email->send();
}

}

with the array $formFields all fields are defined. "Name" is the fields identifier, "type" is the silverstripe form field class and "title" is the fields title. With "checkRequirements" You can add some extra field validation. There are 11 different conditions: hasSpecialSigns, isEmailAddress, isCurrency, isDate, isFilledIn, isFilledInDependantOn, isNumbersOnly, hasMinLength, hasLength, mustEqual, mustNotEqual.

With the array $preferences this particular form defines the submit button's title only.

The method "fillInFieldValues()" allows You to fill fields with any attribute or return value. In our case the logged in users data will be filled in to save him some work.

"submitSuccess" is our action method that is called only on successful validation. In addition to SilverStripe action methods the array $formData is passed, which contains the user's input.

Now comes the interesting part: Each form has it's own template. All CustomHtmlForm templates will be saved in themes/[project]/templates/Layout. 

<% if IncludeFormTag %>
<form class="yform" $FormAttributes >
<% end_if %>

$CustomHtmlFormMetadata

<fieldset>
<legend>Kontaktformular</legend>
<div class="subcolumns">
<div class="c50l">
<div class="subcl">
$CustomHtmlFormFieldByName(Name)
</div>
</div>
<div class="c50r">
<div class="subcr">
$CustomHtmlFormFieldByName(Email)
</div>
</div>
</div>
$CustomHtmlFormFieldByName(Message)
</fieldset>

<div class="actionRow">
<div class="type-button">
<% control Actions %>
$Field
<% end_control %>
</div>
</div>
<% if IncludeFormTag %>
</form>
<% end_if %>

The form's markup matches YAML's needs perfectly now. With the template method $CustomHtmlFormFieldByName() all fields can be called with their identifier as a parameter. Forms get a securityID automatically.

Now the new form must be registered in the corresponding controller:

public function init() {
$this->registerCustomHtmlForm('ContactForm', new ContactForm($this));
parent::init();
}

And last but not least the form must be called in the controller's template:

$insertCustomHtmlForm(ContactForm)

I hope this module will useful for You too. We use it in almost all our projects, which means it has some history. Get Your module copy from our bitbucket repository by cloning or downloading it as a .zip. We do have an API-documentation too.

PS:

Please also read the related article about customizing the CustomHtmlForm (thanks to Glen for mentioning this)