I have generated a strongly-type view from a model class that I have created from scratch. I have used the List as the scaffold template. The error appears at the foreach line with the model object.
View:
#model IEnumerable<HockeyPoolStats.Models.Player>
#{
ViewBag.Title = "Index";
}
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Team_Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Rank)
</td>
<td>
#Html.DisplayFor(modelItem => item.PlayerName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PlayerTeam)
</td>
[...]
Controller:
public class PlayerController : Controller
{
private HockeyPoolStatsDB _db = new HockeyPoolStatsDB();
//
// GET: /Player/
public ActionResult Index()
{
Player _player = new Player();
_db.Players.Add(_player);
var model = _db.Players;
return View(model);
}
}
DbContext
public class HockeyPoolStatsDB : DbContext
{
public DbSet<Player> Players { get; set; }
public DbSet<Team> Teams { get; set; }
public DbSet<Goalie> Goalies { get; set; }
}
I don't understand why model is null. This means that the controller isn't passing the model to the view correctly?
It more likely means that _db.Players is returning null.
Set a breakpoint and step through it and verify that _db.Players is actually returning a list of players.
Related
I am new to ASP mvc and entity framework
I have a model created by entity framework as
public partial class Privilege
{
public Privilege()
{
this.Role_Privilege_Map = new HashSet<Role_Privilege_Map>();
}
public int PrivilegeId { get; set; }
[Required(ErrorMessage="*")]
[Display(Name = "Privilege Name")]
public string PrivilegeName { get; set; }
[Required(ErrorMessage = "*")]
public Nullable<int> ModuleId { get; set; }
public virtual module module { get; set; }
public virtual ICollection<Role_Privilege_Map> Role_Privilege_Map { get; set; }
}
As you can see module is a navigational property.
I have binded this model to a view as
#for (var i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => modelItem[i].PrivilegeName)
#Html.HiddenFor(modelItem => modelItem[i].PrivilegeId)
#Html.HiddenFor(modelItem => modelItem[i].PrivilegeName)
</td>
<td>
#Html.DisplayFor(modelItem => modelItem[i].module.ModuleName)
#Html.HiddenFor(modelItem => modelItem[i].ModuleId)
#Html.HiddenFor(modelItem => modelItem[i].module.ModuleName)
#Html.HiddenFor(modelItem => modelItem[i].module)
</td>
<td>
#Html.CheckBoxFor(modelItem => modelItem[i].Checked)
#Html.HiddenFor(modelItem => modelItem[i].Checked)
</td>
<td>
#Html.ActionLink("Edit", "OpenEditPrivilegeDialog", "RolePrivilegeMapping",
new { id = Model[i].PrivilegeId },
new { #class = "actionHyperLink edit_Privilege_Link" }) |
#Html.ActionLink("Delete", "DeletePrivilege","RolePrivilegeMapping",
new { id = Model[i].PrivilegeId },
new { #class = "actionHyperLink Delete_Privilege_Link" })
</td>
</tr>
}
I have an Update button for updating this model say Privilege name. Now in my action
public ActionResult UpdateRolePrivilege(IList<One_Track.Models.Privilege> updatedPrivilege)
{
if (ModelState.IsValid)
{
}
else
{
ViewBag.PrivilegeMessage = "Privileges updation Failed.";
}
}
return PartialView("PrivilegePartial", sample.GetPrivilegeNames());
}
Is returning false. I put a breakpoint and come to know that the navigational property is null that could be a reason for model not been valid. How can I surpass this. As you can see in code I have added a hidden field for binding navigational property
Why is this happening? Any help will be appreciated
As per the post ModelState.IsValid == false, why? provided by wiz kid
I come to know that tan exception is occuring there as
The parameter conversion from type 'System.String' to type 'sample.Models.module' failed because no type converter can convert between these types.
at System.Web.Mvc.ValueProviderResult.ConvertSimpleType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.UnwrapPossibleArrayType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.ConvertTo(Type type, CultureInfo culture)
at System.Web.Mvc.DefaultModelBinder.ConvertProviderResult(ModelStateDictionary modelState, String modelStateKey, ValueProviderResult valueProviderResult, Type destinationType)}
So I removed the line from view
#Html.HiddenFor(modelItem => modelItem[i].module)
This solved by problem
i'm displaying a table in front end where table records are Editable and each record has a check box.
if some records are selected by making the corresponding checkboxes checked and submitted all the selected records have to be stored in a backend table.
Is it possible using Asp.net MVC3?
If yes how to pass that list of records from View to controller and Model?
As I understand you want to pass array of selected checkboxes to ActionResult during post.
See example below
Model:
public class EditableItemModel
{
public bool SelectedItem { get; set; }
public string Name { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new EditableItemModel[]
{
new EditableItemModel { SelectedItem = true },
new EditableItemModel()
};
return View(model);
}
[HttpPost]
public ActionResult Index(EditableItemModel[] tableItems)
{
IEnumerable<EditableItemModel> selectedItems = tableItems.Where(i => i.SelectedItem);
return RedirectToAction("Index");
}
View:
#using CheckboxInTableExample.Models;
#model EditableItemModel[]
#using (Html.BeginForm("Index"))
{
<table>
#for (int i = 0; i < Model.Length; i++)
{
<tr>
<td>
#Html.CheckBoxFor(m => m[i].SelectedItem)
</td>
<td>
#Html.EditorFor(m => m[i].Name)
</td>
</tr>
}
</table>
<input type="submit" title="Submit" />
}
Hope this helps.
My ViewModel is:
public class ObjectiveVM
{
public string DateSelected { get; set; }
public List<string> DatePeriod { get; set; }
public IList<ObList> obList { get; set; }
public class ObList
{
public int ObjectiveId { get; set; }
public int AnalystId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string AnalystName { get; set; }
public bool Include { get; set; }
}
}
This is passed to the view, populated as expected - and displays correctly in the view.
My problem is when it is posted back to the controller. My controller code to accept it back is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Analyst(ObjectiveVM ovm)
ovm.obList is always showing as null:
My View html is:
#model Objectives.ViewModels.ObjectiveVM
#{
ViewBag.Title = "Analyst";
}
<h2>Copy Objectives for Analyst</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Objective</legend>
#Html.DropDownListFor(model => model.DateSelected, new SelectList(Model.DatePeriod))
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.obList[0].Include)
</th>
<th>
#Html.DisplayNameFor(model => model.obList[0].AnalystName)
</th>
<th>
#Html.DisplayNameFor(model => model.obList[0].Title)
</th>
<th>
#Html.DisplayNameFor(model => model.obList[0].Description)
</th>
</tr>
#foreach (var obList in Model.obList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => obList.ObjectiveId)
#Html.HiddenFor(modelItem => obList.AnalystId)
#Html.HiddenFor(modelItem => obList.Title)
#Html.HiddenFor(modelItem => obList.Description)
#Html.CheckBoxFor(modelItem => obList.Include)
</td>
<td>
#Html.DisplayFor(modelItem => obList.AnalystName)
</td>
<td>
#Html.DisplayFor(modelItem => obList.Title)
</td>
<td>
#Html.DisplayFor(modelItem => obList.Description)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Copy Selected Objectives" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Looking in Developer Tools at the Posted form values, they appear to be ok:
Can anyone see any reason the posted form values, are not mapping back onto my viewmodel in the Controller HTTP post?
Thank you, Mark
You need to use a for...loop here, not a foreach....loop.
#for (int idx = 0;idx < Model.obList.Count;idx++){
#Html.HiddenFor(_ => Model.obList[idx].ObjectiveId)
// ... etc....
}
Without the indexer (idx), the model binder will not know how to bind the values back to the right collection item.
When working with collections in my views, I typically write out my markup without the use of helpers:
#for (int i = 0;i < Model.obList.Count();i++){
<input type="hidden" name="ObList[#i].ObjectiveId" id="ObList[#i].ObjectiveId" value="#ObList[i].ObjectiveId" />
<input type="hidden" name="ObList[#i].AnalystId" id="ObList[#i].AnalystId" value="#ObList[i].AnalystId" />
...
}
This will conform to the wire format the model binder expects, and will slot your values into your ViewModel: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
I have an MVC app that I am trying to put together that requires some select lists and drop down lists.
So, I have the following models....
public class Task
{
public int ID { get; set; }
public string Title { get; set; }
......
public virtual ICollection<Monitor> Monitors { get; set; }
public virtual ICollection<Resource> Resources { get; set; }
}
public class Monitor
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<Task> Tasks { get; set; }
}
public class Resource
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
.....
public IList<Task> Tasks { get; set; }
The interesting part is that when I display a list of tasks, among the other properties that display just fine, I need to display a list of 'Monitors' and a list of 'Resources' that are assigned to the task in the Index view shown below.
#model IEnumerable<ResourceManager.Models.Task>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
.....
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
.....
<th>
#Html.DisplayNameFor(model => model.Monitors)
</th>
<th>
#Html.DisplayNameFor(model => model.Resources)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
.....
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
.....
<td>
#if (item.Monitors == null || item.Monitors.Count == 0)
{<span>No Monitors Assigned</span>}
else
{ string.Join(", ", item.Monitors.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName))); }
</td>
<td>
#Html.DisplayFor(modelItem => item.Resources)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
And here is the controller....
public ActionResult Index()
{
var tasks = from t in db.Tasks where t.IsActive == true select t;
return View(tasks);
}
I would like for the list of Monitors and the list of Resources to display as a string on the Index, Delete and Details Views i.e. 'Monitor 1, Monitor 2, Monitor 3' and 'Resource 1, Resource 2, Resource 3'.
However on the other views (Create and Edit), I want them to appear as a selectable list.
First Create Select list in your controller,
var monitors = //Your linq query
ViewData["ddlList"] = monitors .Select(x => new SelectListItem {
Text = x.FirstName,
Value = x.Id.ToString()
}).ToList();
And then you can use it in your view as follows,
<%=Html.DropDownList("myList") %>
For the display of Monitors/Resources (and since you want them displayed as a comma-delimited list), you can just use string.Join:
<td>
#string.Join(",", Model.Monitors.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName)))
</td>
To be able to actually use Html.DisplayFor, you'd have to create a custom display template so Razor will actually know how to respond. To do so, in your Views folder, create new folder called "DisplayTemplates", and in that, create a new partial view called "Monitors.cshtml" and "Resources.cshtml", strongly-typed to IEnumerable<Monitor> and IEnumerable<Resource>, respectively. Then inside that file, you'll just add roughly the same code as above:
#model IEnumerable<Monitor>
#string.Join(",", Model.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName)))
Then in your view, you can call:
#Html.DisplayFor(m => m.Monitors, "Monitors")
Unfortunately, in this example, you'd have to feed the template name because the default behavior of DisplayFor for a list, is to render the display template multiple times, once for each member of the list. You could do something like:
# Monitor.cshtml
#model Monitor
#Model.FirstName #Model.LastName,
And then:
#Html.DisplayFor(m => m.Monitors)
But your last item would have a comma at the end.
For editing the lists, all you have to do is pass the select lists to your view. Optimally, you'd do this with a view model, but for simplicity's sake, I'll just use ViewBag here. In your controller action:
ViewBag.MonitorChoices = db.Monitors.Select(m => new SelectListItem
{
Value = m.ID.ToString(),
Text = string.Format("{0} {1}", m.FirstName, m.LastName)
});
Then, in your create/edit view:
#Html.ListBoxFor(m => m.Monitors, ViewBag.MonitorChoices)
Try as follows,
var monitors = //Your linq query
List monitorList = new List();
foreach (var monitor in monitors ){
SelectListItem item = new SelectListItem();
item.Text = monitor.FirstName;
item.Value = monitor.Id.ToString();
monitorList .Add(item);
}
ViewData["ddlList"] = monitorList;
I have a controller, which passes a model (ovw.ToList()) to a view:
//
// GET: /Clinic/Overview/
public ActionResult Overview()
{
IEnumerable<Clinic> ovw = from c in db.Clinics
select c;
return View(ovw.ToList());
}
View:
#model IEnumerable<ttp.Models.Clinic>
#foreach (var item in Model)
{
<div>#item.ClinicName</div>
#foreach (var item2 in item.Properties)
{
<div>#item2.Address</div>
This works absolutely fine on screen.
When using MVCMailer, however , if I want to display the same layout in the email, how do I pass the ovw.ToList() to the mailer view, so that I can reference the same model in this way:
(I'm stuck on what to put in as the first line in the view):
#model IEnumerable<ttp.Models.Clinic>
#foreach (var item in Model)
Thanks for any help,
Mark
You should find your answer in the 'Pass Data to Mailer Views' part of this guide: https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
To pass your model along with the view to MVCMailer, you need to use ViewData:
var comment = new Comment {From = me, To = you, Message = "Great Work!"};
ViewData = new ViewDataDictionary(comment);
In my project i doing like this it's below
i am showing all my category list in my index view
in my model class
public List<CategoryDetails> CategoryData { get; set; }
and i am also create CategoryDetails class and create a property to all my field
like this
public int CatID { get; set; }
[Required(ErrorMessage = "Enter Category Name")]
public string CatName { get; set; }
public string CatImage { get; set; }
and create a function in my main model class like this
public void LoadCategory()
{
CategoryData = (from con in dbData.Categorys
select new CategoryDetails()
{
CatID = con.CatID,
CatName = con.CatName,
CatImage = con.CatImage,
}).ToList();
}
In my controller i create a action like this
create my model class object and pass my model function to action
public ActionResult Index()
{
CategoryModel categorymodel = new CategoryModel();
categorymodel.LoadCategory();
return View(categorymodel);
}
and in my view
#model PMS.Models.CategoryModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Category Name
</th>
<th>
</th>
</tr>
#foreach (var item in Model.CategoryData)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CatName)
</td>
</tr>
}
</table>
i think this will help you