我有一个视图,其中包含我的网站条款和条件的单选按钮列表。
e.g。
Yes
@Html.RadioButtonFor(model => model.TermsAndConditions, "True")
No
@Html.RadioButtonFor(model => model.TermsAndConditions, "False",
new { Checked = "checked" })
</div>
@Html.ValidationStyledMessageFor(model => model.TermsAndConditions)
如果用户完成表单没有任何错误,一切正常,但是如果我进行服务器端验证并刷新页面,则会丢失用户为单选按钮做出的选择,并且选定的无线电将返回到默认的假字段。 / p>
我是如何绑定radiobutton所以如果用户选择为true,即使在服务器端验证之后,该值仍然保留?
任何建议都会很棒!
答案 0 :(得分:95)
简而言之,你需要做三件事:
new { Checked = "checked" }
。这个硬编码的检查值将覆盖所有魔法。true
和false
作为单选按钮的值,而不是"True"
和"False"
。这是因为您的属性属于bool
类型。严格来说,您巧合地为true
和false
选择了正确的字符串表示形式,但RadioButtonFor方法的value参数的类型为object
。最好传递您想要比较的实际类型,而不是自己将其转换为字符串。更多内容如下。以下是深入讨论的内容:
框架希望自动为您完成所有这些操作,但是前两个方面做错了,这使得您必须与框架斗争才能获得所需的行为。
RadioButtonFor方法对您指定的属性值调用.ToString()
,并将其与创建单选按钮时传入的值的.ToString()
进行比较。如果它们相等,则它在内部设置isChecked = true
并最终在HTML中呈现checked="checked"
。这就是它决定检查哪个单选按钮的方法。它只是将单选按钮的值与属性的值进行比较,并检查匹配的值。
你可以通过这种方式为几乎任何属性渲染单选按钮,它会神奇地工作。字符串,整数,甚至枚举类型都有效!任何具有ToString
方法的对象都返回一个唯一表示对象值的字符串。您只需确保将单选按钮的值设置为您的属性可能实际具有的值。最简单的方法是传递值本身,而不是值的字符串表示。让框架将它转换为字符串。
(因为您碰巧传递了true
和false
的正确字符串表示形式,那么只要您修复了两个实际错误,这些值就会起作用,但是仍然可以通过实际值,而不是他们的字符串。)
你的第一个真正的错误是对“No”单选按钮进行硬编码Checked = "checked"
。这将覆盖框架尝试为您做的事情,并导致始终检查此单选按钮。
显然,您希望预先选择“否”单选按钮,但您必须以与上述所有内容兼容的方式执行此操作。您需要为视图提供模型类的实例,其中TermsAndConditions设置为false,并让它“绑定”到单选按钮。通常,响应URL的初始GET请求的控制器操作根本不会向View提供模型类的实例。通常,您只需return View();
。但是,由于您希望选择默认值,因此必须为视图提供将TermsAndConditions设置为false的模型实例。
以下是一些说明所有这些内容的源代码:
您可能已经拥有的某种Account类。 (你的View模型):
public class Account
{
public bool TermsAndConditions { get; set; }
//other properties here.
}
控制器中的一些方法:
//This handles the initial GET request.
public ActionResult CreateAccount()
{
//this default instance will be used to pre-populate the form, making the "No" radio button checked.
var account = new Account
{
TermsAndConditions = false
};
return View( account );
}
//This handles the POST request.
[HttpPost]
public ActionResult CreateAccount( Account account )
{
if ( account.TermsAndConditions )
{
//TODO: Other validation, and create the account.
return RedirectToAction( "Welcome" );
}
else
{
ModelState.AddModelError( "TermsAndConditionsAgreement", "You must agree to the Terms and Conditions." );
return View( account );
}
}
//Something to redirect to.
public ActionResult Welcome()
{
return View();
}
整个视图:
@model Account
@{
ViewBag.Title = "Create Account";
}
@using ( Html.BeginForm() )
{
<div>
<span>Do you agree to the Terms and Conditions?</span>
<br />
@Html.RadioButtonFor( model => model.TermsAndConditions, true, new { id = "TermsAndConditions_true" } )
<label for="TermsAndConditions_true">Yes</label>
<br />
@Html.RadioButtonFor( model => model.TermsAndConditions, false, new { id = "TermsAndConditions_false" } )
<label for="TermsAndConditions_false">No</label>
<br />
@Html.ValidationMessage( "TermsAndConditionsAgreement" )
</div>
<div>
<input id="CreateAccount" type="submit" name="submit" value="Create Account" />
</div>
}
奖励:您会注意到我在单选按钮上添加了一些额外的功能。我使用HTML label
元素而不是仅使用纯文本作为单选按钮标签,并将for
属性设置为每个单选按钮的ID。这使用户可以单击标签来选择单选按钮,而不必单击单选按钮本身。这是标准的HTML。为了实现这个目的,我不得不在单选按钮上设置手动ID,否则它们都会获得相同的ID“条款和条件”,这不会起作用。
答案 1 :(得分:15)
您需要在此处执行一些操作,以确保在服务器端验证后维护用户的选择。
a)将每个无线电的“已检查”属性绑定到视图中的模型,例如:
Yes
@Html.RadioButtonFor(model => model.TermsAndConditions, "True", model.TermsAndConditions == true ? new { Checked = "checked" } : null)
No
@Html.RadioButtonFor(model => model.TermsAndConditions, "False", model.TermsAndConditions == false ? new { Checked = "checked" } : null)
b)要在首次显示视图时定义初始默认值,请在GET请求中(在控制器操作中)初始化返回到视图的模型,例如:
public ActionResult SomeForm()
{
return View(new SomeModel { TermsAndConditions = false });
}
b)在您的[HttpPost]控制器操作中确保在验证失败时返回模型,例如:
[HttpPost]
public ActionResult SomeForm(SomeModel model)
{
if (!ModelState.IsValid)
return View(model);
// Do other stuff here
}
这种方式在验证失败后在响应中呈现视图时,它将具有传入的实际模型状态(从而保持用户的选择)。
答案 2 :(得分:4)
我无法告诉您,因为您没有显示您的代码,但我怀疑如果您在服务器端验证失败,那么您只是返回原始视图。如果失败,则需要使用提交的模型填充视图,就像返回任何其他验证错误一样。否则,您将获得默认模型值(对于注册布尔值,它将始终为false)。
也许您可以发布服务器端代码?
答案 3 :(得分:2)
我在这里提供另一个更复杂的例子。
public enum UserCommunicationOptions
{
IPreferEmailAndSMS = 1,
IPreferEmail = 2,
IPreferSMS = 3
}
<强> HTML 强>
@model UserProfileView
// Some other code
<div class="form-group">
<label class="col-lg-2 control-label">Communication</label>
<div class="col-lg-10">
<div class=" col-xs-">
@if (Model.UserCommunicationOption.ToString() == UserCommunicationOptions.IPreferEmailAndSMS.ToString())
{
@Html.RadioButtonFor(x => x.UserCommunicationOption, (int)UserCommunicationOptions.IPreferEmailAndSMS, new { @checked = "checked" })
}
else
{
@Html.RadioButtonFor(x => x.UserCommunicationOption, (int)UserCommunicationOptions.IPreferEmailAndSMS)
}
<label class=" control-label" for="@Model.UserCommunicationOption">I Prefer Email And SMS</label>
</div>
<div class=" col-xs-">
@if (Model.UserCommunicationOption.ToString() == UserCommunicationOptions.IPreferEmail.ToString())
{
@Html.RadioButtonFor(x => x.UserCommunicationOption, (int)UserCommunicationOptions.IPreferEmail, new { @checked = "checked" })
}
else
{
@Html.RadioButtonFor(x => x.UserCommunicationOption, (int)UserCommunicationOptions.IPreferEmail)
}
<label class=" control-label" for="@Model.UserCommunicationOption">I Prefer Email</label>
</div>
<div class=" col-xs-">
@if (Model.UserCommunicationOption.ToString() == UserCommunicationOptions.IPreferSMS.ToString())
{
@Html.RadioButtonFor(x => x.UserCommunicationOption, (int)UserCommunicationOptions.IPreferSMS, new { @checked = "checked" })
}
else
{
@Html.RadioButtonFor(x => x.UserCommunicationOption, (int)UserCommunicationOptions.IPreferSMS)
}
<label class=" control-label" for="@Model.UserCommunicationOption">@DLMModelEntities.Properties.Resource.IPreferSMS</label>
</div>
</div>
</div>
Model
[Required(ErrorMessageResourceName = "Communications", ErrorMessageResourceType = typeof(Resource))]
[Display(Name = "Communications", ResourceType = typeof(DLMModelEntities.Properties.Resource))]
public UserCommunicationOptions UserCommunicationOption { get; set; }
获取强>
var client = AppModel.Clients.Single(x => x.Id == clientId);
if (Convert.ToBoolean(client.IsEmailMessage) && Convert.ToBoolean(client.IsSMSMessage))
{
model.UserCommunicationOption = UserCommunicationOptions.IPreferEmailAndSMS;
}
else if (Convert.ToBoolean(client.IsEmailMessage))
{
model.UserCommunicationOption = UserCommunicationOptions.IPreferEmail;
}
else if ( Convert.ToBoolean(client.IsSMSMessage))
{
model.UserCommunicationOption = UserCommunicationOptions.IPreferSMS;
}
发表强>
[HttpPost]
public ActionResult MyProfile(UserProfileView model)
{
// Some code
var client = AppModel.Clients.Single(x => x.Id == clientId);
if (model.UserCommunicationOption == UserCommunicationOptions.IPreferEmail)
{
client.IsSMSMessage = false;
client.IsEmailMessage = true;
}
else if (model.UserCommunicationOption == UserCommunicationOptions.IPreferEmailAndSMS)
{
client.IsSMSMessage = true;
client.IsEmailMessage = true;
}
else if (model.UserCommunicationOption == UserCommunicationOptions.IPreferSMS)
{
client.IsSMSMessage = true;
client.IsEmailMessage = false;
}
AppModel.SaveChanges();
//Some code
}
<强>数据库强>
<强>网页强>
答案 4 :(得分:1)
我有类似的问题并通过在控制器中设置ViewData值来跟踪用户选择的内容来解决问题。