Oct 01, 2020
In the previous post, we implemented a client-side comparison conditional validation for two numeric fields using Unobtrusive jQuery Validation. It works well for one-page forms, or when both fields are on the same page. But in multi-page forms, there could be circumstances where a field in a page has to be validated conditionally with the value from a field on another page. In this post, we are going to implement this case using server-side validation.
What do you need?
For this example we are going to use Sitecore 9.1.1 with the same requirements as the previous post.
How to implement?
We are going to use the same two-page form example we used in the previous Sitecore Forms post, including the “Other Number” field we created in the previous post:
Our new validation will be “Another Number must be less than Other Number”. To do this, we have to somehow read the value entered in the first page for the Other Number field. Fortunately, when you submit one page of the form, Sitecore Forms stores the values you entered in session. That means that we are able to read those values on the next page, but in server code. Let’s first create an extension method that will return the value stored in session of a field. We are going to use the Sitecore.ExperienceForms.Mvc.IFormRenderingContext
service to access the stored fields.
FormExtensions.cs
namespace Oshyn.Forms.Samples.Extensions
{
public static class FormExtensions
{
public static string GetPostedFieldValue(this IFormRenderingContext formContext, string itemId)
{
if (!ID.TryParse(itemId, out ID id))
{
return null;
}
var postedField = formContext.GetPostedField(id);
if (postedField == null)
{
return null;
}
//If reading other types of fields, include code here to cast field types and extract values.
return postedField.GetType().GetProperty(“Value”)?.GetValue(postedField, null)?.ToString();
}
}
}
Now let’s create our validation class:
OtherPageConditionalValidation.cs
namespace Oshyn.Forms.Samples.Validations
{
public class OtherPageConditionalValidation : ValidationElement<FieldComparisonParameters>
{
public override IEnumerable<ModelClientValidationRule> ClientValidationRules
{
get
{
yield return new ModelClientValidationRule
{
ErrorMessage = FormatMessage(Title, GetOtherFieldTitle()),
ValidationType = “otherpagecond”
};
}
}
protected virtual string Title { get; set; }
protected virtual string OtherFieldId { get; set; }
protected virtual string Operator { get; set; }
public OtherPageConditionalValidation(ValidationDataModel validationItem) : base(validationItem) { }
public override void Initialize(object validationModel)
{
base.Initialize(validationModel);
Assert.IsNotNullOrEmpty(Parameters?.OtherFieldId, “Other Field ID must be set.”);
Assert.IsNotNullOrEmpty(Parameters?.Operator, “Operator must be set to >, >=, <, <= or =“);
var field = validationModel as TitleFieldViewModel;
Title = field.Title;
OtherFieldId = Parameters?.OtherFieldId;
Operator = Parameters?.Operator;
}
public override ValidationResult Validate(object value)
{
var numericValue = value as double?;
if (numericValue == null || !numericValue.HasValue)
{
return ValidationResult.Success;
}
var formContext = ServiceLocator.ServiceProvider.GetService<IFormRenderingContext>();
var otherFieldValue = formContext.GetPostedFieldValue(OtherFieldId);
if (string.IsNullOrEmpty(otherFieldValue) || !double.TryParse(otherFieldValue, out double otherFieldNumericValue))
{
return ValidationResult.Success;
}
switch (Operator)
{
case “>” when numericValue.Value > otherFieldNumericValue:
case “>=“ when numericValue.Value >= otherFieldNumericValue:
case “<“ when numericValue.Value < otherFieldNumericValue:
case “<=“ when numericValue.Value <= otherFieldNumericValue:
case “=“ when numericValue.Value == otherFieldNumericValue:
return ValidationResult.Success;
}
return new ValidationResult(FormatMessage(Title, GetOtherFieldTitle()));
}
private string GetOtherFieldTitle()
{
var otherFieldItem = Sitecore.Context.Database.GetItem(ID.Parse(OtherFieldId));
if (otherFieldItem == null)
{
return “Other Field”;
}
return !string.IsNullOrWhiteSpace(otherFieldItem[“Title”]) ? otherFieldItem[“Title”] : otherFieldItem.Name;
}
}
}
Let’s analyze this class implementation:
- You’ll notice the declaration of the class is very similar to the one we implemented in the previous post. It reuses FieldComparisonParameters as the parameters class (see the previous post for details on this class).
- The
ClientValidationRules
property’s get is now very simple. It only returns a simpleModelClientValidationRule
with the formatted error message, and a type (make sure this type is not used at all on the client side) - The
Validate()
method now contains the logic of the validation:- It converts the field’s value to double.
- It gets the
IFormRenderingContext
service, and uses the extension method we created previously to extract the value from the other field. - It converts the other field’s value to double.
- The switch block reads the Operator property, and applies the conditional logic with both fields depending on the provided Operator.
- If the condition is not fulfilled, return a ValidationResult containing the formatted message that should be defined in the validation’s Sitecore item.
Build and deploy your code to your Sitecore installation. Enter Sitecore Content Editor, and navigate to /sitecore/System/Settings/Forms/Validations
. Create a new Validation item using template /sitecore/templates/System/Forms/Validation
and fill out the fields:
- Type:
Oshyn.Forms.Samples.Validations.OtherPageConditionalValidation,Oshyn.Forms.Samples
(this is the fully qualified name of the validation class we created, change it to your specific namespaces and assembly name) - Message: “{0} must be less than {1}” (this follows C#
string.Format()
conventions, the first (0) parameter is the title of the field that we will attach this validation, and the second (1) parameter is the title of the other field that we will use to compare) - Parameters: “
{“otherFieldId”:”{other_field_id}”, “operator”:”<“}
”. This is the same JSON we used in the previous blog post forFieldComparisonParameters
, but obviously we need to copy and paste the ID of the “Other Number” field for the “otherFieldId” parameter:
For the “operator” value, we are going to use the less-than operator “<“.
In the end, your Validation item should look something like this:
We must allow this validation to be attached to any “Number” field, so we can select it when we attach it to our field in the form. Navigate to /sitecore/System/Settings/Field Types/Basic/Number
, and in the “Allowed Validations” field, add our new Less Than Validator to the list:
Now it’s time to attach the validation to the “Another Number” field. Open the Forms Editor, and select the “Another Number” field in the second page. On the right panel, open the “Validation” section, and select “Less Than Validator”. Click on Apply and save the form:
Publish all created/modified items (or do a full site Smart Publish). Open the form and enter any values on the first page:
Click on Next Page, and purposefully enter in “Another Number” a number greater than the one you entered in “Other Number”. When you try to Submit the form, you will get a validation error message just below the field:
If you enter a value less than what you entered for Other Number, when you click Submit the form will be submitted and you will be shown the Thank You page.
WARNING: This solution only works when fields are located in different pages. It will not work in one-page forms, or when the conditional field is on the same page. This is because server side validations happen BEFORE the field values are saved into session, and this causes inconsistencies. If you need fully server-side validation for fields on the same page, consider including them in a custom Submit Action, with the disadvantage of displaying the validation errors not under the field, but in the form’s validation summary list that appears on top of the form.
Conclusion
Conditional validation is totally possible in Sitecore Forms. Although these examples shown in this series use simple number comparison, you can implement your own conditionals with other types of fields and any rules you require. The disadvantage is that you need to create separate Validation items for each case and set of fields. This also means that you need to train your CMS admins and editors on how to correctly use these validations, since it needs more setup than what is already included out of the box.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.