I'm building an MVC app in which the user will have the possibilities of using a lot of filters to get exactly what he wants.
Here's an overview of those filters based on the controller method:
//
// GET: /Card/SearchIndex
public ActionResult SearchIndex(string objName, string objType, string objCostSymbol, string objCost, string powerSymbol,
string powerValue, string ratingSymbol, string ratingValue, string ownerName, string objSet,
string objRarity, string addCostValue, int? objNumber,
string addCostValue2, string addCostValue3, string addCostValue4, string addCostValue5, string addCostValue6,
bool? blueColor, bool? redColor, bool? yellowColor, bool? purpleColor, bool? greyColor, bool? blackColor,
bool? musicColor, bool? allColor)
{
// MORE CODE HERE...
}
I want to know how would be the best way to deal with all these filters, and how could I get a List of objInfo based on the given parameters. Keep in mind that some values may be null. All I've done up to now is load "all" the objInfo I could, then sort them by removing the non-wanted item, which is in my sense "not smart", but I'm new to MVC App and I'm trying to find a better way to do this.
EDIT
Here's the view that generates the data:
#using System.Web.Mvc.Html
#model PagedList.IPagedList<MvcApp.Models.ObjInfo>
#{
ViewBag.Title = "SearchIndex";
}
<h2>Objects Management</h2>
<p>
#Html.ActionLink("Create New Obj", "Create")
#using (Html.BeginForm()){
<p>
<label>
Obj Colors : Check a box to search for a color.
</label>
All: #Html.CheckBox("allColor", true)<br/>
Blue: #Html.CheckBox("blueColor", true)
Red: #Html.CheckBox("redColor", true)
Yellow: #Html.CheckBox("yellowColor", true) <br/>
Purple: #Html.CheckBox("purpleColor", true)
Grey: #Html.CheckBox("greyColor", true)
Black: #Html.CheckBox("blackColor", true)
Music: #Html.CheckBox("musicColor", true)
</p>
<p>
<label>
Obj Values: Select a value in the list below.
</label>
Obj Number: <input type="number" min="0" max="9999" name="cardNumber" value="int" style="width: 70px"/><br/>
Additional Cost (contains): #Html.DropDownList("addCost", String.Empty) + #Html.DropDownList("addCost2", String.Empty)
+ #Html.DropDownList("addCost3", String.Empty) + #Html.DropDownList("addCost4", String.Empty)
+ #Html.DropDownList("addCost5", String.Empty) + #Html.DropDownList("addCost6", String.Empty) <br/>
Cost: #Html.DropDownList("objCostSymbol", "=") #Html.DropDownList("objCost", String.Empty)<br />
Power: #Html.DropDownList("powerSymbol", "=") #Html.DropDownList("powerValue", String.Empty)<br/>
Rating: #Html.DropDownList("ratingSymbol", "=") #Html.DropDownList("ratingValue", String.Empty)<br />
<label>
Obj Text: Write a name, part of a name, or a word.
</label>
Obj Name: #Html.TextBox("objName") <br/>
Owner: #Html.TextBox("ownerName") <br />
<label>
Obj Categories: Select a category in the list below.
</label>
Type: #Html.DropDownList("objType","All") <br/>
Obj Set: #Html.DropDownList("objSet", "All") <br/>
Rarity: #Html.DropDownList("objRarity", "All")<br />
<div class="float-right">
<input type="submit" value="Filter" name="submitbutton">
</div>
</p>
}
</p>
<span style="color:red; font-size: 1.7em; font-style: italic;">#ViewData["ErrorMessage"]</span>
<table>
<tr>
<th>Obj Name</th>
<th>Obj Number</th>
<th>Obj Color</th>
<th>Additional Cost</th>
<th>Cost</th>
<th>Obj Type</th>
<th>#Html.ActionLink("Power", "SearchIndex", new {sortOrder=ViewBag.PowerSortParm})</th>
<th>#Html.ActionLink("Rating", "SearchIndex", new {sortOrder=ViewBag.RatingSortParm})</th>
<th>Rarity</th>
<th>Obj Set Name</th>
<th>Owner Name</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.m_ObjName)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjColor)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjAddCost)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjCost)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjType)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjPower)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjRating)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjRarity)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjSet.m_ObjSetName)
</td>
<td>
#Html.DisplayFor(modelItem => item.m_ObjOwner)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.m_ObjID }) |
#Html.ActionLink("Details", "Details", new { id=item.m_ObjID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.m_ObjID })
</td>
</tr>
}
</table>
<div>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
of #Model.PageCount
#if (Model.HasPreviousPage)
{
#Html.ActionLink("<<", "SearchIndex", new {page = 1, sortOrder = ViewBag.CurrentSort})
#Html.Raw(" ")
#Html.ActionLink("< Prev", "SearchIndex", new {page = Model.PageNumber - 1, sortOrder = ViewBag.CurrentSort})
}
else
{
#:<<
#Html.Raw(" ");
#:< Prev
}
#if (Model.HasNextPage)
{
#Html.ActionLink("Next >", "SearchIndex", new {page = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSort})
#Html.Raw(" ")
#Html.ActionLink(">>", "SearchIndex", new {page = Model.PageCount, sortOrder = ViewBag.CurrentSort})
}
else
{
#:Next >
#Html.Raw(" ")
#:>>
}
</div>
Any advice will help me do a better job, thank you.
Ho do you normally face this in JavaScript ? You would create an option object, like
var op = {
cardName : "..",
cardType : "" ,
...
}
and pass it to a function. Correct ?
The same do in C# too.
Define a, say, Conditions class, like
public class Conditions {
public string CardName {get;set;}
public string CardType {get;set;}
..
}
and pass it to your function, which controls the values of the properties of that type to act accordingly after.
Why do you not use ModelBinder . I think it's very useful with your case. Please see below:
_ I have a Model:
public class Employee
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public Address HomeAddress { get; set; }
}
and ModelBinder for Employee:
public class EmployeeBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
var emp = new Employee {
Id = controllerContext.HttpContext.Request.Form["Id"],
FirstName = controllerContext.HttpContext.Request.Form["FirstName"],
LastName = controllerContext.HttpContext.Request.Form["LastName"],
BirthDate = new DateTime(int.Parse(controllerContext.HttpContext.Request.Form["year"]),
int.Parse(controllerContext.HttpContext.Request.Form["month"]),
int.Parse(controllerContext.HttpContext.Request.Form["day"]))
};
return emp;
}
}
Then Controller:
public ActionResult Example(Employee emp) {
return View(emp);
}
URL: http://localhost:1034/Home/Example?Id=1&LastName=lazycatit
Here's a way you could handle your problem.
First, create a ViewModel with your search parameters.
public class FilterViewModel
{
public string ObjName { get; set; }
public string ObjType { get; set; }
public string OtherType { get; set; }
}
In your controller, pass this to the view.
public virtual ActionResult SearchResults()
{
return View(new FilterViewModel());
}
In your SearchResults.cshtml you need to encode the model to a json and then use an ajax call to filter your results. Assumming there's a button with btnFilterResults id. This is going to load the results from a partial view (that should be your table) using ajax.
<script type="text/javascript">
var dataViewModel = #Html.Raw(Json.Encode(Model));
$("#btnFilterResults").click(function () {
dataViewModel.ObjName = $("#objName").val(); //Make sure the ids corresponde to your html.
dataViewModel.ObjType = $("#objType").val();
dataViewModel.OtherType = $("#otherType").val();
$.ajax({
url: "#Url.Action(MVC.ControllerName.GetSearchResults())",
data: { viewModel: JSON.stringify(dataViewModel) },
success: function(data) {
$("#tableDiv").empty(); //
$("#tableDiv").html(data);
}
});
});
</script>
Finally, in your controller you can get the results:
[HttpGet]
public virtual ActionResult LoadTableReporteGeneral(string viewModel)
{
var filterOptions = JsonConvert.DeserializeObject<FilterViewModel>(viewModel);
var query = from t in db.YourTableName
select t;
//This returns an IQueryable with all of your data, no filtering yet.
//Start filtering.
if(!String.IsNullOrEmpty(filterOptions.ObjName))
{
query = query.Where(x => x.ObjName == filterOptions.ObjName);
}
if(!String.IsNullOrEmpty(filterOptions.ObjType ))
{
query = query.Where(x => x.ObjType == filterOptions.ObjType );
}
//and so on.
//Finally return a partial view with your table.
return PartialView(MVC.Shared.Views._YourTableName, query);
}
Note: I'm using T4MVC and Json.Net packages.
Hope this helps.
Related
How I can solve this error :
Value cannot be null
this is the Model :
public class Orders_Tables
{
// internal IQueryable<object> result { get; set; }
public Lab_Orders LabOrders { get; set; }
public Lab_orders_Cash LabOrdersCash { get; set; }
public Lab_Sample_status LabOrderStatus { get; set; }
public IEnumerable<LAB_RESULTS> LabResults { get; set; }
public IEnumerable<TestsRanges> testsRanges { get; set; }
public IEnumerable<TestsUnits> testUnits { get; set; }
public IEnumerable<LAB_CULTURE_RESULT> LabCultureResults { get; set; }
public IEnumerable<LAB_MICRO_NEGATIVE_RESULT> LabMicroResults { get; set; }
public IEnumerable<LabTests> labtests { get; set; }
public IEnumerable<LAB_RESULTS_CLINIC_VIEW> labClinicsViewResult { get; set; }
public IEnumerable<LAB_RESULT_CASH_VIEW> labCashView { get; set; }
public IEnumerable<LAB_PARASITOLOGY_VIEW> LabParasitologyView { get; set; }
public IEnumerable<LAB_CULTURES_VIEW> LabCulturesView { get; set; }
public IEnumerable<LAB_MICRO_VIEW> LabMicroView { get; set; }
public IEnumerable<LAB_HISTOPATHOLOGY_VIEW> LabHistopathologyView { get; set; }
public IEnumerable<LAB_HISTO_RESULT> LabHistoResult { get; set; }
public IEnumerable<LAB_PARA_RESULTS> LabParaResult { get; set; }
public Lab_Hematology_Samples LabSamples { get; set; }
public IEnumerable<LAB_URINE_ANALYSIS_RESULT> LabUrineResult { get; set; }
public IEnumerable<LAB_URINE_RESULT_VIEW> LaburineView { get; set; }
public Patients patients { get; set; }
public IEnumerable<Customers> customers { get; set; }
}
This is the view I used the Model.order_table :
#model IEnumerable<AljawdahNewSite.Models.Orders_Tables>
#{
ViewBag.Title = "Clinics Orders";
//Layout = "~/Views/Shared/_LayoutPatients.cshtml";
}
<link rel="stylesheet" href=#Url.Content("/Content/bootstrap.min.css")>
<link rel="stylesheet" href=#Url.Content("/Content/style.css")>
<li><img width="500" height="100" style="margin-left:300px" src="~/Contents/images/mamlakaheader.png" /> </li>
<li style="margin-left:1200px">Logout - تسجيل الخروج </span></li>
<li style="margin-left:500px"> #Html.ActionLink("Welcome " + Session["UserFullname"], "Clinicsorders", "Orders") </li>
<h3 style="text-align:center;color:coral;padding:10px;margin-left:500px">Orders List</h3>
<style> a {color: brown;text-decoration: wavy;text-shadow: 20px;font-size:medium;} a:hover {color: blue;}</style>
#using (Html.BeginForm("Clinicsorders", "Orders", FormMethod.Get))
{
<div class="vertical-top">
<span id="FromDate" style="margin-left:60px;color:red;font-size:large"><b>From Date</b></span><input id="FromDatetext" style="margin-left:10px" type="text" name="startdate" />
<span id="ToDate" style="margin-left:95px;color:red;font-size:large"><b>To Date</b></span><input id="ToFatetext" type="text" style="margin:10px" name="enddate" /><br /><br />
<span id="PCfileno" style="color:red;font-size:large"><b>Polyclinic File No</b></span><input id="PCFILENOTEXT" style="margin-left:10px" type="text" name="pcfileno" />
<span id="IDNO" style="color:red;font-size:large;margin-left:30px"><b>ID or Iqama No</b></span><input id="idnotext" type="text" style="margin:10px" name="idno" />
<span id="passport" style="color:red;font-size:large"><b>Passport No</b></span><input id="passporttext" style="margin-left:10px" type="text" name="Passport" />
<span id="mobile" style="color:red;font-size:large;margin-left:30px"><b>Mobile No</b></span><input id="mobiletext" type="text" style="margin:10px" name="Mobile" />
<input id="Submit1" type="submit" value="Search" class="btn btn-dark" />
</div>
}
<table class="table">
<tr>
<td> Patient Name </td>
<td> Order No. </td>
<td> Test Id</td>
<td> order date </td>
<td> Polyclinic File </td>
<td> Order Status </td>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.patients.Patient_Name</td>
<td>#item.LabOrders.ORDER_ID</td>
<!--Here is one-->
<td>#(item.LabCultureResults?.FirstOrDefault()?.TESTID.HasValue ? item.LabCultureResults?.FirstOrDefault()?.TESTID : "No Test ID" )</td>
<td>#item.LabOrders.ORDER_DATE</td>
<td>#item.patients.PCfileNO</td>
<td>#item.LabOrderStatus.status_name</td>
<td>#Html.ActionLink("Result", "MasterDetails", new { id = item.LabOrders.ORDER_ID },new { #class = "btn btn-primary" , target = "_blank" })</td>
<td>#Html.ActionLink("Invoice", "Index", "Invoice", new { id = item.LabOrders.ORDER_ID }, new { #class = "btn btn-primary", target = "_blank" })</td>
#if (item.LabCultureResults?.FirstOrDefault()?.TESTID)
{
<!--Here is two (Do not render if TESTID has not a value)-->
<td>#Html.ActionLink("Culture Result", "download_culture", new { id = item.LabOrders.ORDER_ID, testid = item.LabCultureResults.FirstOrDefault().TESTID }, new { #class = "btn btn-primary", target = "_blank" })</td>
}
#*<td>#Html.ActionLink("Culture Result", "download_culture", new { id = item.LabOrders.ORDER_ID,testid = item.LabCultureResults.FirstOrDefault().TESTID }, new { #class = "btn btn-primary", target = "_blank" })</td>*#
</tr>
}
</table>
The error appeared on this line when I added TESTID
<td>#item.LabCultureResults.FirstOrDefault().TESTID</td>
How to show TESTID if available and skip if null ?
This is the controller code :
public ActionResult Clinicsorders(DateTime? startdate,DateTime? enddate, string pcfileno, string idno , string Passport , string Mobile)
{
int custId = (int)Session["UserCustid"];
// eager load navigation properties
// query is IQueryable
var query = db.Lab_Orders.Where(r => r.CUSTID == custId)
.Join(db.Lab_Sample_status, order => order.order_status, status => status.status_id, (order, status) => new { Order = order, Status = status })
.Join(db.Patients, rec => rec.Order.patient_no, patient => patient.Patient_No, (rec, patient) => new Orders_Tables { LabOrders = rec.Order, LabOrderStatus = rec.Status, patients = patient });
if (startdate.HasValue && enddate.HasValue)
{
query = query.Where(r => DbFunctions.TruncateTime(r.LabOrders.ORDER_DATE) >= DbFunctions.TruncateTime(startdate.Value) &&
DbFunctions.TruncateTime(r.LabOrders.ORDER_DATE) <= DbFunctions.TruncateTime(enddate.Value));
}
if (!string.IsNullOrEmpty(pcfileno))
{
query = query.Where(r => r.patients.PCfileNO == pcfileno);
}
if (!string.IsNullOrEmpty(idno))
{
query = query.Where(r => r.patients.Patient_id == idno);
}
var model = query.OrderByDescending(r=>r.LabOrders.ORDER_ID).ToList();
return View(model);
}
I need to make changes on the controller code and add the table , the orders table class include all the tables in one model together
Sample code demonstrating the problem:
List<string> LabCultureResults = null;
Console.WriteLine(LabCultureResults.Count); // (1)
Console.WriteLine(LabCultureResults.FirstOrDefault()); // (2)
(1) throws the infamous NullReferenceException ("Object reference not set to an instance of an object.").
(2) throws an ArgumentNullException with message "Value cannot be null. (Parameter 'source')", because an extension method (like FirstOrDefault) can be called on a null value, but may decide not to accept it.
So your LabCultureResults is null.
When that Model is the result of an Entity Framework query, you need to .Include(it => it.LabCultureResults).
Be aware that FirstOrDefault() may return a null, so don't just get the TESTID of the result - that will throw a NullReferenceException when the result is null. So use item.LabCultureResults?.FirstOrDefault()?.TESTID.
I catch another issue in your code. You have two accessors in page for TESTID. They marked on code below. You have to handle both accessors. May be your item or LabOrdersis null. If not, the code below can does the job.
If condition depends on its own type.
For example if TESTID is int? you can use this:
item.LabCultureResults?.FirstOrDefault()?.TESTID.HasValue
<table class="table">
<tr>
<td> Patient Name </td>
<td> Order No. </td>
<td> Test Id</td>
<td> order date </td>
<td> Polyclinic File </td>
<td> Order Status </td>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.patients.Patient_Name</td>
<td>#item.LabOrders.ORDER_ID</td>
<!--Here is one-->
<td>#(item.LabCultureResults?.FirstOrDefault()?.TESTID.HasValue ? item.LabCultureResults?.FirstOrDefault()?.TESTID : "No Test ID" )</td>
<td>#item.LabOrders.ORDER_DATE</td>
<td>#item.patients.PCfileNO</td>
<td>#item.LabOrderStatus.status_name</td>
<td>#Html.ActionLink("Result", "MasterDetails", new { id = item.LabOrders.ORDER_ID },new { #class = "btn btn-primary" , target = "_blank" })</td>
<td>#Html.ActionLink("Invoice", "Index", "Invoice", new { id = item.LabOrders.ORDER_ID }, new { #class = "btn btn-primary", target = "_blank" })</td>
#if(item.LabCultureResults?.FirstOrDefault()?.TESTID.HasValue)
{
<!--Here is two (Do not render if TESTID has not a value)-->
<td>#Html.ActionLink("Culture Result", "download_culture", new { id = item.LabOrders.ORDER_ID,testid = item.LabCultureResults.FirstOrDefault().TESTID }, new { #class = "btn btn-primary", target = "_blank" })</td>
}
</tr>
</table>
FirstOrDefault returns....default if it does not exist so dereferencing it will generate a nullreference exception
edit: extra if TESTID does not exist
#item.LabCultureResults.FirstOrDefault().TESTID ?? "EMPTY"
A quick fix is to use the null coalescent operator ( ? )
#item.LabCultureResults.FirstOrDefault()?.TESTID ?? "EMPTY"
OR
#item.LabCultureResults.FirstOrDefault() ?? "EMPTY"
A combination of the above answers:
Try:
#item?.LabCultureResults.FirstOrDefault()?.TESTID ?? ""
I created a page that I can search the store detail via entity framework
I added a column of checkbox in the table.
I would like to keep the checkbox "checked=True" after I submit via the search button.
What would be the recommend way to achieve that ?
I tried following method, but the checkbox get "unchecked" after I click submit
1. https://www.sitepoint.com/quick-tip-persist-checkbox-checked-state-after-page-reload/
View as following :
#using (Html.BeginForm())
{
<p>
Find by name: #Html.TextBox("SearchString")
<input type="submit" name ="StoreIndexButton" value="Search" />
</p>
}
<table class="table" id="displayresult">
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.market)
</td>
<td>
#Html.DisplayFor(modelItem => item.status)
</td>
<td>
#Html.DisplayFor(modelItem => item.oper)
</td>
<td>
#Html.DisplayFor(modelItem => item.operator)
</td>
<td>
#Html.ActionLink("Details", "Details", new { id=item.store1 })
</td>
<td>
#Html.CheckBox("selected",new { value = item.store1, id="selected"+item.store1.ToString() })
</td>
</tr>
}
</table>
Controller as following :
public ActionResult Index(string StoreIndexButton,string searchString)
{
var AR_stores = (from m in db.stores
select m).Take(10);
string[] selectedList = Request.Form.GetValues("selected");
if (!String.IsNullOrEmpty(searchString) && StoreIndexButton =="Search")
{
AR_stores = (from m in db.stores
select m).Where(s => s.name.Contains(searchString));
}
return View(AR_stores);
}
Model as following :
using System;
using System.Collections.Generic;
public partial class store
{
public int store1 { get; set; }
public string name { get; set; }
public string market { get; set; }
public string status { get; set; }
public string oper { get; set; }
public string operator { get; set; }
}
I would on this way :
on partial class add a flag parameter.
public string checkStatus {get; set;}
on default, this will be false and none of choices will be selected.
After submit the function, you have list of selected items and you can set them as selected (checkStatus will be true).
MVC does not have ViewState like ASP.Net WebForms (Not sure viewstate is a feature or drawback). So you have to save the state of the checkbox using a hidden field or a variable. You can try this with jquery and ajax
I need to submit list of skills. when i try to do this submitted model is null. But in Fidler I see that data was send.
public class MvcSkill
{
[HiddenInput(DisplayValue = false)]
public int Id { get; set; }
[Display(Name = "Category Name")]
[StringLength(128, ErrorMessage = "Max length - {0} symbols")]
[Required(ErrorMessage = "Please enter your last name")]
public string Name { get; set; }
public int Level { get; set; }
[Required(ErrorMessage ="Choose skill category")]
public string CategoryName { get; set; }
}
Partial view for each skill (strange input for skill level is bootstrap-star-rating:
#using MvcApp.Infrastructure;
#model MvcApp.ViewModels.MvcSkill
<tr>
<td>
#Html.HiddenFor(x => x.Id)
</td>
<td>
#Html.HiddenFor(x => x.Name)
#Html.DisplayFor(x => x.Name)
</td>
<td>
#Html.HiddenFor(x => x.CategoryName)
#Html.DisplayFor(x => x.CategoryName)
</td>
<td>
<input for="Level" id="#Model.Id" value="#Model.Level" name="Level" type="number" class="rating-loading" data-size="xs" data-min="0" data-max="5" data-step="1" data-show-clear="false">
</td>
#{
var identity = (CustomIdentity)User.Identity;
if (identity.Roles.FirstOrDefault(r => r == "Administrator") != null)
{
<td>
#Html.RouteLink("Edit", new { controller = "Administrator", action = "EditSkill", id = Model.Id })
</td>
<td>
#Html.RouteLink("Remove", new { controller = "Administrator", action = "RemoveSkill", id = Model.Id })
</td>
}
}
</tr>
View for list of skills:
#model IList<MvcApp.ViewModels.MvcSkill>
#{
ViewBag.Title = "Skills";
}
#using (Html.BeginForm("Index","Skill", Model))
{
<table>
#foreach (var s in Model)
{
#Html.Partial("_Skill", s)
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input id="submit" type="submit" value="Update" class="btn btn-default" />
</div>
</div>
}
#section scripts{
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" rel="stylesheet">
<link href="~/Content/star-rating.css" media="all" rel="stylesheet" type="text/css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"></script>
<script src="~/Scripts/star-rating.js" type="text/javascript"></script>
#foreach (var item in Model)
{
string id = item.Id.ToString();
<script>
$(document).on('ready', function () {
$('##id').rating({
step: 1,
defaultCaption: 'Unknown',
starCaptions: { 0: 'Unknown', 1: 'Beginner', 2: 'Elementary', 3: 'Intermediate', 4: 'Advanced', 5: 'Profi' },
starCaptionClasses: function (val) { return 'text-success'; }
}).on('rating.change', function (event, value, caption) {
Model.Skills.FirstOrDefault(s => s.Key.Id.ToString() == id).Value = value;
});
});
</script>
}
}
And controller method:
[HttpPost]
public ActionResult Index(List<MvcSkill> skillModel)
{
//Do something...
return View();
}
Fidler text:
Id=1&Name=c%2B%2B&CategoryName=Programing&Level=5&Id=3&Name=PHP&CategoryName=Programing&Level=3&Id=6&Name=JAVA&CategoryName=Programing&Level=3&Id=7&Name=Name&CategoryName=.Net+Frameworks&Level=5
You have to manually add indexes so MVC framework can successfully bind data. Something like:
#using (Html.BeginForm("Index","Skill", Model))
{
<table>
#for (int i = 0; i < Model.Length; i++)
{
<tr>
<td>
#Html.Hidden("[" + i + "].Id");
</td>
<td>
#Html.DisplayFor(m => Model.ElementAt(i).Name)
#Html.Hidden("[" + i + "].Name");
</td>
<td>
#Html.DisplayFor(m => Model.ElementAt(i).CategoryName)
#Html.Hidden("[" + i + "].CategoryName");
</td>
</tr>
}
</table>
}
Or, as stated in comments you can use BeginCollectionItem (which I personally use). What BeginCollectionItem does is, generally it adds GUIDs as index fro you. Source code can be found here and you can get familiar with it here.
My home controller looks like this
public ActionResult Index()
{
List<District> allDistrict = new List<District>();
List<Tehsil> allTehsil = new List<Tehsil>();
List<SubTehsil> allSubTehsil = new List<SubTehsil>();
using (FarmerBDContext db = new FarmerBDContext())
{
allDistrict = db.Districts.ToList();
}
ViewBag.DistrictId = new SelectList(allDistrict, "DistrictId", "DistrictName");
ViewBag.TehsilId = new SelectList(allTehsil, "TehsilId", "Tehsilname");
ViewBag.SubTehsilId = new SelectList(allSubTehsil, "SubTehsilId", "SubTehsilName");
return View();
}
My District, Tehsil and SubTehsil dropdown are getting populated from another Model class.
District Class
public int DistrictId { get; set; }
public string DistrictName { get; set; }
public virtual ICollection<Tehsil> tbTehsils { get; set; }
My Tehsil And Subtehsil class are similar but have relationships b/w them
This model class is strongly typed to my form Index.cshtml
public string DistrictName { get; set; }
public string TehsilName { get; set; }
public string SubTehsilName { get; set; }
.... // Other Fields
And my Index view is like this
<table>
<tr>
<td class="editor-label Label">
#Html.LabelFor(model => model.DistrictName)
</td>
<td>
#Html.DropDownList("DistrictName", (SelectList)#ViewBag.DistrictId, " -- Select District -- ", new { #class = "ddl"})
</td>
</tr>
<tr>
<td></td>
<td class="editor-field">
#Html.ValidationMessageFor(model => model.DistrictName)
</td>
</tr>
<tr>
<td class="editor-label Label">
#Html.LabelFor(model => model.TehsilName)
</td>
<td>
#Html.DropDownListFor(model => model.TehsilName, #ViewBag.TehsilId as SelectList, "Select Tehsil", new { #class = "ddl" })
</td>
</tr>
<tr>
<td></td>
<td class="editor-field">
#Html.ValidationMessageFor(model => model.TehsilName)
</td>
</tr>
....
</table>
<p>
<input type="submit" value="Details" />
</p>
I am accessing them in another controller like this which is based on my model properties.
ViewBag.DistrictName = model.DistrictName;
ViewBag.TehsilName = model.TehsilName;
ViewBag.SubTehsilName = model.SubTehsilName;
I also tried accessing text of dropdown using the name of dropdownlist
Request.Form["DistrictName"].ToString()
and even used
FormCollection form
One more thing to note is that when i use simple
<select>
<option id=1>Abc</option>
</select>
I am getting the Text which is Abc
Because a <select> tag posts back the value attribute of its selected option. You usage of
ViewBag.DistrictId = new SelectList(allDistrict, "DistrictId", "DistrictName");
means that your generating options which have a value attribute equal to the DistrictId property of District. If you inspect the html your generating you will see (assuming you collection contains new District() { DistrictId = 1, DistrictName = "ABC" }; and new District() { DistrictId = 2, DistrictName = "XYZ" };)
<select name="DistrictName" ...>
<option value="1">ABC</option>
<option value="2">XYZ</option>
</select>
If you want the value of the DistrictName property to be bound to your model, then it needs to be
ViewBag.DistrictId = new SelectList(allDistrict, "DistrictName", "DistrictName");
Alternatively you could do
IEnumerable<string> allDistrict = db.Districts.Select(d => d.DistrictName);
ViewBag.DistrictId = new SelectList(allDistrict); // a more appropriate name might be ViewBag.DistrictList
Side note: html table elements are for tabular data, not layout!
I'm trying to so a simple form to send some data. My form have a list of checkboxes and next to each box, a name and a role of person. What I want to do : recover the list of person that box have been checked.
I've created a model that way to do that :
public class CoupleModel
{
public Boolean isSelected { get; set; }
public String name {get; set;}
public String login { get; set; }
public String role { get; set; }
public CoupleModel(String name, String login, String role)
{
this.name = name;
this.login = login;
this.role = role;
this.isSelected = false;
}
public CoupleModel()
{
this.isSelected = false;
}
}
My form looks like this :
#using (Html.BeginForm("CreateInventory", "Home"))
{
#Html.Action("PersonListInventory")
<button type="submit" class="btn btn-primary">Validate creation</button>
}
And the PartialView linked to it is this one :
#model List<MyApp.Models.CoupleModel>
<table class="table table-striped table-bordered"">
<tbody>
#for (int i = 0; i < Model.Count(); i++) {
<tr>
<td>
#Html.EditorFor(m => m[i].isSelected)
</td>
<td>
#Html.EditorFor(m => m[i].name)
</td>
<td>
#Html.EditorFor(m => m[i].role)
</td>
</tr>
}
</tbody>
</table>
And then, in my controller view, I just want to list the name of the people where the box have been checked :
[HttpPost]
public ActionResult CreateInventory(List<CoupleModel> model)
{
String res = "";
foreach (var item in model) {
if (item.isSelected)
{
res += "selected : " + item.login + "<br>";
}
else
{
res += item.login + "<br>";
}
}
ViewBag.Res = res;
return View();
}
But only the "isSelected" part is set, that's to say that login is always blank when displaying. Why isn't it set ? Do I need to do some particular binding ?
that's to say that login is always blank when displaying.
That's perfectly normal. You don't have a corresponding field in your form. You need to add it as a hidden field:
#Html.HiddenFor(m => m[i].login)
You need to add #Html.HiddenFor(..)s for the fields you want to pass along.
The result:
#for (int i = 0; i < Model.Count(); i++) {
#Html.HiddenFor(m => m[i].login)
<tr>
<td>
#Html.EditorFor(m => m[i].isSelected)
</td>
<td>
#Html.EditorFor(m => m[i].name)
</td>
<td>
#Html.EditorFor(m => m[i].role)
</td>
</tr>
}
On the side, please use the .NET naming convention.