Correct way to bind mvc3 launcher to model

I have a view that contains a list of radio exchanges for my site conditions and conditions.

eg.

Yes @Html.RadioButtonFor(model => model.TermsAndConditions, "True") No @Html.RadioButtonFor(model => model.TermsAndConditions, "False", new { Checked = "checked" }) </div> @Html.ValidationStyledMessageFor(model => model.TermsAndConditions) 

Everything is in order if the user fills out the form without any errors, however, if I check the servers and refresh the page, I lose the choice that the user made for the radio exchange, and the selected radio returns to the default false field.

How should I bind a radio object, so if the user selects true, does this value remain even after checking on the server side?

Any suggestions would be great!

+46
asp.net-mvc-3
Apr 24 2018-11-11T00:
source share
5 answers

For a short answer, you need to do three things:

  • Remove new { Checked = "checked" } from the second switch. This hard-coded value will cancel all magic actions.
  • When you return your ViewResult from the controller action, give it an instance of your model class where TermsAndConditions is false. This will provide the false default value that you need so that a false radio book is selected for you.
  • Use true and false as the values ​​for your radio buttons instead of "True" and "False" . This is because your property is of type bool . Strictly speaking, you accidentally selected the correct string representations for true and false , but the value parameter for the RadioButtonFor method is of type object . It is best to pass the actual type you want to compare instead of converting it to a string yourself. More on this below.

Here's what happens in depth:

The frame wants to do all this for you automatically, but you did these first two things wrong, which forces you to struggle with the frame to get the behavior you need.

The RadioButtonFor method calls .ToString() by the value of the property you specified and compares it with the .ToString() value that you passed when creating the switch. If they are equal, then it internally sets isChecked = true and finishes rendering checked="checked" in the HTML. Here's how he decides which switch to choose. It simply compares the value of the switch with the value of the property and checks the one that matches.

You can display switches for almost any property this way, and it will magically work. Lines, ints, and even listings all work! Any object that has a ToString method that returns a string that uniquely represents the value of the object will work. You just need to make sure that you set the value of the switch to a value that your property may have. The easiest way to do this is to simply pass in the value, not a string representation of the value. Let the structure convert it to a string for you.

(Since you managed to pass the correct string representations true and false , these values ​​will work as long as you correct your two actual errors, but it is still wise to pass the actual values, not their strings.)

Your first real mistake was hard coding Checked = "checked" for the "No" switch. This will override what the system is trying to do for you, and the results of this switch are always checked.

Obviously, you want the No switch to be pre-selected, but you must make it compatible with everything above. You need to provide a view of the instance of your model class, where the "Terms of Use" parameter is set to "false" and "bind" it to the switches. Typically, a controller action that responds to an initial GET request for a URL does not display an instance of the model class at all. Typically, you simply return View(); . However, since you want the default value to be selected, you must provide a view for your model instance for which the TermsAndConditions conditions are set to false.

Here are some sources to illustrate all of this:

Some kind of account class that you probably already have. (Model of your kind):

 public class Account { public bool TermsAndConditions { get; set; } //other properties here. } 

Some methods in your controller:

 //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(); } 

The whole 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> } 

BONUS:. You will notice that I have added some extra features to the switches. Instead of just using plain text for radio button labels, I used an HTML label element with a for attribute set to the identifiers of each radio button. This allows users to click on a label to select a radio button instead of clicking on the button itself. This is standard HTML. To do this, I had to set manual identifiers on the switches, otherwise they both will get the same identifier only "TermsAndConditions", which will not work.

+94
Jan 10 2018-12-12T00:
source share

There are several things you need to do here to ensure that user selection is supported after server-side validation.

a) Bind the "checked" property of each radio to your model in the view, for example:

 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) To determine the initial default value at the first view, initialize the model returned to the view in the GET request (in the controller action), for example:

 public ActionResult SomeForm() { return View(new SomeModel { TermsAndConditions = false }); } 

b) Make sure that in the action of your controller [HttpPost] you return the model if the validation fails, for example:

 [HttpPost] public ActionResult SomeForm(SomeModel model) { if (!ModelState.IsValid) return View(model); // Do other stuff here } 

Thus, when the view is displayed in the response after verification is complete, it will have the actual state of the model that was transmitted (thus supporting the user's choice).

+13
Aug 24 2018-11-11T00:
source share

I can’t say since you didn’t show your code, but I suspect that if you refuse to check on the server side, you simply return the raw view. When this fails, you need to populate the view with the model that was submitted, just as if you were returning any other validation errors. Otherwise, you will get the model default values ​​(which will always be false for logical registration).

Maybe you can publish your code on the server side?

+4
Jul 29 '11 at 2:10
source share

Here I propose another more complex example.

  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; } 

Get

  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; } 

Post

  [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 } 

Database

enter image description here

page

enter image description here

+2
Jul 16 '14 at 16:31
source share

I had a similar problem and solved the problem by setting the ViewData value in the controller to track what the user selected.

+1
Jun 14 '11 at 17:52
source share



All Articles