Well, If you don't want to use javascript
then you have to use custom validator
on asp.net backend
side. Here is the complete steps how you could do this.
Custom Validator Method:
public class RequiredCustom : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var viewModel = (ViewPhoneNumberInput)validationContext.ObjectInstance;
var checkBoxCounter = 0;
foreach (var plan in viewModel.plans)
{
if(plan.IsSelected == true)
{
checkBoxCounter++;
}
if (plan.IsSelected == true && checkBoxCounter >0)
{
return new ValidationResult(ErrorMessage = "You have selected "+ checkBoxCounter + " checkbox!");
}
else
{
return new ValidationResult(ErrorMessage == null ? "Please check one checkbox!" : ErrorMessage);
}
}
return ValidationResult.Success;
}
}
Your Existing Model
public class ViewPhoneNumberInput
{
[Required(ErrorMessage = "You did not enter your phone number! Please enter your phone number!")]
public String PhoneNumber { get; set; }
[RequiredCustom(ErrorMessage = "Please select at least one checkbox")]
public List<Plans> plans { get; set; }
}
Views:
@model ViewPhoneNumberInput
@{ ViewBag.Title = " "; }
<h2>Select Your Plan</h2>
@using (Html.BeginForm("NewCustomerView", "StackOverFlow"))
{
for (int i = 0; i < Model.plans.Count; i++)
{
int counter = 0;
@Html.CheckBoxFor(r => Model.plans[i].IsSelected)
<label> @Model.plans[i].PlanName</label>
@Html.HiddenFor(h => @Model.plans[i].PlanId)
@Html.HiddenFor(h => @Model.plans[i].PlanName)
<br />@Html.ValidationMessageFor(r => Model.plans)<br />
}
<p><strong>Phone Number</strong></p>
@Html.TextBoxFor(r => Model.PhoneNumber)
<p> @Html.ValidationMessageFor(r => Model.PhoneNumber) </p>
<input id="Button" type="submit" value="Next" />
}
Output:

Update:
I would preferably handle this following way:
public class RequiredCustom : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var viewModel = (ViewPhoneNumberInput)validationContext.ObjectInstance;
var checkBoxCounter = 0;
foreach (var plan in viewModel.plans)
{
if(plan.IsSelected == true)
{
checkBoxCounter++;
}
if (plan.IsSelected == true && checkBoxCounter == 1)
{
return new ValidationResult(ErrorMessage = "You have selected checkbox!");
}
else
{
return new ValidationResult(ErrorMessage == null ? "Please check one checkbox!" : ErrorMessage);
}
}
return ValidationResult.Success;
}
}
Note: This is the solution for the exception you were getting System.InvalidCastException: 'Unable to cast object of type 'PlanService.API.Models.ViewPhoneNumberInput' to type 'PlanService.API.Models.Plans
. Because you were passing a list to the validator but previously it was expecting single list. Now its alright.
Now the validator model expecting a list of plans and can act accordingly.
Update Output

Hope it would help you to achieve your goal.