I have a model (entity class) Newsletter. I pass a list of Newsletter to a View and display the list of Newsletter in a table with each Newsletter across a row. Besides each Newsletter row, there is a checkbox. I will select the Newsletters that I want to send by checking the checkbox and clicking on a send button.
How can I pass the selected Newsletters to the controller?
Thanks.
In your view:
<input type="checkbox" name="newsletterIds" value="<%=newsletter.Id%>"/>
In your target controller:
public ActionResult SendNewsletters(int[] newsletterIds)
{
... do something with the ids...
}
Do something like this in your view:
<%= Html.CheckBox("cbNewColors", true) %><label for="cbNewColors">New colors</label>
in your controller, do something like this:
bool bChecked = form["cbNewColors"].Contains("true");
Simply add a boolean value called Selected to your entity class which, when passed back to the controller, will tell the controller which newsletters were selected in your list.
If you don't want to "pollute" your entity class with client metadata, you could inherit from it and add the selected bool in your derived class.
Alternatively your model can simply contain a separate list that holds references to selected newsletters or some unique identifier with which individual newsletters can later be selected from an original list.
You'll have to do some manual work, since MVC adds hidden fields for each checkbox, and relies on the model binder to deal with the value true,false coming in from the form submission (if the box was checked).
Assuming you have unique IDs available in your views, I'd recommend the following:
Manually create the checkboxes (i.e. don't use the Html helper) with the same name
< input type="checkbox" name="newsletters" value="nl_[id]" id="nl_[id]" />[name]< /label>
Accept a string[] newsletters parameter into your action that handles the post. (You may need to accept a string, and then split it on commas, I don't remember array newslettersArray = newsletters.Split(','); ;)
Convert the string into a list of newsletter IDs doing something like this:
var ids = newsletters.Select(n => int.Parse(n.Substring(2)).ToList();
Related
first question on stack so please be gentle ;). I have a long MVC form that requires the user to be able to click an 'Add Person' button , which would then create a copy of an 'Add Person' partial view , which is then filled in with the Person details. On form submit, the controller would then need to contain the details of each new added person stored as a Person object in the Person[] array I have in my View Model. so for example:
User clicks 'Add Person' button 3 times
3x ' Add Person' partial views are displayed on screen, one after the other
User fills in the 3 listed forms
User submits form
Model submitted to controller contains an array of 3 Person objects, populated with the values the user has entered.
I've got the EditorFor working when displaying a list of template forms for an already populated Array of Person objects, but not sure how I would go about actually inserting a new 'Person' into the model via mouse click. Each new person will need to be given an ID of Guid type.
Sorry if my question is vague.I'm trying not to be. I cant provide sample code for my exact solution as this is for a government project but can whip up an similar example if required. Thank you for your time
This should give you a general idea of how to do it
var partialView = '#Html.Raw(#Html.Partial("Person", new ViewModel()).ToString().Replace("\r\n", String.Empty).Replace("\n", String.Empty).Replace("\r", String.Empty))';
partialView = partialView.replace('id="1"', 'id=ListName_{0}'.format(newId));
$("#persons").append(partialView);
Firstly I create a variable containing the partial view as a string, next we need to change the ids and the rest of the properties so they follow the convention used for lists when data binding in MVC.
It follows the following convention
<input type="text" name="stocks[0].Key" value="MSFT" />
<input type="text" name="stocks[1].Key" value="AAPL" />
See the following for a description
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
Once all ids are correctly created you can post the form as per usual.
You're not going to be able to add a person to the view model from client side code. The view model doesn't exist client side, only server side.
My suggestion is to make sure the partial views are all in the form being submitted and have an array of Person objects as a parameter in the controller action you're posting to. You'll need to make sure you use the correct convention for each name on each input field of each partial view.
So for example the partial view each input field would need to be named like this Person[index].Field. Where index is an integer and Field is the appropriate property from the Person model that this particular input tag represents.
I have a class called "PropertyFeature" which simply contains PropertyFeatureID and Description. It's a proper model created through LINQ to SQL mapped to an SQL Server database table. An example instance/row would be:
PropertyFeatureID: 2
Description: "Swimming Pool"
The number of rows (PropertyFeatures) can of course grow and shrink, and so I want to dynamically render a list of checkboxes so that the user can select any of them.
I can dynamically render the Checkboxes easily enough, with something like:
<%foreach (var Feature in (ViewData["Features"] as IEnumerable<MySolution.Models.PropertyFeature>)) { %>
<%=Html.CheckBox("Features", new { #id = Feature.PropertyFeatureID, #value = Feature.PropertyFeatureID })%><label for="Feature<%=Feature.PropertyFeatureID%>"><%=Feature.Description%></label>
<%}%>
I specify the ID for each checkbox and render the matching label so that the user can intuitively click the label and toggle the checkbox - that works great.
I set the CheckBox's "name" to "Features" so all the checkboxes render with the same name, and the MVC Model Binder piles them into a single collection called "Features" when the form is posted. This works nicely.
Once the form is submitted, I use the checked values and store them, so I need the actual integer values so I know which PropertyFeature is selected, not just a pile of Booleans and field names. So ideally, I want it as an array or a collection that's easy to work with.
I am able to retrieve the selected values from within my Controller method when the button is clicked because I have specified the parameter as int[] Features.
But the problem is that it doesn't maintain state. That is, when I click the submit button and the page reloads (with the form again displayed) I want all of the dynamic checkboxes to retain their checked status (or not). All of the other fields that I've created with Html.DropDownList and Html.TextBox all maintain their states successfully no problems at all on the same page in the same form.
I have spent hours reading all of the other threads and articles on similar issues and there is a lot of talk about using ICollection and IDictionary to bundle things up and include a Boolean value for each item so that it can maintain the checkbox state. But I don't 100% grasp how to use that in the context of my own personal example. I would like to keep the solution really simple and not have to code up pages of new classes just to maintain my checkbox state.
What is the cleanest and proper way to do this?
I got it working after much playing around with the various different approaches.
In the view:
<%string[] PostFeatures = Request.Form.GetValues("Features");%>
<% foreach (var Feature in (ViewData["AllPropertyFeatures"] as
IEnumerable<MySolution.Models.PropertyFeature>))
{ %>
<input type="checkbox" name="Features"
id="Feature<%=Feature.PropertyFeatureID.ToString()%>"
value="<%=Feature.PropertyFeatureID%>"
<%if(PostFeatures!=null)
{
if(PostFeatures.Contains(Feature.PropertyFeatureID.ToString()))
{
Response.Write("checked=\"checked\"");
}
}
%> />
<label for="Feature<%=Feature.PropertyFeatureID%>">
<%=Feature.Description%></label> <%
} %>
In the receiving controller method:
public ActionResult SearchResults(int[] Features)
This method has a number of advantages:
Allows labels to be clicked to toggle the corresponding checkboxes (usability).
Allows the Controller method to receive a super tidy array of ints, which ONLY contains the ints that have been selected - and not a whole other pile of items which were unselected or containing false/null/blank/0 etc.
Retains the checkbox's checked state when the page reloads containing the form, i.e. the user's selection is retained.
No random/stray type=hidden input fields created from the default ASP.Net MVC Html.CheckBox helper - I know it does those for a good reason, but in this instance, I don't require them as I only want to know about which IDs have been selected and for those to be in a single, tidy int[].
No masses of additional server side bloated classes, helpers and other happy mess required to achieve such a simple thing.
I would recommend this approach for anyone wanting the cleanest / bloat-free solution for a dynamic checkbox list where you need the IDs and you just want to get down to business!
The problem is that when you are rendering your list of checkboxes, you aren't setting any of them as selected. You will need to set your int[] Features in ViewData, and then in your foreach loop, check to see if the ID of that Feature is in the array in ViewData.
something like:
<%=Html.CheckBox("Features",
((int[])ViewData["SelectedFeatures"]).Contains(Feature.PropertyFeatureID),
new { #id = Feature.PropertyFeatureID, #value = Feature.PropertyFeatureID })%
although I didn't test it, so it might not be 100%.
I have an Edit action/view for my User object, but only want a few fields to be editable.
I've set up the view to bind to the User object, and am using Html.EditorFor() for the few fields that I want to be editable.
I noticed in my User object on Post:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditUser(Mynamespace.User user)
{ }
that only the fields that I provided .EditorFor() controls for actually have any data.
I tried using Html.Hidden(Model.ID) for one of the fields that i didn't want to be editable, but it is null in the new User object created from model binding.
So, my question- How do I bind where only a couple of the fields should be editable?
Thanks!
It sounds like you probably want to start thinking about using a View Model that is specific to the form/input that you're dealing with. But in the short term, ....
You could bind to a FormCollection parameter instead and copy the values manually, OR...
you can use the TryUpdateModel method to populate this existing user object with the new data.
Here's the documentation for TryUpdateModel:
http://msdn.microsoft.com/en-us/library/dd470756.aspx
It's still possible for malicious users to send phony form-values that map to real properties on your model, so to protect against this (like an employee changing his salary property with a simple form hack) you can introduce an interface that contains the white list properties that you allow.
Here's an example:
public interface IUserEditableFields
{
string Username {get;set;}
string Email {get;set;}
}
//... in the controller action
if(TryUpdateModel<IUserEditableFields>(user)) {
//validation passed
//only Username and Email were editable
}
This is a good resource on how to do this:
http://css.dzone.com/news/aspnet-mvc-think-before-you-bi
Are you using the strongly-type helper for the hidden field or is it exactly like you've typed. If you've got it exactly as typed, then the name of the hidden field is the value of the id, not the name of the property on the model (ID). You might want to change it to:
<%= Html.Hidden( "ID" ) %>
or (if using strongly-typed helpers)
<%= Html.HiddenFor( m => m.ID ) %>
Ben's answer is largely correct, in that a ViewModel might be more appropriate, and short of that, TryUpdateModel can be used. However, I add that in that case, rather than requiring the domain object to implement a new interface, you use the overload TryUpdateModel<T>(T, string[]), which allows you to whitelist the updateable properties in a string array by name.
Hey all, this is a newbie ASP.NET MVC question.
I have a view that has a list of checkboxes and a submit button. On submit it posts to a controller method but I can't figure out how to get the values of the checkboxes. Also, I can't figure out how to get model data that I passed into the view when I'm in the post method, I tried using Html.Hidden but that didn't seem to work.
Here's the code:
http://pastebin.com/m2efe8a94 (View)
http://pastebin.com/m39ebc6b9 (Controller)
Thanks for any input received,
Justin
First thing I noticed is that your hidden fields need to be inside your form. Currently in your view, they are above the BeginForm, so they won't be included in the form submission.
To get the values of the selected check boxes, add an IsOffered parameter to your OfferTrade Action method.
public ActionResult OfferTrade(FormCollection result, List<string> IsOffered)
That parameter will contain a list of the ItemId's for all the checked IsOffered boxes.
The HtmlHelper's CheckBox works differently and I don't like the way it works, so I don't use it.
Making the IsOffered parameter type List<int> should also work if your ItemId field is an integer.
First of all your ItemId and UserId is outside your form:
<%= Html.Hidden("ItemId", Model.ItemIWant.ItemId) %>
<%= Html.Hidden("UserId", Model.ItemIWant.UserId) %>
//...
<% using (Html.BeginForm()) {%>
Secondly you could try to make your Controller action method use "model binding" (if this is also called model binding)
public ActionResult OfferTrade(int ItemId, int UserId, IList<string> IsOfferred)
Edit Just noticed you are not using the HtmlHelper CheckBox so your list will contain only selected items, but a point still:
You might want to look into Phil Haacks post on Model Binding To A List, but there is a small change to this in the RTM version of MVC:
You dont need the ".Index" hidden fields, but then the indexes in the Name fields must be zero-indexed and increasing (by 1).
i have this code in my membership service class (taken from the asp.net-mvc sample app)
public MembershipUserCollection GetUnapprovedUsers()
{
MembershipUserCollection users = Membership.GetAllUsers();
MembershipUserCollection unapprovedUsers = new MembershipUserCollection();
foreach (MembershipUser u in users)
{
if (!u.IsApproved)
{
unapprovedUsers.Add(u);
}
}
return unapprovedUsers;
}
i now need a view to show this list of information and allow someone to approve them which will go back to the controller and set the IsApproved property to true.
Create a view which will generate a form containing label and checkbox for each member of the collection. You need to be able to get from the id of the checkbox to the user.
In the HTTP.POST Action method, iterate through the submitted fields looking for set checkboxes, when you find one set the corresponding user to approved.
Obviously the form can display arbitrary details for each user.
To use the inbuilt control helpers takes a bit more effort because you don't have a fixed size model to work with. To achieve something similar I:
Used a non-strongly typed view
populated ViewData["ids"] with IEnumerable<IdType> (which the view would loop over)
For each entry populated ViewData["field" + id] for each field I was displaying in the entity
In the view looped over the ids using ViewData["ids"] to call the HTML helpers with the id of the field.
(That was V1, in V2 I used model state so I could use the inbuilt validation error display support, but that doesn't really apply if you just want to select users.)
The POST processing was similar, repopulating the id list from the database and the looking up in the passed FormCollection.