Well, I have done this code before and it has worked, but this time it just wont work, please help me out here. I have searched the web for hours and tested many options, can't make it work. As you might have guessed I just want everything from my database (written in ssms) to be passed to the view, without errors. I get many different errors, the latest error is:
The model item passed into the dictionary is of type System.Collections.Generic.List1[System.String]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[FE.Blog]'.
The controller:
public ActionResult Contact()
{
var q = from p in dbBlog.Blog
select p.Description;
return View(q.ToList());
}
The View:
#model IEnumerable<FE.Blog>
#foreach (var item in Model)
{
#item.Description
}
You are selecting just one column p.Description which is string but your view expects Model to be IEnumerable<FE.Blog>.
So change your model in view if you need only on column:
#model List<string>
#foreach (var item in Model)
{
#item
}
Or if you want the view to bind with IEnumerable<FE.Blog> then you have to the object in query instead of just selecting one property:
public ActionResult Contact()
{
var q = from p in dbBlog.Blog
select p;
return View(q.ToList());
}
and in View:
#model IEnumerable<FE.Blog>
#foreach (var item in Model)
{
#item.Description
}
I just solved my problem I think, it looks so.
The problem was that I had forgot the "#model FE.Blog" above another forms using-statement in another View. There are partials view all over the place, this explains the errors I've been collecting.
Regards
Related
I am trying to return a list to my view. I can return it with #viewbag but i only get one entry from it .
If i try to do return view(items) I get exception issues. what should I do ?
here is my controller
foreach (var movie in item)
{
var items = _db.Movies.Where(s => s.imdbID.Equals(movie.Movieid)).ToList();
ViewBag.Movies = items;
return View(items);
}
Here is my view
#foreach (var item in ViewBag.Movies)
{
<p> #item.Title </p>
}
First of all you must not return View() inside a loop.
What is the meaning there ?
var items = new List<Movies>();
foreach (var movie in item)
{
items = items.Add(_db.Movies.Where(s =>
s.imdbID.Equals(movie.Movieid)).ToList());
}
return View(items);
And if you are returning the list why do you need that ViewBag.
ViewBag is needed when you dont want to include any other model in Dto you are passing. So if you are passing list of type Movies and for example you need another list of different type you pass the other one on ViewBag.
Do this on your View:
#model List<Movies>
#foreach(var item in Model)
{
<p> #item.Title </p>
}
Move your return outside the loop and remove the ViewBag, it looks like your controller is wrong, and some part of the View.
I Would also change the Where to FirstOrDefault, because you expect only 1 Movie to be found in the db.
And remove the .ToList(), because that does nothing right now.
like this:
var items = new List<Movies>();
foreach (var movie in item)
{
items.Add(_db.Movies.FirstOrDefault(s => s.imdbID.Equals(movie.Movieid)));
}
return View(items);
Also change your view to this:
#model IEnumerable<namespace.Models.movies>
#foreach(var item in Model)
{
<p> #item.Title </p>
}
You should use your model in the view, not the Viewbag, because right now, the (items) does nothing.
Also, look up how to add to a list in c#, it feels like you have some more to learn there, you can check here:
https://www.jennerstrand.se/add-object-to-list-in-c-sharp/
In view, you have to import the model of movies.
For example in view,
#model IEnumerable<projectName.models.movies>
#foreach(var item in Model)
{
<p> #item.Title </p>
}
I have an ItemsController with an Index action returning and rendering items on the client like
return View(itemViewModels);
Each itemViewModel has some bootstrap tabs. In each tab a partialView is rendered.
When the user edits a partialView and send the data to the Tab1Controller how can I return the View for the whole itemViewModel showing validation errors for the one partial view inside that tab1?
I have made the View work requesting/responsing with the sent itemViewModel but then Only the single item`s html is returned not the full items html.
AND when I return the Index View to the ItemsViewModels then I can NOT return my passed itemViewModels to show the validation errors.
[HttpGet]
public ActionResult Index(ItemViewModel viewModel)
{
return View("ItemsViewModels", viewModel);
}
This code does not work because the View does not match to the viewmodel type.
But I need to show the Html of the ItemsViewModels with the invalid (data-val attributes) html of the single edited itemViewModel.
I can NOT post and return the ItemsViewModels because it has many other properties which would make the modelstate invalid...
Do you have any idea?
UPDATE
I am NOT allowed to use ajax else the problem would be done quickly... this is for a common website and the customer wants a postback no ajax/SPA behavior.
At the moment I get the whole items from the service again and render it but then every ItemViewModel`s html has an invalid e.g. textbox. But I want that only a certain ItemViewModel is invalid.
[HttpPost]
public virtual async Task<ActionResult> SaveLanguage(ItemViewModel itemViewModel)
{
var viewModels = GetItemsViewModelsFromSErvice();
viewModels.Items.ElementAt(0).Settings = itemViewModel;
return View(MVC.Test.Items.Views.Index,viewModels );
}
If you are forced to do a full postback, but each partial view contains just a form with the elements for that 1 item then you'll have to reconstruct the other items in your controller before returning.
Your controller method would be something like
public ActionResult Index()
{
var vm = GetAllItems(); //method to get all your items for first load
return View(vm);
}
[HttpPost]
public ActionResult Index(ItemViewModel viewModel)
{
//get the full list of items, and then replace just the altered one
var vm = GetAllItems(); // assume returns a list
var index = vm.FindIndex(x => x.ID == viewModel.ID);
vm[index] = viewModel;
//might have to rename items in the ModelState.Errors dictionary
//so they are associated with the correct item index.
//first get the list of errors. As viewModel is not a list for this method
//they will have keys like "PropertyName".
//For a listItem need renaming to something like "[#].PropertyName" (# = index)
var errs = from ms in ModelState
where ms.Value.Errors.Any()
let fieldKey = ms.Key
let errors = ms.Value.Errors
from error in errors
select new {fieldKey, error.ErrorMessage};
//clear the ModelState, and then re-add any model-errors with the renamed key
ModelState.Clear();
foreach(var item in errs)
{
ModelState.AddModelError(
String.Format("[{0}].{1}", index, item.fieldKey), item.ErrorMessage);
}
return View("ItemsViewModels", vm);
}
In addition you might need to rename your form elements so that the model binder treats them as list items after postback. I'm not 100% sure this is necessary though.
If you can use ajax this becomes neater...
It looks like your index Model is a List<ItemViewModel>
Then your Main view (Index.cshtml) would be something like..
#model List<ItemViewModel>
...
#for(int i = 0; i < Model.Count; i++)
{
<div id="#String.Format("partialContainer{0}", Model[i].ID)">
#Html.Partial("Partial1", Model[i])
</div>
}
(notice that the ID of the container div is something that we can reference as the ajax update target)
And then have your partial Views use the relevant partial Models
Eg Partial1.cshtml:
#model ItemViewModel
... etc
#using (Ajax.BeginForm("RefreshPartial", "Home", null, new AjaxOptions() {
UpdateTargetId = String.Format("partialContainer{0}", Model.ID), HttpMethod = "Post" }, null))
{
#Html.TextBoxFor(m => m.Property1);
#* form controls... *#
<input type="submit" value="Submit" />
}
I am having a problem in a ASP.NET MVC project. I have a database where I have several tables, and I want to list all the records inside each table in my View, I am able to do this using only one table, I am going to provide here the code that works with one table and what I am trying to do.
Controller:
Using only one table I would do:
Mp5DataclassesDataContext db = new Mp5DataclassesDataContext();
public ActionResult Admin()
{
return View(db);
}
This is what I am trying to do:
return View(db);
At this point I can debug and see that all my tables are in that db object, with all the correct data. Then the problem is in my View
View:
#*This is defined at the top of my .cshtml*#
#model IEnumerable<Interface_AutoUtad.Models.Mp5DataclassesDataContext>
#*This is the code that works with only one table*#
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.table_column)
}
#*What I am trying to do:*#
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.some_other_table.table_column)
}
I can't get this last part to work because "some_other_table" doesn't show up.
Is there a way I can achieve this ? I want to Iterate through each table and inside iterate through each record in that table.
Thank you all in advance :)
It looks like you've set the "model" for your view to be your application's DbContext. Don't do that. Views are only processed at runtime, and querying into your database is way too much logic for a view. Any errors will only be exposed at runtime, and you have a huge potential for errors.
Views are designed to work with only one type. If you need to work with multiple types in the same view, you can either utilize a view model or use child actions.
View Model
public class MultipleTypesViewModel()
{
public IEnumerable<SomeType> SomeTypes { get; set; }
public IEnumerable<OtherType> OtherTypes { get; set; }
...
}
Then in your view:
#model Namespace.To.MultipleTypesViewModel
...
#foreach (var item in Model.SomeTypes)
{
#Html.DisplayFor(modelItem => item.table_column)
}
#foreach (var item in Model.OtherTypes)
{
#Html.DisplayFor(modelItem => item.table_column)
}
...
Child Actions
[ChildActionOnly]
public ActionResult ListSomeTypes()
{
var someTypes = db.SomeTypes.ToList();
return PartialView(someTypes);
}
[ChildActionOnly]
public ActionResult ListOtherTypes()
{
var otherTypes = db.OtherTypes.ToList();
return PartialView(otherTypes);
}
...
Then, create an appropriate partial view for each:
ListSomeTypes.cshtml
#model IEnumerable<Namespace.To.SomeType>
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.table_column)
}
ListOtherTypes.cshtml
#model IEnumerable<Namespace.To.OtherType>
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.table_column)
}
Etc. And then finally in your main view:
#Html.Action("ListSomeTypes")
#Html.Action("ListOtherTypes")
(In this case, the model of the main view is totally irrelevant.)
i'm newbie to MVC 3.0 and LINQ to SQL. called store procedure and saved it result in VAR but now how to view it's data in VIEW ?
CODE:
using EmployeeAttendance_app.Models;
namespace EmployeeAttendance_app.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Employee Attendance";
var DataContext = new EmployeeAtdDataContext();
var EmployeeAtd = DataContext.GetAttendance_Sp;
return View(EmployeeAtd);
}
public ActionResult About()
{
return View();
}
}
}
SP:
Select * from V_EmpAtd
View:
#foreach (GetAttendance_SpResult emp in (IEnumerable<Object>)ViewData.Model)
{
<li>#emp.DeptName</li>
}
this view shows the results, successfully :) but i don't understand that why do i need "GetAttendance_SpResult" in foreach and how
return View(EmployeeAtd);
in controller is related to this ?
right click within your action and select 'Create View'
public ActionResult Index()
{ // right click here...
then visit the view /HomeController
Where is your model? "M" "V" "C" ;-)
First you should create a class (your model, called for example EmployeeModel- you should take a name corresponding to the type of your data) corresponding to the fields of your items of your database results. How? Look here:
http://www.asp.net/mvc/tutorials/mvc-5/introduction/adding-a-model
The list of items corresponding to that model will be passed to your View in your controller so your view should start with:
#model IEnumerable<yourNameSpace.Models.EmployeeModel>
And then in your view you will be able to display the properties of your item. Sample for a table:
<table>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.DeptName)
</td>
</tr>
}
</table>
But you can do what you want: a list, ...
In a few words: back to MVC basics. See sample here: http://www.asp.net/mvc/tutorials/mvc-5/introduction/accessing-your-models-data-from-a-controller, especially when they are in "Examining the Generated Code".
I have the following model in MVC:
public class ParentModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public IEnumerable<ChildModel> Children { get; set; }
}
When I want to display all of the children for the parent model I can do:
#Html.DisplayFor(m => m.Children)
I can then create a ChildModel.cshtml display template and the DisplayFor will automatically iterate over the list.
What if I want to create a custom template for IEnumerable?
#model IEnumerable<ChildModel>
<table>
<tr>
<th>Property 1</th>
<th>Property 2</th>
</tr>
...
</table>
How can I create a Display Template that has a model type of IEnumerable<ChildModel> and then call #Html.DisplayFor(m => m.Children) without it complaining about the model type being wrong?
Like this:
#Html.DisplayFor(m => m.Children, "YourTemplateName")
or like this:
[UIHint("YourTemplateName")]
public IEnumerable<ChildModel> Children { get; set; }
where obviously you would have ~/Views/Shared/DisplayTemplates/YourTemplateName.cshtml:
#model IEnumerable<ChildModel>
<table>
<tr>
<th>Property 1</th>
<th>Property 2</th>
</tr>
...
</table>
This is in reply to Maslow's comment. This is my first ever contribution to SO, so I don't have enough reputation to comment - hence the reply as an answer.
You can set the 'TemplateHint' property in the ModelMetadataProvider. This would auto hookup any IEnumerable to a template you specify. I just tried it in my project. Code below -
protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
{
var metaData = base.CreateMetadataFromPrototype(prototype, modelAccessor);
var type = metaData.ModelType;
if (type.IsEnum)
{
metaData.TemplateHint = "Enum";
}
else if (type.IsAssignableFrom(typeof(IEnumerable<object>)))
{
metaData.TemplateHint = "Collection";
}
return metaData;
}
You basically override the 'CreateMetadataFromPrototype' method of the 'CachedDataAnnotationsModelMetadataProvider' and register your derived type as the preferred ModelMetadataProvider.
In your template, you cannot directly access the ModelMetadata of the elements in your collection. I used the following code to access the ModelMetadata for the elements in my collection -
#model IEnumerable<object>
#{
var modelType = Model.GetType().GenericTypeArguments[0];
var modelMetaData = ModelMetadataProviders.Current.GetMetadataForType(null, modelType.UnderlyingSystemType);
var propertiesToShow = modelMetaData.Properties.Where(p => p.ShowForDisplay);
var propertiesOfModel = modelType.GetProperties();
var tableData = propertiesOfModel.Zip(propertiesToShow, (columnName, columnValue) => new { columnName.Name, columnValue.PropertyName });
}
In my view, I simply call #Html.DisplayForModel() and the template gets loaded. There is no need to specify 'UIHint' on models.
I hope this was of some value.
In my question about not getting output from views, I actually have an example of how to template a model with a collection of child models and have them all render.
ASP.NET Display Templates - No output
Essentially, you need to create a model that subclasses List<T> or Collection<T> and use this:
#model ChildModelCollection
#foreach (var child in Model)
{
Html.DisplayFor(m => child);
}
In your template for the collection model to iterate and render the children. Each child needs to strongly-typed, so you may want to create your own model types for the items, too, and have templates for those.
So for the OP question:
public class ChildModelCollection : Collection<ChildModel> { }
Will make a strongly-typed model that's a collection that can be resolved to a template like any other.
The actual "valid answer" is -IMHO- not correctly answering the question. I think the OP is searching for a way to have a list template that triggers without specifying the UIHint.
Magic stuff almost does the job
Some magic loads the correct view for a specified type.
Some more magic loads the same view for a collection of a specified type.
There should be some magic that iterates the same view for a collection of a specified type.
Change the actual behavior?
Open your favorite disassembler. The magic occurs in System.Web.Mvc.Html.TemplateHelpers.ExecuteTemplate. As you can see, there are no extensibility points to change the behavior. Maybe a pull request to MVC can help...
Go with the actual magic
I came up with something that works. Create a display template ~/Views/Shared/DisplayTemplates/MyModel.cshtml.
Declare the model as type object.
If the object is a collection, iterate and render the template again. If it's not a collection, then show the object.
#model object
#if (Model is IList<MyModel>)
{
var models = (IList<MyModel>)Model;
<ul>
#foreach (var item in models)
{
#Html.Partial("DisplayTemplates/MyModel", item)
}
</ul>
} else {
var item = (MyModel)Model;
<li>#item.Name</li>
}
}
Now DisplayFor works without UIHint.