I have a collection of "permissions". Each permission would have three properties: Id, Name, and HasPermission. So as an example, consider the following object:
public class AccessPerm
{
int PermId {get;set;}
string PermName {get;set}
bool HasPerm {get;set;}
}
public class UserProfile
{
Collection<AccessPerm> UserPerms {get;set;}
}
So I want to use the CheckBoxFor helper to create checkboxes so that one can set the user's permissions. If you check the box, then HasPerm should be true. If you uncheck it, HasPerm should be false. The problem I am having is I don't see a way to bind both the PermId and the HasPerm properties to the checkbox. I used the following code to bind the HasPerm property, but it is not useful because I don't know the PermId.
<%
for(int ix=0; ix< Model.UserProfile.Perms.Count; ix++)
{
Html.CheckBoxFor(model => model.UserProfile.Perms[ix].HasPerm);
}
%>
This code does indeed bind HasPerm, and the value is correct. However, since I don't have the id, I can't do anything with the value. Please advise.
You could include it as hidden field:
<% for(int ix = 0; ix < Model.UserProfile.Perms.Count; ix++) { %>
<%= Html.HiddenFor(model => model.UserProfile.Perms[ix].PermId) %>
<%= Html.CheckBoxFor(model => model.UserProfile.Perms[ix].HasPerm) %>
<% } %>
This way you will get the same list in your POST controller action containing the id and whether it is selected.
You might try building a SelectList object and bind it to checkbox list.
Related
I have a Asp.NET MVC Page which has a model like
namespace Sample.Models
{
public class ContModel
{
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "Code")]
public string Code { get; set; }
[Display(Name = "Customer")]
public string Customer { get; set; }
public List<Order> Orders { get; set;}
}
public class Order
{
public string OrderId;
public string OrderDesc;
}
}
I have successfully bound the model data using this article
https://www.pluralsight.com/guides/asp.net-mvc-getting-default-data-binding-right-for-hierarchical-views
The example given in the article uses
for loop and #Html.TextBoxFor to form the table. Now I want to add\delete rows programatically.
So far all the samples I have referred are inserting rows using jQuery. And all the table rows are formed as a JSON string and passed to the controller using AJAX calls.
Is AJAX the only way to do this?. Is there a proper way to bind the data of newly added rows so that it will automatically passed on form submit using POST ?
Ok, so to start, disclaimer: I haven't tested the below code, it's possibly a little incomplete and might not work out of the box. But the main concepts are all there that I think will get you where you're wanting to go with a little applied thought.
Also, I'm not entirely sure about what happens if the index values of the items being bound to the list during model binding are not in order or are missing (for instance if you have a list of 3 orders and delete a row with index 2, you'll have a list with indexs 1 and 3 being bound, how does it create the list with 2 missing - you'll have to check this yourself.)
If you test it and find there is an issue, then you might have to rethink my quick attempt at storing the counter variable and maybe re-indexing the names of the items in the existing html when a row is deleted. - you can probably do away with the counter variable completely if you used a global variable in your javascript which will keep the value throughout the life of that page, but it's been a while since I've done something like that and while I seem to remember it working I can't say for sure.
Deleting:
With deleting, you need to some how know what is being deleted. There's two ways that quickly come to mind;
You can check in your database once you've got the model in your controller, which items are in your database, vs which aren't in the list, and then remove those missing from the list from the database.
When an item is deleted, you store the OrderId in another hidden input in a comma separated string like "3,25,100", and have that bind to your model as well. That way, when you have the model in your controller, you can just split on the comma, and loop through the array and remove the corresponding orders.
I'm sure there's a number of other ways to do that though.
<table>
<thead>
<tr>
<th></th>
<th>Description</th>
<th><button id="AddOrder">Add Order></button></th>
</tr>
</thead>
<tbody id="tableBody">
#for (int i = 0; i < Model.Orders.Count(); i++)
{
var item = Model.Orders[i];
<tr id="Order-#item.OrderId">
<td>
<button type="button" data-id="#item.OrderId" class="removeOrderBtn"></button>
#* The trick to model binding with a list is the name attribute matching the Property Name on the model and giving it an index as below *#
<input type="hidden" name="Orders[#i].OrderId" value="#item.OrderId" />
</td>
<td>
#item.OrderDesc
<input type="hidden" name="Orders[#i].OrderDesc" value="#item.OrderDesc" id="OrderDesc-#item.OrderId" />
</td>
</tr>
}
</tbody>
</table>
#*Store the value of the last index in this input to keep track of it constantly*#
<input type="hidden" id="count" value="#(Model.Orders.Count()-1)">
<script type="text/javascript">
$("#AddOrder").on('click', function (e) {
//get the counter input and store it because we're going to update the value later.
var counterInput = $("#count");
var counter = counterInput.val();
counter++;
//Assumed your new order description has an id of description.
var description = $("#description").val();
//Again you need to prepare your html so that the model binding will work by forming the name correctly.
var newRow = "<tr><td><input type='hidden' name='Orders[" + counter + "].OrderId' value='0' /></td><td <input type='hidden' name='Orders[" + counter + "].OrderDesc value=" + description +" /></td></tr>";
var tableBody = $("#tableBody");
//Append the new tr to the table body after the other rows (might be a better way to do this with append or something similar).
tableBody[0].innerHTML = tableBody[0].innerHTML + newRow;
//Update the counter stored in the input so that we can keep track of how many items we have in the list to try avoid duplicate numbers
counterInput.val(counter);
});
$(".removeOrderBtn").on('click', function (e) {
var id = e.target.dataset.id;
var tableBody = $("#tableBody");
tableBody.remove("#Order-" + id); // I think this takes a selector.
var counterInput = $("#count");
var counter = counterInput.val();
counter--;
counterInput.val(counter);
});
</script>
Let me know if you have any questions.
try this I hope it works for you
<script src="//jsfiddle.net/mustafaozkaya/nfxz4ep2/18/embed/"></script>
I have a n properties of ShowSeat Class: SeatCol1Status , SeatCol2Status ..., SeatColnStatus
I want list value of this to view, but I don't like
<%= ShowSeats[rowIndex].SeatCol1Status %>
<%= ShowSeats[rowIndex].SeatCol2Status %>
..................
<%= ShowSeats[rowIndex].SeatColnStatus %>
How do generate it with loop in html of webform
You can add an indexed property that you can then loop over (guessing at the return type):
public SeatStatus SeatStatus[int col]
{
get
{
switch(col)
case 1: return SeatCol1Status;
case 2: return SeatCol2Status;
// etc
}
}
But maybe you shouldn't have made "n" specific properties but just a single one, containing a list of "seat statusses" that you can index into (and easily iterate over). And this also adapts easily when not all rows have the same number of seats.
I have the following code in my view:
#foreach (var x in model)
{
<input type="checkbox" name="#x.name" /> #x.name
}
That loop will create about 10 check boxes with each of them having a unique name generated during the runtime. The whole point of this is to make this dynamic without me having to type the values of each name. So when I am trying to check in my controller if each of these check boxes are checked or not, how do I do it? Normally, I would pass a parameter to my controller
public ActionResult MyController(string/bool checkboxName)
and this would work fine if I had one checkbox. However, passing 10 parameters for each check box in the controller sounds insane! What if I add more to x in model later so that I have 20 check boxes?
In the loop you are creating the checkboxes, add them to an ICollection and then iterate over that collection looking for CheckBox.Checked.
I'm certain there is a helper function for that in MVC but I'm traveling and don't quite remember it. Something like this should work, adapt as needed.
Note: This assumes they are all on the same page.
#foreach (var control in this.Controls)
{
if (control is CheckBox)
{
if (((CheckBox)control).Checked)
{
//record as you need
}
}
}
I think one of the ways to do this, which might not be ideal but can still work is to use the FormCollection in the MVC framework since you are using a loop, you can loop the elements in your action
/// your view side
#foreach (var x in model)
{
<input type="checkbox" name="#x.name" /> #x.name
}
///The action side
public ActionResult MyController(FormCollection collection, YourModel model)
{
foreach (var x in model)
{
bool IsThisCheked= Convert.ToBoolean(collection[x.name].ToString());
}
}
I think you can pass the whole list of checkboxes to the post controller and then iterate through them like
[HttpPost]
public ActionResult About(List<Requirements> requirements)
{
foreach (var item in requirements)
{
if (item.IsSelected == true)
{
//perform some operation
}
}
List is the list that I passed from view to controller on submitting the form
Now coming to view it can be something like this
#for (int i = 0; i < Model.Requirements.Count; i++)
{
#Html.HiddenFor(m => m.Requirements[i].RId)
#Html.CheckBoxFor(m => m.Requirements[i].IsSelected, new { id = "requirements_" + i, #class = "divider" })
#Html.DisplayFor(m => m.Requirements[i].RName)
}
RId,RName,IsSelected(someproperty to store boolean) are my model properties related to checkboxlist
I only need this one variable in the front end of the page. I am trying to achieve something like this:
<% bool YesNo = Eval("isParent") == "True" ? true : false %>
Data binding doesnt allow me to do this
Does anyone know a way around this?
Thank you for all your answers, Instead of trying to find bool value, I made the If return as text true or false and worked my way around that.(with control properties and css classes)
My Solution
Visible='<%#(string)Eval("isParent") == "True" ? false : true %>'
class="<%#(string)Eval("isParent") == "True" ? "LegendHeader" : "" %>"
the reason I did it this way is because the data is bound to the specific fields, as Vladimir Sachek mentioned, if you do it the way I wanted to you'll have to loop the data and set variable accordingly
use DataBinder.Eval instead and specify the model you are taking the data from
<% bool YesNo = DataBinder.Eval(new{isParent = "True"}, "isParent") == "True" ? true : false; %>
<%= YesNo %>
try
var YesNo = <%= Eval("isParent").ToString() %> == "True"
Try something like
<% bool YesNo(Eval("isParent").toString()) %>
Where YesNo is a method in your code behind. Like following
public bool YesNo(string sIsParent)
{
if(sIsParent.equals("1")){ return true; } else { return false; }
}
Jack said:
it gives me error Databinding methods such as Eval(), XPath(), and
Bind() can only be used in the context of a databound control.
You can use Eval only inside Repeater, GridView and similar controls. This is because Eval
uses the current data item to retrieve the requested property (the 'IsParent')
If i got a list of checkbox in a View, and this list came from Enum (flags). If my checkbox as all the same name, did my controller will update automaticly my Enum (flags) values in my ViewModel with multiple selection ?
Suppose i get in my View
<% foreach (var t in Enum.GetValues(typeof(FoodType)))
{
Response.Write(t.ToString() + " ");
%>
<input type="checkbox" name="TypeOfFood" value="<%:(int)t %>" />
<% }%>
My Controller working like this
public ActionResult Manage(FoodEntity food)
{
}
If i check many check box when i look then FoodType property in my foodEntity, only the value of the first checkbox is selected, but my enum is a flag... what i need, if i want support flag ?
thanks.
Unfortunately no.
It will just grab the first checked value and assign that to your value field.
That would be a pretty cool feature though.
Heres a quick way to get the value you're looking for back into your model:
int newEnumValue = Request.Form["CheckBoxField"].Split(',').Aggregate(0, (acc, v) => acc |= Convert.ToInt32(v), acc => acc);