Loop over ModelView in razor - c#

I have created razor forms that do a #foreach to loop over the model and produce my rows. Now I am trying to to the same thing over a ViewModel, and I get the following error.
Unable to create a constant value of type 'MyProject.Models.SupportContact'.
Only primitive types or enumeration types are supported in this context.
My #model is being passed in as IQueryable(MyProject.Models.SupportContactFormView), and SupportContact is part of that ViewModel, but I can't seem to reference it in the model.
I can do this:
#foreach (var item in Model ) {
#Html.DisplayFor(modelItem => item.SupportContact.Contact)
But then I will get the error above when it actually try to process my cshtml. I have tried to do:
#foreach (MyProject.Models.SupportContact item in Model ) {}
But I can't drill down thru the model to get the SupportContacts. How can I get to a my SupportContact class inside my ViewModel?
Thanks
Edit:
Here is the ViewModel declaration:
public class SupportContactFormView
{
public SupportContact SupportContact { get; private set; }
public SelectList Priorities { get; private set; }
public SelectList ContactTypes { get; private set; }
public String Group_COde { get; private set; }
}

In your case, I would create a viewmodel specifically for that view and set it up like so
ViewModel Class
public class IndexViewModel
{
public IList<SupportContact > SupportContacts { get; set; }
}
Controller
public ActionResult Index()
{
var viewModel = new IndexViewModel();
viewModel.SupportContacts = IQueryableListOfContacts.ToList();
return View(viewModel)
}
View
#model IndexViewModel
#foreach (var contact in Model.SupportContacts) {
#Html.DisplayFor(_ => contact.Contact)
You need to play around a bit with the code, as I doubt I have the property names/action method name correct first time, but I hope you get the basic idea. Create a viewmodel class that the view file makes use of, and dump the contact details into a List. That will make it easier for you.
EDIT:
Actually, I think I got the wrong end of the stick here. The error "Unable to create a constant value of type 'MyProject.Models.SupportContact'.
Only primitive types or enumeration types are supported in this context." means that there is something wrong with your LINQ data.
Are you using Entity Framework or Linq2SQL? Ignore my answer about the viewmodel appraoch, your actual issue is LINQ related. Try iterating over the list of contacts in an ActionMethod instead e.g.
public ActionMethod Index()
{
foreach (var contact in whateveryourcontactslistis) {
}
// ....
}
If you still have a problem here, then it's your LINQ data at fault.

Related

DropDownList Error, System.InvalidOperationException

Create.cshtml
#Html.DropDownList("KategoriId",null,htmlAttributes: new { #class="form-control"})
MakaleController.cs
public ActionResult Create()
{
ViewBag.KategoriId = new SelectList(db.Kategoris, "KategoriId", "KategoriAdi");
return View();
}
but it's say When I make a post request,
The ViewData element with the 'KategoriId' key is of type 'System.Int32', but of type 'IEnumerable '.
How to fix this error, I tried many ways but it did not happen. He says that the value is generally null.
Kategori.cs (!! NOT KATEGORIS, i create with code first)
[Table("Kategori")]
public partial class Kategori
{
public int KategoriId { get; set; }
[StringLength(50)]
public string KategoriAdi { get; set; }
public virtual Makale Makale { get; set; }
}
Updated
Your dropdown definition is not right
it should look like below
#Html.DropDownListFor(m => m.CategoryID, Model.CategoryList, "-Please select-")
you pass null to Dropdownlist, but it is supposed to be at least an empty list
You also try to keep dropdownlist data in viewbag. it is supposed to be a List property in the view model.
P.S: using native words in variable names are not acceptable in global projects due to readability issues =)
P.S: You can check a similar question and answer from here The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'

Which is the best way to use multiple models with sames properties and using a unique view?

For example, I have 3 models with an Id (int), a Name (string) and an active (bool). It's possible to use just one view for these models with the same properties ? A technique like a generic object ? Inheritance ? It's to avoid to write multiple views with the same HTML code.
You could create a ViewModel.
For sample:
public class CustomerViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
And create another ViewModel with a type like this:
public class CustomersViewModel
{
public CustomerViewModel Customer1 { get; set; }
public CustomerViewModel Customer2 { get; set; }
public CustomerViewModel Customer3 { get; set; }
}
and type your view with this type:
#model CustomersViewModel
Or just use an collection to type your view
#model List<CustomerViewModel>
Take a look at this anwser!
https://stackoverflow.com/a/694179/316799
In a view you can either
specify shared base class for all models and use that.
use dynamic as model
split view in shared (extract into separate view) and specific part. Than call shared sub-view with either existing model (if using base class/dynamic) or simply new model constructed based on data in specific model.
Sample of extracting shared portion with inheritance. Using Html.Partial to render shared portion:
class SharedModel { /* Id,...*/ }
class SpecificModel : SharedModel { /* Special... */ }
SpecificView:
#model SpecificModel
#Html.Partial("SharedView", Model)
<div>#Model.Special</div>
SharedView:
#model SharedModel
<div>#Model.Id</div>
Side note: You can specify view name when returning result by using View if view name does not match action name:
return View("MySharedView", model);
In ASP.NET MVC4 you have the opportunity not to define a model for the view. This means leave the definition of the model empty (don't use #model MyNamespace.MyClass) and then it will automatically use "dynamic" as model.
Greetings
Christian

using ViewBag to pass a model object

I'm trying to sort my result page (which is in another view than the filtration page). I have faced this weird issue I do not understand why keeps happening to me.
All the codes provided in very short form, please ask me if you need any other parts of my code for more information.
My Index view(where user filters results):
#model IEnumerable<Cars.Models.CarSearch>
#using (Html.BeginForm("SearchResult", "Home", FormMethod.Post,
new
{
id = "CategoryFormID",
data_modelListAction = #Url.Action("ModelList"),
data_makeListAction = #Url.Action("MakeList"),
data_editionListAction = #Url.Action("EditionList")
}))
{
<label>Make</label>
<select id="MakeID" name="carMake">
<option>All Makes</option>
</select>
}
My SearchResult view:
#model IEnumerable<Cars.Models.Car>
Make
My model:
public class Car
{
public String Make { get; set; } //is my table model
}
public class CarFilter {
public String carMake { get; set; }
}
public class CarSearch {
public CarFilter CarFilter { get; set; }
public byte PageSize { get; set; }
public short PageNumber { get; set; }
public int TotalRows { get; set; }
}
My Controller:
public ActionResult SearchResult(String sortOrder, CarFilter filters)
{
ViewBag.CurrentFilters = filters;
return View();
}
All I'm trying to do is to get carMake from Index post it to controller in CarFilter form (since in my code there are LOTS of fields in the form and I don't want to write them all down) and when user clicks on sort by Make it GET the SearchResult method and it's supposed to set filters = ViewBag.CurrentFilters which is the value user inputted from beginning.
Now the funny part is, when I replace CarFilter filters with String carMake and other places respectively. It works like a charm.
My question:
Why?
How can I do this with CarFilter filters?
UPDATE:
Problem is that filters = ViewBag.CurrentFilters in my SearchResult view does not work with the type CarFilter, because it keeps giving me NULL value when user clicked on the sort by Make.
Second UPDATE:
I tried changing filters = ViewBag.CurrentFilters with CarFilter = ViewBag.CurrentFilters. Now CarFilter filters in my SearchResult(...)method in my controller is not and null object, but ALL the values of the objects in the model class is null (which shouldn't be). I mean the filters object exists but it seems like the values of CarFilter class in my model haven't been passed by ViewBag.CurrentFilters to the view.
when you canged the name it worked because framework found property name and the bind it to what you have within action parameters doesnt work so nicely with objects. My advice is to stick with simple types
Here is similiar case:
How to send model object in Html.RenderAction (MVC3)
Its not a ViewBag problem thants how it works in general. Its the prime reason for using flatted models :/

Pass tuple with two object collections to view?

I want to pass two collections of objects. First is Post, second is Gallery. However I get error and I don't know how to fix this.
I've done this when passing two single objects and it is working fine, but now I need to pass two collections of those objects and it gives me error.
Error
The model item passed into the dictionary is of type
'System.Tuple2[System.Linq.IQueryable1[photoBlog.Models.Gallery],System.Linq.IQueryable1[photoBlog.Models.Post]]',
but this dictionary requires a model item of type
'System.Tuple2[System.Collections.Generic.IEnumerable1[photoBlog.Models.Gallery],System.Collections.Generic.IEnumerable1[photoBlog.Models.Post]]'.
Controller
public ActionResult Index()
{
photoBlogModelDataContext _db = new photoBlogModelDataContext();
var posts = _db.Posts.OrderByDescending(x => x.DateTime).Take(4);
var galleries = _db.Galleries.OrderByDescending(x => x.ID).Take(4);
return View(Tuple.Create(galleries, posts));
}
View
#model Tuple<IEnumerable<photoBlog.Models.Gallery>, IEnumerable<photoBlog.Models.Post>>
#foreach (var item in Model.Item1)
{
#item.Name
}
I think you should modify your controller method to this:
public ActionResult Index()
{
photoBlogModelDataContext _db = new photoBlogModelDataContext();
var posts = _db.Posts.OrderByDescending(x => x.DateTime).Take(4).ToArray();
var galleries = _db.Galleries.OrderByDescending(x => x.ID).Take(4).ToArray();
return View(Tuple.Create(galleries, posts));
}
From your error message, it appears that the queries are not resolved yet when your view is rendered. By also doing ToArray or ToList, you will force the query to hit the database before you return from the controller method.
You need to create a new Entity in your domain.Model
Here is an example I provided today :
MVC3: button to send both form (model) values and an extra parameter
Later Edit :
namespace App.Domain.Model
{
public class Tuple
{
public IEnumerable<photoBlog.Models.Gallery> Gallery{ get; set; }
public IEnumerable<photoBlog.Models.Post> Post{ get; set; }
}
}
you will send the Tuple object to your view as follows :
#model: (Domain.Model.)Tuple <--- (your exact model path )
#foreach (var item in Model.Gallery)
{
#item.Name
}
Another posibility would be using viewbag ... but i strongly suggest you do it the correct way,i.e. the MVC way
Just try this
var posts = _db.Posts.OrderByDescending(x => x.DateTime).Take(4).ToList();
var galleries = _db.Galleries.OrderByDescending(x => x.ID).Take(4).ToList();

ASP.NET MVC Forms for Model

I'm trying to learn MVC by building a full-featured website. I'm a little stuck when it comes to dealing with forms, and posting data, and models....
BTW: I'm using EF Code-First w/MS SQL CE
Here's the Models in question:
public class Assignment
{
public int AssignmentID { get; set; }
public int? CourseID { get; set; }
public string Name { get; set; }
// etc...
public virtual Course Course { get; set; }
}
public class Course
{
public int CourseID { get; set; }
// etc...
}
I'm loading a partial view that allows the user to add a new assignment
Controller:
public ActionResult Assignments()
{
var assignments = myContext.Assignments.OrderBy(x => x.DueDate);
return View(assignments);
}
[HttpPost]
public ActionResult AddAssignment(Assignment assignment)
{
myContext.Assignments.Add(assignment);
myContext.SaveChanges();
return RedirectToAction("Assignments");
}
// Returns a strongly-typed, partial view (type is Assignment)
public ActionResult AddAssignmentForm()
{
return PartialView();
}
Here's where I'm stuck: I want this form to have a drop down list for the different courses that an assignment could possibly belong to. For example, an assignment called "Chapter 3 Review, Questions 1-77" could belong to course "Pre-Algebra". However, if I use the code below, I have to explicitly declare the SelectListItems. I thought that with the given Assignment model above, I should be able to have the drop down list for Courses automatically generated using MVC awesomeness. What am I doing wrong?
AddAssignment Partial View:
#model MyModels.Assignment
#using(Html.BeginForm("AddAssignment", "Assignments"))
{
// Can't I create a drop down list without explicitly
// setting all of the SelectListItems?
#Html.DropDownListFor(x => x.Course, ....
}
Basically you are confusing/mixing your business model and your UI model.
The quick fix here is to add the data for the dropdown list to the ViewBag (a dynamic object).
Alternatively you could create a class AssignmentModel that contains the relevant Assignment properties and the List.
And No, this is not well supported in the templates.
You do realize you'll need some error handling in the Post method(s)?

Categories

Resources