I've been trying to find a way to make one of two fields valid and haven't come up with much. Is there a way to do this with custom field validators or is that just relevant to individual fields? The requirement is that one of two fields must be filled in, probably only one, but even if that's not possible, just having at least one filled in (and then there being a default in terms of which is used) would be acceptable, I suppose.
-
Nothing OOTB, but there may be a way to achieve what you are looking for via breaking up your content appropriately into different templates. For example, if you have two datasource templates, you could have different rules for validation. The author picks which template they want to use by selecting compatible renderings. It may help to know more about your specific authoring scenario to help guide you.– Jason St-CyrCommented Jan 7, 2019 at 15:23
2 Answers
I would recommend implementing a custom Item validation rule.
Note: This is different from a field validation, in that it validates the entire item instead of a single field.
1. Create custom validator
Create a new class that implements the Sitecore.Data.Validators.StandardValidator
base class. In the Evaluate()
method, get both fields and check to see if either of them has a value:
public class AtLeastOneFieldPopulatedValidator : StandardValidator
{
public override string Name => "At Least One Field Populated";
public AtLeastOneFieldPopulatedValidator() {}
public AtLeastOneFieldPopulatedValidator(SerializationInfo info, StreamingContext context) : base(info, context) {}
protected override ValidatorResult Evaluate()
{
Item item = base.GetItem();
if (item == null)
{
return ValidatorResult.Valid;
}
if (!string.IsNullOrEmpty(item["Field 1"]) || !string.IsNullOrEmpty(item["Field 2"]))
{
return ValidatorResult.Valid;
}
return base.GetFailedResult(ValidatorResult.CriticalError);
}
protected override ValidatorResult GetMaxValidatorResult()
{
return base.GetFailedResult(ValidatorResult.Error);
}
}
2. Create Validation Rule
item
First, create a new Validation Rule
(template /sitecore/templates/System/Validation/Validation Rule
) item somewhere below this node:
/sitecore/system/Settings/Validation Rules/Item Rules
Important: Make sure you populate the
Type
field with your fully-qualified name of your custom validator's class (e.g.Custom.Services.AtLeastOneFieldPopulatedValidator, Custom.Services
).
3. Associate your Validation Rule
to your items
On the __Standard values
of your item's template, show Standard Fields (View ribbon tab -> Standard fields) and add your Validation Rule
to the appropriate validation fields. I recommend including it in all four.
(Optional) Extra credit: Add parameters
I've not tested this, but I'm sure there's a way to pass parameters using the Parameters
field on the Validation Rule
item. In these parameters, you could pass a list of the fields to check so your validator can be reused by creating multiple Validation Rule
items in Sitecore.
-
did you test this code? It would be great if it works but my understanding is that item["Field 2"] would not have a value at the point the validation for item["Field 1"] fires. This is mentioned in the SSE posts I've referenced in my answer. Commented Jan 7, 2019 at 18:19
-
I believe this will be different, however, because this is an Item validator (not a field validator). I believe it still runs after every field is updated (I haven't dug through the CE JS to verify that), but it validates the entire item instead of just a single field. Commented Jan 7, 2019 at 18:23
-
It also appears this is the same solution they used in the second SSE post you linked: "We additionally put an item validator on the component itself to prevent it from going through workflow." Commented Jan 7, 2019 at 18:25
-
Ahr right, sorry yes it's not a field validator so the values should both be set. No worries then. Commented Jan 7, 2019 at 18:30
-
@AdamSeabridge you point out a valid concern, though, that it was not clear. I've edited the answer to attempt to call that out more clearly. Commented Jan 7, 2019 at 18:34
There is nothing out of the box that will do this for you as far as I am aware and although you think it might be possible custom validation I don't think it is as the a validator works on only one field at a time so updates to the item would only have the updated data for that single field and not the other field. Therefore I think your only option here might be to use the item:saving
event to validate the data there as mentioned by Richard Seal below:
Item validator access already stored data instead of newly inputed data
You need to be careful with this though to make sure it doesn't fire all of the time. Maybe you could check the template before running this validation or something.
Another related thread on SSE is here: Apply field validations across fields
-
Yeah, talking to another developer we already it seems have a custom validator that's doing something via the item:saving event, so I should be able to just tack this additional validation on to it. Thanks for helping me pinpoint the issue and solution. Commented Jan 7, 2019 at 15:27
-
No worries. I come across these kind of scenarios now and again and sometimes you can just handle the display logic in the controller before rendering and through Content Editor education. It would be useful if we could do this more easily with Custom Validators though. Commented Jan 7, 2019 at 15:37