Trying to figure out the best way to handle this.
I need to have logic in where it requires:
1) the Amount if a the color type allows an amount.
2) Credit cards if applicable (only allowed on 1 color at this time).
In the View, I had the required validator however since it applies to the Amount, it shows on ALL amounts, not just the textbox for the radio button selected.
I've tried jQuery to put Required attributes on the fields when clicked but seems like when I set it it applies to every item: Example: $('#TxtColorType_Green').rules("add", "required");
Sample Screen Shot
Example below demos how it would work:
- Red - Allows an amount, but no credit cards
- Green - Allows an amount and Credit card
- Blue - Does not allow amount
MODELS
public class ColorSelected
{
[Required(ErrorMessage = "Color Required")]
[Display(Name = "Color Type:")]
public string ColorTypeId { get; set; }
// [Required(ErrorMessage = "Color Amount Required")] since Radio Button, need to set Required attribute when selected **
[Display(Name = "Color Amount:")]
public decimal? CostAmt { get; set; }
}
public class ColorType
{
Public String ColorTypeId;
Public String ColorTypeShortDesc;
Public String Description;
Public String AmountDescription;
Public String DefaultChoice;
public bool? DefaultChoice { get; set; }
public bool? AllowCreditCard { get; set; }
public ColorType()
{
init();
}
}
public class ColorTypeRed : ColorType
{
public override void init()
{
ColorTypeId = "R";
ColorTypeShortDesc = "Red";
Description = "Red";
AmountDescription = "Pay Later.";
DefaultChoice = true;
}
}
public class ColorTypeGreen : ColorType
{
public override void init()
{
ColorTypeId = "G";
ColorTypeShortDesc = "Gr";
Description = "Green";
AmountDescription = "Pay Now";
AllowCreditCard = true;
}
}
public class ColorTypeBlue : ColorType
{
public override void init()
{
ColorTypeId = "B";
ColorTypeShortDesc = "Bl";
Description = "Blue";
AmountDescription = null;
}
}
ViewModel
public class ColorViewModel
{
public ColorSelected colorSelected;
public List<ColorType> ColorTypes;
public ColorViewModel()
{
ColorTypes.Add(new ColorTypeBlue());
ColorTypes.Add(new ColorTypeRed());
ColorTypes.Add(new ColorTypeGreen());
}
}
View
@model ColorViewModel
<div id="divColorType" class="ec-radiobtnlist">
@{
foreach (var ColorType in Model.ColorTypes)
{
var idVal = string.Format("ColorType_{0}", ColorType.ColorTypeShortDesc);
<div>
<label>
@Html.RadioButtonFor(m => m.ColorSelected.ColorTypeId,
ColorType.ColorTypeId,
new { id = string.Format("Rb{0}", idVal) }
)
<span>@ColorType.Description</span>
</label>
@{
if (ColorType.AmountDescription != null)
{
<text>
@Html.TextBoxFor(m => m.ColorSelected.CostAmt,
new { @id = string.Format("TxtAmt{0}", idVal), @class = "txtAmt", @maxlength = "10", @size = "3" }).00,
@Html.Raw(ColorType.AmountDescription)
@*@Html.ValidationMessageFor(m => m.ColorSelected.CostAmt) Unfortunately right now if put this in the error will occur on ALL Color types as it uses the same property*@
</text>
};
if (ColorType.AllowCreditCard == true)
{
<div id=@string.Format("{0}_PmtCC", idVal)>
@Html.Partial("_CreditCardDetails")
</div>
};
}
</div>
}
}
</div>
Thanks in Advance!
There are multiple reasons why you code will fail, including that your generating multiple textboxes for the same property (
CostAmt
) and theDefaultModelBinder
will only bind the first value (so if you select 'Green', the value of the textbox associated with 'Red' will be bound). In fact nothing will be bound in the POST method because your view model contains only fields, not properties.To have both client and server side validation, you need to use a conditional validation attribute that implements
IClientValidatable
, for example a foolproof[RequiredIf("SelectedColor", "G")]
applied to the properties describing the 'CreditCard', and those properties must also be in the view model. AFAIK, there is nothing out of the box to handle a 'RequiredIf' for multiple values ('Red' or 'Green'), but you can download myRequiredIfContains
attribute from GitHubYour view model should be
Then in the view
Where
hidden
is styled withdisplay: none;
You will then need some javascript to handle the radio buttons
.change()
event to toggle the visibility of the controls based on the value of the selected radio button