How to bind selected radio button value using MVC in view - asp.net-mvc

<div class="row mt-4">
<div class="col-md-12 correct_answer">
<lable>Correct Answer</lable><br /><br />
<label class="radio-label">
#Html.RadioButtonFor(x => x.IsCorrectAnswerOption1, new { #class = "form-control", #type = "radio", id = "IsCorrectAnswerOption1", name = "IsCorrectAnswerOption1"})
<span>A</span>
</label>
<label class="radio-label">
#Html.RadioButtonFor(x => x.IsCorrectAnswerOption2, new { #class = "form-control", #type = "radio", id = "IsCorrectAnswerOption2", name = "IsCorrectAnswerOption2" })
<span>B</span>
</label>
<label class="radio-label">
#Html.RadioButtonFor(x => x.IsCorrectAnswerOption3, new { #class = "form-control", #type = "radio", id = "IsCorrectAnswerOption3", name = "IsCorrectAnswerOption3" })
<span>C</span>
</label>
<label class="radio-label">
#Html.RadioButtonFor(x => x.IsCorrectAnswerOption4, new { #class = "form-control", #type = "radio", id = "IsCorrectAnswerOption4", name = "IsCorrectAnswerOption4" })
<span>D</span>
</label>
<br />
<span id="CorrectAnswerError" class="error">Correct Answer is required</span>
</div>
</div>
Here i have four different radio buttons with different id's and name in that model i have one true value but here i am unable to bind the selected radio value i.e true.

Instead of using boolean variables for each option you can create an enum and give it as a property in a model. In post method you can directly map selected option by the user by
MyOptions Property itself.
Note: Do not change the name attribute of the element.
//Your Model
public class Answer
{
public Options MyOptions { get; set; }
}
public enum Options
{
None,
Option1,
Option2,
Option3,
Option4,
}
//Your Controller
public ActionResult SelectOption()
{
Answer ans = new Answer();
return View(ans);
}
[HttpPost]
public ActionResult SelectOption(Answer answer)
{
var selectedOption = answer.MyOptions;
return View();
}
//Your cshtml page
#model Answer;
#using (Html.BeginForm(FormMethod.Post))
{
#Html.RadioButtonFor(x => x.MyOptions, Options.Option1) <span>Option 1</span>
#Html.RadioButtonFor(x => x.MyOptions, Options.Option2)<span>Option 2</span>
#Html.RadioButtonFor(x => x.MyOptions, Options.Option3)<span>Option 3</span>
#Html.RadioButtonFor(x => x.MyOptions, Options.Option4)<span>Option 4</span>
<button type="submit">Submit</button>
}

Related

Selected Dropdownlist value not being passed to MVC model using Ajax.Beginform

I've used code very similar to what follows elsewhere in my program. It works there. Why, when I click submit, does my selected item in the dropdownlistfor NOT bind to the model?
public class APIDataViewModel
{
public ChangeBuildState ChangeBuildStateValue { get; set; }
public int SelectedIntValue { get; set; }
}
public class ChangeBuildState
{
public Dictionary<int, string> BuildState { get; set; }
public ChangeBuildState()
{
BuildState = new Dictionary<int, string>()
{
{ -1, "Halt"},
{ 4, "Ready"}
};
}
}
#using (Ajax.BeginForm(
"ChangeBuildStateRun",
"Stores",
new
{
Area = "",
locationNumber = Model.locationNumber,
macAddress = Model.mac,
buildState = Model.SelectedIntValue
},
new AjaxOptions
{
UpdateTargetId = "APIModal",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "CloseAddWkstnModals",
OnFailure = "APIFailed"
},
new
{
id = "ChangeBuildStateForm"
}))
{
<div class="row Padding_Std center-block">
<div class="col-sm-7 col-sm-offset-4 col-md-7 col-md-offset-2 Padding_Std">
<label class="ModalInputLblStyle">IP Address: </label>
#Html.EditorFor(m => m.ipaddress,
new
{
htmlAttributes = new
{
#class = "input-sm AddEditWorkstationTBoxStyle",
#readonly = "readonly",
#disabled = "disabled"
}
})
</div>
</div>
<div class="row Padding_Std center-block">
<div class="col-sm-7 col-sm-offset-4 col-md-7 col-md-offset-2 Padding_Std">
<label class="ModalInputLblStyle">MAC Address: </label>
#Html.EditorFor(m => m.mac,
new
{
htmlAttributes = new
{
#class = "input-sm AddEditWorkstationTBoxStyle",
#readonly = "readonly",
#disabled = "disabled"
}
})
</div>
</div>
<div class="row Padding_Std center-block">
<div class="col-sm-7 col-sm-offset-4 col-md-7 col-md-offset-2 Padding_Std">
<label class="storeSearchInputLblStyle">Select Build State: </label>
#Html.DropDownListFor(m => m.SelectedIntValue,
new SelectList(
Model.ChangeBuildStateValue.BuildState,
"Key",
"Value"),
"--- Select ---",
new { #class = "DDL_LogLevelStyle" })
</div>
</div>
<div class="row">
<div class="col-sm-9 col-sm-offset-4">
<div class="col-md-4 col-sm-3 center-block" id="BtnChangeBuildState">
<input type="submit" value="Change Build State" class="btn btn-sm button-alt-1 button-v center-block" />
</div>
...
</div>
}
public ActionResult ChangeBuildStateRun(int locationNumber = 0, string macAddress = "", int buildState = 999)
{
APIDataViewModel model = new APIDataViewModel();
model.locationNumber = locationNumber.ToString();
model.mac = macAddress;
try
{
bool apiCallResult = _epmService.UpdateStoreWorkstationBuildState(locationNumber, macAddress, buildState);
model.webapi_name = "Change Build State";
model.response_type = "ChangeBuild";
model.success = apiCallResult;
return PartialView("_APIResults", model);
}
catch
{
model.webapi_name = "Change Build State";
model.response_type = "ChangeBuild";
model.success = false;
return PartialView("_APIResults", model);
}
}
I haven't included the _APIResults partial view, as buildstate always comes in as 0, when it appears it should come in as -1 or 4 (assuming you change the dropdown to Halt or Ready, which is what I did.

Adding new attributes on RadioButton through MVC model variable

I have MVC class and one of the variables has been declared as:
[UIHint("YesNoRadio")]
[Required(ErrorMessage = "test")]
public bool? Emergency { get; set; }
this creates HTML as
<div class="radio-inline"><label>
<input data-val="true" data-val-required="Test" id="Emergency" name="Emergency" type="radio" value="true">Yes</label>
</div>
<div class="radio-inline"><label>
<input id="Emergency" name="Emergency" type="radio" value="false">No</label>
</div>
what i want is to add new attribute, lets say div-effect = "emergencyExplain" and radio button to come as
<label><input id="Emergency" name="Emergency" type="radio" value="false" div-effect = "emergencyExplain">No</label>
YesNoRadio.cshtml is below:
#model bool?
<div class="radio-inline">
<label>
#if (Model.HasValue && Model.Value)
{
#Html.RadioButtonFor(x => x, "true", new { #checked = "checked" });
}
else
{
#Html.RadioButtonFor(x => x, "true");
}
Yes
</label>
</div>
<div class="radio-inline">
<label>
#if (Model.HasValue && !Model.Value)
{
#Html.RadioButtonFor(x => x, "false", new { #checked = "checked" });
}
else
{
#Html.RadioButtonFor(x => x, "false");
}
No
</label>
</div>
and its called as:
#Html.EditorFor(m => m.Emergency, new { htmlAttributes = new { #class = "form-control" } })
New to MVC form creation so any help in pointing in right direction will be appreciated.
Thanks
Using the [UIHint] attribute just instructs the EditorFor() method to use that template. It does not pass any additional data to the template other that the modell property. You need to use this overload of EditorFor() where you pass the name of the template and an object representing the additionalViewData.
You have no shown the model property that contains the value that you want to add to the data-effect attribute, but assuming its
public string Effect { get; set; }
and you set its value in the GET method before you pass the model to the view, then delete the [UIHint] attribute from the Emergency property and modify the main view to
#Html.EditorFor(m => m.Emergency, "YesNoRadio", new { effect = Model.Effect })
Then change the YesNoRadio.cshtml template to
<div class="radio-inline">
<label>
#Html.RadioButtonFor(x => x, true, new { id = "", div_effect = ViewData["effect"] })
<span>Yes</span>
</label>
<label>
#Html.RadioButtonFor(x => x, false, new { id = "", div_effect = ViewData["effect"] })
<span>No</span>
</label>
</div>
Which will generate
<input data-val="true" data-val-required="Test" div-effect="emergencyExplain" name="Emergency" type="radio" value="True">
A few things to note about your current view code.
Using new { htmlAttributes = new { #class = "form-control" } }
wont do anything when using a custom EditorTemplate - its only
applicable using the built-in templates (how would it know which
element to apply that class to). If you want the class name applied
to the radio buttons, add that in the RadioButtonFor() method in
the template
You do not need to (and should not) set the checked attribute.
That attribute is set by the RadiobuttonFor() method based on the
value of the property (if its null, no buttons will be selected,
and if its true or false then the appropriate button will be
selected
Note also the use of new { id = "" } which removes the id
attribute which would other wise be generating duplicates which is
invalid html

How to update multiple models at the same time in ASP.NET MVC 5 Entity Framework

I am trying to update Two models at the same time.
Models:
Page
Fields
One page has multiple fields, I want them to update at the same time.
public class PageEditViewModel
{
public Page mPage { get; set; }
public IEnumerable<Field> Fields { get; set; }
}
Here is my View:
<div class="row">
<div class="col-md-12">
<h3>Fields</h3>
#foreach (var field in Model.ContentFields)
{
#Html.HiddenFor(m => field.Id)
switch (field.FieldType)
{
case "TextBox":
<div class="form-group">
<label class="control-label">
#field.FieldName<span class="required"> * </span>
</label>
#Html.TextBoxFor(m => field.Content , new { #class = "form-control" })
</div>
break;
case "TextArea":
<div class="form-group">
<label class="control-label">
#field.FieldName<span class="required"> * </span>
</label>
#Html.TextAreaFor(m => field.Content, new { #class = "form-control" })
</div>
break;
case "Image":
<div class="form-group">
<label class="control-label">
#field.FieldName<span class="required"> * </span>
</label>
<input type="file" name="contentImage" id="cImage" class="form-control" accept="image/*" />
</div>
break;
}
}
</div>
</div>
And Controller:
public ActionResult Update(PageEditViewModel viewModel)
{
if (!ModelState.IsValid)
{
var page = _context.MenuPages.Single(s => s.Id == viewModel.mPage.Id);
var contentFields = _context.ContentFields.Where(c => c.MenuPageId == page.Id);
var viewM = new PageEditViewModel
{
DashboardHeading = "Edit a Page",
mPage = page,
ContentFields = contentFields
};
return View("EditPage", viewM);
}
var pageEdit = _context.MenuPages.SingleOrDefault(p => p.Id == viewModel.mPage.Id);
pageEdit.Name = viewModel.mPage.Name;
pageEdit.IsActive = viewModel.mPage.IsActive;
pageEdit.IsShowInMenu = viewModel.mPage.IsShowInMenu;
// _context.SaveChanges();
foreach (var field in viewModel.ContentFields)
{
var cfield = _context.ContentFields.SingleOrDefault(f => f.Id == field.Id);
cfield.Content = field.Content;
}
_context.SaveChanges();
When I Send the data from View to Controller, I get the data for Pages but Null for the Fields Model (Object Reference not set to an instance...).
I am looking forward to any guide from members here.
Thanks.
I think Umesh answer is correct.
After changing your loop, how are you setting your Html.TextBoxFor, HiddenFor and so on?
It should be:
#Html.HiddenFor(m => m.ContentFields[i].Id)
You need to replace #foreach loop on view
#foreach (var field in Model.ContentFields)
{
By for loop
#for (var i = 0; i < Model.ContentFields.Count; i++)
{
This will bind your list to model, while sending data to controller

MVC parent child kind of model form submit doesn't send child collection to controller

I have a company model and it has employees list model as shown below
public class Company
{
[Required]
[Display(Name = "Company Name")]
public string Name { get; set; }
public List<EmployeeModel> Managers { get; set; }
}
and the Employee model as below
public class EmployeeModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
and my parent view is as shown below
#using (Html.BeginForm("CompanySignupSuccess", "Home", FormMethod.Post, new { #class = "horizontal-form", role = "form", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary("", new { #class = "text-danger" })
<div>
<div class="form-group">
#Html.LabelFor(m => m.Name, new { #class = "control-label" })<span class="required">*</span>
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
</div>
<div class="form-group">
<label for="file">Logo:</label>
<input type="file" name="logo" id="logo" accept=".png,.jpg,.jpeg" />
</div>
<div id="managerList">
<div id="editorRowsManagers">
#foreach (var item in Model.Managers)
{
#Html.Partial("DetailsView", item)
}
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-default pull-right" value="Send" />
</div>
</div>
}
and the partial view shown below
#model yourAssembly.EmployeeModel
<div style="border:1px solid;margin:20px; padding:10px;">
Manager Details:
<div class="form-group">
#Html.LabelFor(m => m.Name, new { #class = "control-label" })
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "control-label" }) <span class="required">*</span>
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Phone, new { #class = "control-label" }) <span class="required">*</span>
#Html.TextBoxFor(m => m.Phone, new { #class = "form-control phoneno" })
</div>
</div>
When I click on submit button, the model that goes to controller does have only Name and Logo properties filled in and the list object(Managers) is null, so I am not sure what is that I am missing here. BTW, I used the list of employees , because I would like add more employees by having a 'Add' button, and the Add button will just render another partial view.
public ActionResult CompanySignupSuccess(Company model)
{
if (ModelState.IsValid)
{
//do some process
}
else
{
ModelState.AddModelError("", "Invalid Data entered.");
}
// If we got this far, something failed, redisplay form
return View("CompanySignup", Model);
}
Can anyone please help me on how to send the child list object along with some properties on parent class when the Submit button is hit.
You cannot use a partial to generate controls for a collection unless you pass the HtmlFieldPrefix (refer this answer for an example). However the correct way to do this is to use an EditorTemplate. Rename your partial to EmployeeModel.cshtml (i.e. to match the name of the class) and move it to the /Views/Shared/EditorTemplates folder (or /Views/YourControllerName/EditorTemplates folder).
Then replace your loop in the view with
#Html.EditorFor(m => m.Managers)
which will correctly generate the necessary name attributes for binding, i.e
<input ... name="Managers[0].Name" />
<input ... name="Managers[1].Name" />
etc (currently all your generating is duplicate name attributes (and duplicate id attributes which is invalid html)

Using a html select box with razor

I have a html selector, and I want to use the selected value for my "model => model.type" in my form. Is there a way to set the value in my #Html.EditorFor(model => model.type) to the value of the selector?
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Bet</legend>
<div class="editor-label">
#Html.LabelFor(model => model.type)
</div>
<div class="editor-field">
<select id ="type">
<option value="Football">Football</option>
<option value="Rugby">Rugby</option>
<option value="Horse Racing">Horse Racing</option>
</select>
#Html.EditorFor(model => model.type)
#Html.ValidationMessageFor(model => model.type)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
You can try with this options:
Model:
public string Type { get; set; }
public IEnumerable<SelectListItem> TypeList
{
get
{
return new List<SelectListItem>
{
new SelectListItem { Text = "Football", Value = "Football"},
new SelectListItem { Text = "Rugby", Value = "Rugby"},
new SelectListItem { Text = "Horse Racing", Value = "Horse Racing"}
};
}
}
HTML (Razor):
#Html.DropDownListFor(model => model.Type, Model.TypeList)
OR
HTML (Razor):
#Html.DropDownListFor(model => model.Type, new SelectList(new string[] {"Football", "Rugby", "Horse Racing"}, Model.Type))
#andresdescalzo's solution (last one) works with a minor change:
#Html.DropDownListFor(model => model.Type, new SelectList(new string[] {"Football", "Rugby", "Horse Racing"}, "Rugby"), htmlAttributes: new { #class = "form-control" })
First: Add a selected item for dropdown list (e.g. "Rugby")
Second: remove last Model.Type and add htmlAttributes
PS: SelectedList open parentheses closed after selected item of list (here is "Rugby")
The solution provided by #andresdescalzo works only when we pass the model from Controller to the view.
public class SomeController : Controller
{
public ActionResult SomeAction()
{
return View(new SomeModelWithIEnumerationsSelectListItem())
}
}
An addition to the existing answers: If you get the exception "object reference not set to an instance of an object" when implementing #andresdescalzo's solution, you either need to:
Return the model that you are working with as #diwas mentioned
Instantiate a model on the razor page so you can call the method. This is helpful if you are using a ViewModel instead of a simple EF model.
The second can be done like this:
#{ var tempModel = new YourNameSpace.Models.YourModel(); }
#Html.DropDownListFor(model => model.Type, tempModel.TypeList, Model.Type))
This is the Razor View
<div class="editor-field col-md-3">
#Html.DropDownListFor(model => model.Servers,
Model.AvailableServers,new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SqlServerName)
</div>
Dynamic DropDown from controller
List<SelectListItem> ServersAvailable = new List<SelectListItem>();
bool IdSelected = false;
ServersAvailable.Add(new SelectListItem { Text = "......Select your server name......", Value = "" });
for (int i = 0; i < dt.Rows.Count; i++)
{
ServersAvailable.Add(new SelectListItem
{
Text = dt.Rows[i].ItemArray[0].ToString(),
Value = dt.Rows[i].ItemArray[0].ToString(),
Selected = IdSelected
});
}

Resources