Passing model property to checkbox - c#

My model
public class UserVM
{
public string Email { get; set; }
public string Password { get; set; }
//my windows authentication checkbox property
public bool WindowsAuthChk { get; set; }
//my windows autologin checkbox property
public bool AutoLoginChk { get; set; }
}
My view(cshtml)
#model Models.UserVM
#using (Html.BeginForm("Login", "Account", FormMethod.Post, new { id = "signinForm" }))
{
<div class="col-md-12">
#Html.LabelFor(m => m.Email)
</div>
<div class="col-sm-6">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
//my checkbox
<div>#Html.CheckBox("checkWindowsAuth",Model.WindowsAuthChk) #Html.Label("Use windows authentication")</div>
//which is not working, I want to pass my model property WindowsAuthChk to my checkbox above and get the bool value to controller.....I want to know how to pass bool model property to checkbox in #Html.CheckBox
public bool WindowsAuthChk { get; set; }
thanks in advance....

If i am not wrong, you can just use Html.EditorFor(), if the property is a non nullable bool mvc will generate a checkbox for you.
#Html.EditorFor(item => item.BoolProp)
you could also use the Html.CheckboxFor() methode.
#Html.CheckboxFor(item => item.BoolProp)
https://dotnetfiddle.net/8gyGKN

Related

Fill ViewModel collection from multiple fields

I have a form in which user can select which shipping methods they want to support for they product that they are selling, e.g. first class letter, second class letter, parcel, etc. I only give users a collection of possible shipping methods, they declare how much each one will cost, so if someone wants to sell a toaster in a parcel, they will charge less than for a set of dumbbells.
My ProductViewModel:
public int Id { get; set; }
public ICollection<SelectedShippingMethodViewModel> SelectedShippingMethods { get; set; }
And SelectedShippingMethodViewModel:
public class SelectedShippingMethodViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
}
In my form I create a section with possible options like this:
<h3>Add new product</h3>
<hr />
#using (Html.BeginForm("AddNew", "ProductCreator", null, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
<label class="col-sm-2 control-label">Shipping methods</label>
<div class="col-sm-10">
#foreach (ShippingMethod shippingMethod in ViewBag?.ShippingMethods)
{
<div class="row">
<div class="col-md-3">
// I don't know what should be here
#Html.CheckBox("SelectedShippingMethods", false)
#shippingMethod.Name
</div>
<div class="col-md-2">
// I don't know what should be here
#Html.TextBox("SelectedShippingMethods.Price")
</div>
</div>
}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Add product</button>
</div>
</div>
}
I have a database table with every possible shipping method that I acquire like this:
[HttpGet]
public async Task<ActionResult> AddNew()
{
ViewBag.ShippingMethods = await _shippingService.GetAllShippingMethodsAsync();
return View();
}
The problem is if checkbox is selected I have to bind Price and Name for each individual SelectedShippingMethodViewModel and I have no idea how to make it work.
Your view models are incorrect. To allow users to select the shipping methods they want and add a price, that view model needs to be
public class ShippingMethodViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
public bool IsSelected { get; set; } // your checkbox binds to this property
}
and the ProductViewModel should be
public class ProductViewModel
{
public int Id { get; set; }
....
public List<ShippingMethodViewModel> ShippingMethods { get; set; }
}
Then in the GET method, initialize your ProductViewModel and populate the ShippingMethods based on all available ShippingMethods, for example
var shippingMethods = await _shippingService.GetAllShippingMethodsAsync()
ProductViewModel model = new ProductViewModel
{
....
ShippingMethods = shippingMethods.Select(x => new ShippingMethodViewModel
{
Name = x.Name
}).ToList()
};
return View(model);
and in the view, use a for loop or EditorTemplate for typeof ShippingMethodViewModel to correctly generate your form controls
#for (int i = 0; i < Model.ShippingMethods.Count; i++)
{
#Html.LabelFor(m => m.ShippingMethods[i].IsSelected, Model[0].ShippingMethods.Name)
#Html.CheckBoxFor(m => m.ShippingMethods[i].IsSelected)
#Html.LabelFor(m => m.ShippingMethods[i].Price)
#Html.TextBoxFor(m => m.ShippingMethods[i].Price)
#Html.HiddenFor(m => m.ShippingMethods[i].Name) // if you want this to be submitted as well
}
Then in the POST method
public ActionResult AddNew(ProductViewModel model)
{
// Get the selected Shipping Methods and the associated price
var selectedMethods = model.ShippingMethods.Where(x => x.Selected);

Bind multiple values to a single checkbox and post it to controller

Model.cs
A campaign can have multiple images, that's why IEnumerable<int> ImageIdList.
public class Campaign
{
public int Id { get; set; }
public int CreatedBy { get; set; }
public int UpdatedBy { get; set; }
public IEnumerable<int> ImageIdList { get; set; }
}
View.cshtml
I want to download all the images related to a campaign, based on the ImageIdList, that's why I need to post all these ImageIds when a particular Campaign is checked and download button is clicked.
#model Campaign
#{
Layout = "....";
var assets = Model.AssetsInCampaign.ToList();
}
#using (Html.BeginForm("action-method", "controller", FormMethod.Post))
{
<div class="btnSubmit">
<input type="submit" value="Download Asset(s)" />
</div>
#foreach(var i in assets)
{
<div class="s_checkcol">
<input type="checkbox" name="ids" />
#foreach (var imageId in i.Where(c => c.AssetId == doc.FileDataId).SelectMany(c => c.ImageIdList))
{
<input type="hidden" name="ids" value=#(imageId)>
}
</div>
}
}
Controller.cs
public ActionResult DownloadFiles(IEnumerable<int> ids)
{
// code
}
NOTE: Only a part of code(where I'm facing the problem) is provided here. Its a DB first approach and in no way I can alter that (ORDERS).
I tried the above, but all of the ids are posted to the controller no matter how many checkboxes are selected.
Question: How should I bind the IEnumerable<int> ImageIdList property to a checkbox in View.cs and post the data to Controller.cs so that only the ids of selected checkboxes are posted?
This is a nice practice... it will work and Iam working with such a
manner (Iam sure that it will work very well) but one thing you have to be very carefull while coding this, little bit
complicated
Iam taking this effort not only for as an answer to this particular question.
Its for all stackoverflow users. Because i never found the below method anyware in stackoverflow.
I get this method by a long search. You people can use this.
It will help you to avoid for loops to bind the Checkboxlist
Its the best good for re-usability (need a single line (max: 20-25 chars to bind a CheckBoxList in Razor))
CheckBoxListItem.cs
create a New Class CheckBoxListItem //you can use any other names
public class CheckBoxListItem
{
public int ID { get; set; }
public string Display { get; set; }
public bool IsChecked { get; set; }
}
MyModel.cs
This is modelclass
public class MyModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<CheckBoxListItem> ChkList { get; set; }
}
HomeController.cs
This is controller
public ActionResult Index()
{
var model = new MyModel(){
Id = 0,
Name = "Your Name",
ChkList = dbContext.myTable.Select(x => new CheckBoxListItem { ID = x.MyTableFieldID, Display = x.MyTableFieldName, IsChecked = true })
//If you need only int part, then just avoid to bind data on Display field
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyModel myModel) //Your model object on PostAction
{
IEnumerable<CheckBoxListItem> ChkList = myModel.ChkList;
// Here is your answer, You can see all your check box items (both checked and unchecked) in ChkList, it will shows all your checked items are true and non-checked items are false in IsChecked field
}
Here you have to give more patiance
Goto the Folder View>Shared>EditorTemplates and RightClick Add>View... and Create a new View with the same name CheckBoxListItem.cshtml
CheckBoxListItem.cshtml
#model Project.Models.CheckBoxListItem
<div class="">
#Html.HiddenFor(x => x.ID)
<div class="">
#Html.CheckBoxFor(x => x.IsChecked)
</div>
#Html.LabelFor(x => x.IsChecked, Model.Display, new { #class = "" })
</div>
Create your View
Index.cshtml
#model #model Project.Models.MyModel
<div class="form-group">
#Html.LabelFor(model => model.Id, htmlAttributes: new { #class = "" })
<div class="col-md-10">
#Html.EditorFor(model => model.Id, new { htmlAttributes = new { #class = "" } })
#Html.ValidationMessageFor(model => model.Id, "", new { #class = "" })
</div>
</div>
#Html.EditorFor(model => model.ChkList) //This only one line of code is enough to bind a checkBoxList in future
<input type="submit" value="Create" class="" />
You will get all these in your post action

Collection in ViewModel gone after postback

I have the following ViewModel:
public class ActivityReportViewModel
{
public Dictionary<int, List<string>> Periods { get; set; }
public List<Project> Projects { get; set; }
public List<Templates> Templates { get; set; }
public DateTime TimePeriod { get; set; }
}
public class Project
{
public string Customer { get; set; }
public string ProjectNumber { get; set; }
public string ProjectDescription { get; set; }
public bool IsSelected { get; set; }
public int TemplateId { get; set; }
public bool XLSX { get; set; }
public bool PDF { get; set; }
}
I fill this ViewModel in my controller and then send it to my Create view, which works fine and the values of the Projects property are all there. However, when I postback the data to the server, the values are gone. I tried supplying HiddenFields to all properties of each Project to no avail. Here's my relevant view markup:
<div>
#Html.LabelFor(model => model.Projects, htmlAttributes: new { #class = "ms-Label" })
<ul class="ms-List" style="list-style:none;">
#for (int x = 0; x < Model.Projects.Count; x++)
{
<li class="ms-ListItem">
<span class="ms-ListItem-primaryText">#Model.Projects[x].ProjectDescription</span>
<span class="ms-ListItem-secondaryText">#Model.Projects[x].Customer</span>
<span class="ms-ListItem-tertiaryText">#Model.Projects[x].ProjectNumber</span>
#*<div class="ms-ListItem-selectionTarget js-toggleSelection"></div>*#
#Html.HiddenFor(m => Model.Projects[x].IsSelected)
#Html.HiddenFor(m => Model.Projects[x].ProjectDescription)
#Html.HiddenFor(m => Model.Projects[x].Customer)
#Html.HiddenFor(m => Model.Projects[x].ProjectNumber)
#Html.HiddenFor(m => Model.Projects[x].XLSX)
#Html.HiddenFor(m => Model.Projects[x].PDF)
<div class="ms-Dropdown">
<i class="ms-Dropdown-caretDown ms-Icon ms-Icon--caretDown"></i>
#Html.DropDownListFor(m => m.Projects[x].TemplateId, new SelectList(Model.Templates, "Id", "Name"), new { #class = "ms-Dropdown-select" })
</div>
<div class="ms-ChoiceField">
<input id="excel+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-input" value="#Model.Projects[x].XLSX" type="checkbox">
<label for="excel+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-field"><span class="ms-Label is-required">Excel</span></label>
</div>
<div class="ms-ChoiceField">
<input id="pdf+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-input" value="#Model.Projects[x].PDF" type="checkbox">
<label for="pdf+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-field"><span class="ms-Label is-required">PDF</span></label>
</div>
</li>
}
</ul>
<div>
#Html.ValidationMessageFor(model => model.Projects, "", new { #class = "text-danger" })
</div>
</div>
EDIT:
Here's my POST action method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ActivityReportViewModel report)
{
using (AppContainer _db = new AppContainer())
{
if (ModelState.IsValid)
{
_db.SaveChanges();
return RedirectToAction("Index");
}
return PartialView(report);
}
}
The DefaultViewModel Binder uses the HTML attribute name to determine which property to bind back to on the server. I cannot see name attribute specified on your input element. Please specify name attribute on the elements you wish to post back to the server with the property of the view model.
Specifiy name attribute as below. Notice I have added name attribute with value as the property of your view model
<input id="excel+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-input" name="#Model.Projects[x].ProjectNumber" value="#Model.Projects[x].XLSX" type="checkbox">

MVC model not binding on post

Can't figure out what I'm doing wrong. When the form in the view is posted the model properties turn out to be null.
Model
public class RegistrationModel
{
public RegistrationModel()
{
Registration = new REGISTRATION();
AddPayment = true;
}
public REGISTRATION Registration { get; set; }
public bool AddPayment { get; set; }
}
View
#model Client.Models.RegistrationModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(excludePropertyErrors: false)
<div class="form-group">
#Html.DropDownList("SECTION_ID", null, string.Empty, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.DropDownList("STUDENT_ID", null, string.Empty, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.DropDownList("STATUS_ID", null, string.Empty, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.CheckBoxFor(model => model.AddPayment)
</div>
<p>
<input type="submit" class="btn btn-success" value="Create" />
</p>
}
Controller
public ActionResult Create()
{
//code to populate view dropdowns
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(RegistrationModel model)
{
WriteFileLog(_logPath, Newtonsoft.Json.JsonConvert.SerializeObject(model));
}
In the controller's Create action that handles the post model properties are null.
Registration Class (autogenerated by EF from database):
public partial class REGISTRATION
{
public REGISTRATION()
{
this.REGISTRATION_AUDIT = new HashSet<REGISTRATION_AUDIT>();
}
public int ID { get; set; }
public int SECTION_ID { get; set; }
public int STUDENT_ID { get; set; }
public int STATUS_ID { get; set; }
public virtual ICollection<REGISTRATION_AUDIT> REGISTRATION_AUDIT { get; set; }
public virtual SECTION SECTION { get; set; }
public virtual V_REGISTRATION_STATUS V_REGISTRATION_STATUS { get; set; }
public virtual PERSON PERSON { get; set; }
}
I would recommend using the strongly-typed helpers, like so:
#Html.DropDownListFor(m => m.Registration.SECTION_ID, null, string.Empty, new { #class = "form-control" })
Otherwise, you need to adjust the names you're using to
#Html.DropDownList("Registration.SECTION_ID", null, string.Empty, new { #class = "form-control" })
You can probably simplify what you're doing by duplicating the Registration class's members into your view model, replacing the Registration property.
As #StephenMuecke points out, you're missing a few parts from your model/markup. The template for the DropDownList helper you're using is
DropDownListFor(
[model property to bind],
[collection of possible values to bind],
[option label],
[HTML attributes])
Passing null for that second parameter means you have no values to populate the generated <select> element with, and should normally generate an exception.
I'm not a fan of using ViewBag to pass collections into the view, so I'd recommend something like
public class RegistrationModel
{
public RegistrationModel()
{
Registration = new REGISTRATION();
AddPayment = true;
}
public REGISTRATION Registration { get; set; }
public bool AddPayment { get; set; }
public SelectList Sections { get; set; }
public SelectList Students { get; set; }
public SelectList Statuses { get; set; }
}
and then adjust the markup accordingly:
#Html.DropDownListFor(m => m.Registration.SECTION_ID, Model.Sections, string.Empty, new { #class = "form-control" })

HtmlPrefix for Partialview, remove the dot

I created a partial view that should display a list of user with a check box , so i can reuse this partial view in various pages.
The problem is that, i'm not able to have the correct htmlprefix the input generated
(I would like to remove the . of the prefix )
Model:
public class CircleEditViewModel
{
[Key]
public int CircleId { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
public bool IsSystem { get; set; }
public List<SimpleUserListViewModel> Users { get; set; }
public CircleEditViewModel()
{
Users = new List<SimpleUserListViewModel>();
}
}
public class SimpleUserListViewModel
{
public SimpleUserListViewModel()
{
}
public SimpleUserListViewModel(User user)
{
this.UserId = user.UserId;
FullName = user.FullName;
}
public int UserId { get; set; }
public byte[] Picture { get; set; }
public string FullName { get; set; }
public bool IsCheckedForAction { get; set; }
}
'Main view':
#model Wims.Website.ViewModels.CircleEditViewModel
<script type="text/javascript">
$(document).ready(function () {
$.validator.unobtrusive.parse('form');
});
</script>
#using (Ajax.BeginForm(Html.ViewContext.RouteData.Values["Action"].ToString(), null, new AjaxOptions { HttpMethod = "POST", OnSuccess = "SaveDone(data)" }, new { id = "editform" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Circle</legend>
#Html.Label(DateTime.Now.ToString());
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</fieldset>
#Html.Partial("~/Views/Shared/_UserList.cshtml", Model.Users,
new ViewDataDictionary(Html.ViewDataContainer.ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "Users" }
})
#Html.GenerateSecureDataControls(model => model.CircleId)
<input type="submit" value="Save" />
}
Partial view:
#model List<Wims.Website.ViewModels.Shared.SimpleUserListViewModel>
#{
if (Model != null)
{
for (int i = 0; i < Model.Count; i++)
{
<div class="userDetail">
<div>
<div>
#Html.CheckBoxFor(model => model[i].IsCheckedForAction)
</div>
<div class="iconDiv">
#Html.Image("~/Content/Images/defaultUser.jpg", Model[i].FullName, null)
</div>
<div>
#Html.TextBoxFor(model => model[i].FullName)
#Html.HiddenFor(model => model[i].UserId)
</div>
</div>
</div>
<div style="clear: both"></div>
}
}
}
I am almost there, the input generated id's are
id="Users.[0].FullName
Is there any way i can remove the first dot?
I've found some solution yesterday on a blog (which i can't find anymore...) but it was for MVC3 and I couldn't make it work anyway...
Thanks for the help!
EDIT:
Maybe I should use EditorFor instead of partial view:
.NET MVC 4 Strongly typed ViewModel containing Strongly typed Model with EditorFor and EditorTemplate partial view not binding
Will check tonight
Alrighty, The EditorFor worked perfectly..
I need to read more about this.

Categories