Create form element with validator
Shows how to create a form element with a custom validator.
Note
Optimizely Forms is only supported by MVC-based websites and HTML5-compliant browsers.
Form elements inherit from an ElementBlockBase
class, which is the only type allowed in the form element Content Area. Inherit from ValidatableElementBlockBase
to support custom validator.
By default, you can choose from available form element validators (that inherit ElementValidatorBase
class). If you only need some of these validators, or you have your own validator, you can include or exclude them selectively by using the AvailableValidatorTypesAttribute
attribute. The following element includes only the RequiredValidator
along with its validator. Apply MyCustomValidator
to this element; do not make it available for others.
[ContentType(GUID = "{A4EE6053-3932-4300-8B3B-7BABF9AEAB67}", GroupName = ConstantsFormsUI.FormElementGroup, Order = 2230)]
[AvailableValidatorTypesAttribute(Include = new Type[] {
typeof (RequiredValidator)
})]
public class MyCustomElementBlock: ValidatableElementBlockBase {
public virtual string CustomProperty {
get;
set;
}
///
/// Always use a custom Validator to validate this element (along with builtin Validator RequiredValidator)
/// The custom Validator is not visible to Editor (in EditView), but it still works to validate element value
///
[Display(GroupName = SystemTabNames.Content, Order = -5000)]
public override string Validators {
get {
var customValidator = typeof (MyCustomValidator).FullName;
var validators = this.GetPropertyValue(content => content.Validators);
if (string.IsNullOrEmpty(validators)) {
return customValidator;
} else {
return string.Concat(validators, EPiServer.Forms.Constants.RecordSeparator, customValidator);
}
}
set {
this.SetPropertyValue(content => content.Validators, value);
}
}
}
MyCustomValidator
:
public class MyCustomValidator: ElementValidatorBase {
private Injected<LocalizationService> _localizationService;
protected LocalizationService LocalizationService {
get {
return _localizationService.Service;
}
}
public override bool ? Validate(IElementValidatable targetElement) {
return true;
}
///
/// return false if we don't want to show this specific-validators to Editor. This validators always work programatically for AddressElement.
public override bool AvailableInEditView {
get {
return false;
}
}
///
public override IValidationModel BuildValidationModel(IElementValidatable targetElement) {
var model = base.BuildValidationModel(targetElement);
if (model != null) {
model.Message = this.LocalizationService.GetString("/episerver/forms/validators/elementselfvalidator/unexpectedvalueisnotaccepted");
}
return model;
}
}
Only the RequiredValidator
 appears in edit view; MyCustomValidator
is included transparently.
You must specify a validate handler to validate a form element on the client side. Serverside"s
Fullnameof the
Validatorinstance is used as object key (case-sensitive) to lookup the
Clientsidevalidate function. The
EpiForm` client code calls this function to validate the form element's value before submitting the form.
// extend the EpiForm JavaScript API in ViewMode
$.extend(true, epi.EPiServer.Forms, {
/// extend the Validator to validate Visitor's value in Clientside.
Validators: {
"EPiServer.Forms.Samples.Implementation.Validation.MyCustomValidator": function (fieldName, fieldValue, validatorMetaData) {
// this function is used to validate visitor's data value in ViewMode
if (!condition) {
return {
isValid: false,
message: validatorMetaData.model.message
};
}
return {
isValid: true
};
},
},
})
Element view
The default path of element views is found at modules\\\_protected/EPiServer.Forms/Views/ElementBlocks
, but you can override this by adding custom views in the Views/Shared/ElementBlocks
 folder. If you want a custom view location, you can override the GetDefaultViewLocation
method of CustomViewLocationBase
class:
[ServiceConfiguration(typeof (ICustomViewLocation))]
public class FormsSamplesViewLocation: CustomViewLocationBase {
public virtual string GetDefaultViewLocation() {
var defaultPathToBlockViews = "~" + ModuleHelper.ToResource(this.GetType(), "Views/ElementBlocks");
return defaultPathToBlockViews;
}
}
Form element resources
If a form element needs its resource, it must implement the IElementRequireClientResources
interface. The form element's resource is loaded after the form's resources and external's resources. For example, the DateTime
element requires jQuery datetime to work, but it is not loaded until the element is dragged into the form. For example:
public IEnumerable<Tuple<string, string>> GetExtraResources() {
if (!string.IsNullOrWhiteSpace(Settings.Instance.GoogleMapsApiV3Url)) {
var publicVirtualPath = ModuleHelper.GetPublicVirtualPath(Constants.ModuleName);
var currentPageLanguage = FormsExtensions.GetCurrentPageLanguage();
return new List<Tuple<string, string>>() {
new Tuple<string, string>("script", string.Format(Settings.Instance.GoogleMapsApiV3Url, currentPageLanguage)),
new Tuple<string, string>("script", publicVirtualPath + "/ClientResources/ViewMode/AddressesElementBlock.js")
};
}
return new List<Tuple<string, string>>();
}
Note
The
Constants.ModuleName
comes fromEPiServer.Forms.Samples
namespace. You can replace it with your project namespace.
Customize an element's icon and image
To display a form element's image in the Forms Element gadget, add an image with the same name as the element name inside modules/_protected/EPiServer.Forms.UI/{version}/ClientResources/epi-forms/themes/sleek/images/contenttypes
. If you want a different location for a form element's big icons, you can override the default one (dojo part):
var contentTypeService = dependency.resolve('epi.cms.ContentTypeService'),
self = this;
aspect.around(contentTypeService, '_getImagePathByTypeIdentifier', function (originalFunction) {
return function ( /*String*/ typeIdentifier, /*Array*/ registeredTypes, /*String*/ clientResourcePath) {
var types = self._settings.registeredElementContentTypes;
if (types instanceof Array && types.indexOf(typeIdentifier) >= 0) {
// show the .png as big icon for creating FormElement in the ContentArea
return self._settings.clientResourcePath + '/ClientResources/epi-formssamples/themes/sleek/images/contenttypes/' + typeIdentifier.split('.').pop() + '.png';
}
return originalFunction.apply(contentTypeService, arguments);
};
});
From Optimizely Forms 4.4.2, you can use the ImageUrl
attribute to change the big icon of a form element block like other block types by adding this to the custom element block:
[ImageUrl("~/static/img/thumbnails/CustomTextArea.png")]
For the small icon in the Form Elements gadget, add a class as follows:
.epi-forms-icon.epi-forms-icon--small.epi-forms-mycustomelementblock__icon {
background:url(images/mycustomelemeticon.png) 0px 0px no-repeat
}
For examples of custom form elements, see https://github.com/episerver/EPiServer.Forms.Samples.
Updated 2 months ago