mvc-4 generate list in view - asp.net-mvc

I have a little problem with getting my View to generate properly.
I get Error: Model does not contain a public definition for 'GetEnumerator'
I have tried to change my generic list into a IEnumerable list but then it popped a few more errors in the code I couldnt get rid of, Im not sure if I have to add it to my UploadedFile class somehow ?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Mvc_fileUploader.Models
{
public class UploadedFile
{
public string Name { get; set; }
public string Path { get; set; }
public long Size { get; set; }
}
}
Controller:
[HttpGet]
public ActionResult UploadedFiles()
{
var uploadedFiles = new List<UploadedFile>();
var files = Directory.GetFiles(Server.MapPath("~/fileUploads/"));
foreach (var file in files)
{
var fileInfo = new FileInfo(file);
var uploadedFile = new UploadedFile();
uploadedFile.Name = Path.GetFileName(file);
uploadedFile.Size = fileInfo.Length;
uploadedFile.Path = ("~/fileUploads/") + Path.GetFileName(file);
uploadedFiles.Add(uploadedFile);
}
return View();
View:
#model Mvc_fileUploader.Models.UploadedFile
#{
ViewBag.Title = "UploadedFiles";
}
<h2>UploadedFiles</h2>
<table style="background-color:lightpink; border:solid 2px black;">
<tr>
<td>Name</td>
<td>Size</td>
<td>Preview</td>
</tr>
#foreach (var file in Model)
{
<tr>
<td>#file.Name</td>
</tr>
}
</table>
the source on github: https://github.com/xoxotw/mvc_fileUploader

Need to set the model of the view to be
IEnumerable<Mvc_fileUploader.Models.UploadedFile>
[EDIT]
You're not returning the model. In your controller action; add the list you've created to the View() call, eg:
[HttpGet]
public ActionResult UploadedFiles()
{
var uploadedFiles = new List<UploadedFile>();
var files = Directory.GetFiles(Server.MapPath("~/fileUploads/"));
// do stuff
return View(uploadedFiles);

#model Mvc_fileUploader.Models.UploadedFile
It is used when only one model is passed to the view. If u want to pass list of model, then u have to write like following.
IEnumerable<Mvc_fileUploader.Models.UploadedFile>

Related

getting all rows from db mvc asp.net

var listdata = db.UserDetails.Select(m => new SelectListItem
{
Value = m.userid.ToString(),
Text = string.Format("{0}{1}{2}{3}",m.bankname,m.userid,m.gender,m.name)
});
Here UserDetails is the table that is present in the database and this is the way i am trying to display every entry of the table.
Controller
[HttpGet]
public ActionResult getAll()
{
var listdata = db.UserDetails.Select(m => new SelectListItem
{
Value = m.userid.ToString(),
Text = string.Format("{0}{1}{2}{3}",m.bankname,m.userid,m.gender,m.name)
});
return View("getAll", listdata);
}
View
#model UserApp.Models.UserDetails
#{
ViewBag.Title = "getAll";
}
<h2>getAll</h2>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.gender)
</td>
</tr>
}
Model
namespace UserApp.Models
{
public class UserModel : IEnumerable<UserModel>
{
public int userid {get; set;}
public string name{get; set;}
public IList<SelectListItem> bankname { get; set; }
public string gender{get; set;}
}
}
How do i get the elements and display them properly on the view?
I can't seem to get a proper solution.
Stuck on this thing for hours.
P.s: new to it, any help will be appreciated.
First, add ToList() for your listdata to make it list, currently it is still IQueryable , second your view accepts model, you are passing list of model, I guess you want that to be list not model, something like this
#model List<UserApp.Models.UserDetails>
Third, you are selecting SelectListItem but you are using UserApp.Models.UserDetails, I think you should be doing something like this
var listdata = db.UserDetails.ToList().Select(x => new UserApp.Models.UserDetails {
userid = x.userid, (repeat the same for all)
}).ToList();
because looking at your code you don't need selectListItem, you need UserApp.Models.UserDetails.
That should fix all your problems, I hope I didn't miss any.
My approach may not be the best approach but it seems to work for me.
I usually have my model for the item :
model :
namespace UserApp.Models
{
public class UserModel
{
public int userid {get; set;}
public string name{get; set;}
public IList<SelectListItem> bankname { get; set; }
public string gender{get; set;}
}
}
Then I have in my database class ( a class that calls the database and populates the queries etc: Call it CodeDB() for this example)
DB getter :
public List<UserModel> getUsers(){
{
List<UserModel> myUsers = new List<userModel>();
// however you are accessing your db do it here
string sql = "select * ...";
//access DB
//open connection
//run query command usually for me it is rdr = cmd.ExecuteReader();
while(rdr.Read()){
UserModel retrievedUser = new UserModel();
retrievedUser.userid = (int)rdr[0];
retrievedUser.name = rdr[1].ToString();
... add the other fields
myUsers.Add(retrievedUser);
}
//close db connection
return myUsers
}
In my Controller
//call my database class
CodeDB() DB = new CodeDB()
[HttpGet]
public ActionResult getAll()
{
List<UserModel> viewUsers = DB.getUsers();
ViewBag.users = viewUsers
return View();
}
in the view
#{
if(Viewbag.users != null)
{
foreach(UserApp.Models.UserModel u in ViewBag.users)
{
#Html.Raw( " userID : " + u.userid +" Gender : " + u.gender)
}
}
}
I think you could do. MVC Scaffolding of Crud with there Views Auto Generated
When you make your controller There's an option "MVC Controller with Views"
Then it will ask For your Model that you want to use for scaffolding which will be
"UserModel" Then just give your Controller a Name.
Now if you look at the Index View of your Controller it will have all the attributes you want and don't want.But of course, you can remove the unnecessary attributes
Hope this helps!

MVC 5 Multiple Models

Is it possible to have multiple #Model functions within one page?
I have a Views/Shared/_layout.cshtml page which has the following code to pull the navigation from an SQL Server 2012 database:
#model IEnumerable<WebApplication1.navigation_V>
<ul class="nav sf-menu clearfix">
#foreach (var item in Model) {
<li>#Html.MenuItem(item.title_TV, item.url_TV, "Home")</li>
}
</ul>
This works fine on all views within the Views/Home folder, however the View/Accounts/Login.cshtml file has the following code:
#model WebApplication1.Models.LoginViewModel
Now I get the following error when trying to view the Account/Login page:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[WebApplication1.navigation_V]', but this dictionary requires a model item of type 'WebApplication1.Models.LoginViewModel'.
When writing the code I am not getting any red underline squiggles, the error only fires when trying to access the Account/Login page. This navigation function must be viewable on all pages, what I'm dreading next is actually getting the rest of the page content from the database in to these pages.
Any help would be much appreciated :-)
For further information I have included more code.
WebApplication1Entities.cs
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
namespace WebApplication1
{
public partial class WebApplication1Entities : DbContext
{
public WebApplication1Entities()
: base("name=WebApplication1Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<navigation_V> navigation_V { get; set; }
}
}
navigation_V.cs
using System;
using System.Collections.Generic;
namespace WebApplication1
{
public partial class navigation_V
{
public int navigation_ID { get; set; }
public string title_TV { get; set; }
public string url_TV { get; set; }
}
}
Controllers/HomeController.cs:
public static class MenuExtensions
{
public static MvcHtmlString MenuItem(
this HtmlHelper htmlHelper,
string text,
string action,
string controller
)
{
var li = new TagBuilder("li");
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.GetRequiredString("action");
var currentController = routeData.GetRequiredString("controller");
if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
{
li.AddCssClass("active");
}
li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
return MvcHtmlString.Create(li.ToString());
}
}
namespace WebApplication1.Controllers
{
public class HomeController : Controller
{
private WebApplication1Entities db = new WebApplication1Entities();
public ActionResult Index()
{
return View(db.navigation_V.ToList());
}
}
}
Views/Shared/Layout.cshtml
#model IEnumerable<WebApplication1.navigation_V>
<ul class="nav sf-menu clearfix">
#foreach (var item in Model) {
<li>#Html.MenuItem(item.title_TV, item.url_TV, "Home")</li>
}
</ul>
I hope this make things a little clearer.
Instead of rendering navigation IEnumerable in layout you can write child action in your Home controller like this:
[ChildActionOnly]
public ActionResult Navigation()
{
var navigationModel = ..
// your code to retrieve IEnumerable<WebApplication1.navigation_V>
// from DB
return View(navigationModel);
}
View for this action is Views/Home/Navigation.cshtml:
#{ Layout = null; } // preventing recursive rendering
#model IEnumerable<WebApplication1.navigation_V>
<ul class="nav sf-menu clearfix">
#foreach (var item in Model) {
<li>#Html.MenuItem(item.title_TV, item.url_TV, "Home")</li>
}
</ul>
And code for _layout.cshtml, replace your old navigation code with this one:
#{ Html.RenderAction("Navigation", "Home"); }

How to pass a string array from controller to the view MVC4 without creating multiple actionresults?

I am new to mvc4 so please go easy, i am trying to pass multiple names of destinations from the controller to my view. How can i do this without creating more actionresults and objects. I want to create a table with the destination names using a string array. Is this possible any help would be appreciated. Thank You in advance.
Controller:
public ActionResult Destinations()
{
string[] arrivalAirport = new string[4] { "london", "paris", "berlin",
"manchester" };
Destination dest = new Destination();
dest.arrivalName = arrivalAirport[2];
return View(dest);
}
Model:
public class Destination
{
public string arrivalName { get; set; }
public string arrivalCode { get; set; }
}
View:
#model Flight.Models.Destination
#{
ViewBag.Title = "Destinations";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<table>
<tr>
<td>#Html.Label("Arrival Name")</td>
<td>#Model.arrivalName</td>
</tr>
</table>
The wording of your question is very confusing, but it sounds like you want to pass multiple Destination objects to your view. If that's the case, just pass multiple destination objects to your view.
Controller:
public ActionResult Destinations()
{
string[] arrivalAirport = new string[4] { "london", "paris", "berlin",
"manchester" };
var airports = new List<Destination>();
foreach( var airport in arrivalAirport )
{
airports.Add( new Destination() { arrivalName = airport } );
}
return View(airports);
}
View:
#model List<Flight.Models.Destination>
<table>
#foreach( var dest in Model )
{
<tr>
<td>Arrival Name</td>
<td>#dest.arrivalName</td>
</tr>
}
</table>
use a view model where you can define whatever information you need for your view
public class ViewModel{
public List<string> Airports { get; set; }
public Destination destination { get; set; }
etc...
}
then on your controller you populate the view model
public ActionResult Index(){
ViewModel vm = new ViewModel();
var db = //query your database
vm.Destination.arrivalName = db.ArrivalName;
etc...
return View(vm);
}
and on your view
#model ViewModel
#Html.TextBoxFor(x => x.Destination.arrivalName)
Hopefully this helps

Displaying one object value (from a collection) in a label

I am learning MVC4. I could display records in a tabular format using foreach.
Now, I need to display theDescription of (only) first Topic object in a label. I need to do it without a foreach. How can we do it?
VIEW
#model MvcSampleApplication.Models.LabelDisplay
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
foreach (var item in Model.Topics.Select((model, index) => new { index, model }))
{
<div>#(item.index) --- #item.model.Description---- #item.model.Code</div> <div></div>
}
}
Controller Action
public ActionResult Index()
{
LabelDisplay model = new LabelDisplay();
Topic t = new Topic();
t.Description = "Computer";
t.Code=101;
Topic t3 = new Topic();
t3.Description = "Electrical";
t3.Code = 102;
model.Topics = new List<Topic>();
model.Topics.Add(t);
model.Topics.Add(t3);
return View(model);
}
Model
namespace MvcSampleApplication.Models
{
public class LabelDisplay
{
public List<Topic> Topics;
}
public class Topic
{
public string Description { get; set; }
public int Code { get; set; }
}
}
REFERENCE
Iterate through collection and print Index and Item in Razor
I need to display theDescription of (only) first Topic object in a label
Unless I totally misunderstood you, selecting the first item (only) in your view would look something like:
#if (Model.Topics.Any())
{
#Html.DisplayFor(x => x.Topics.First().Description)
}

EditorTemplate for collection property not used when calling EditorForModel (custom object template)

I am aware that complex types are not usually rendered when using EditorForModel but I am using a custom object template that does not do the check and calls Html.Editor for every property including complex types.
Unfortunately, whilst I can see the correct TemplateHint value for the property within the object template, the Editor call doesn't seem to use it and the built in collection template is used instead.
My object template is basically this:
#foreach (var property in ViewData.ModelMetadata.Properties.Where(x => x.ShowForEdit))
{
#Html.Editor(property.PropertyName)
}
If I force the use of the template by passing the name to the Editor call then the ModelMetadata is empty in the template.
Is this a bug / are there any workarounds?
Some more info:
So my view model contains the following:
[ACustomAttribute("Something")]
public IEnumerable<int> SelectedOptions { get; set; }
The attribute implements IMetadataAware and adds some stuff to the AdditionalValues Collection of the ModelMetadata as well as setting the TemplateHint. I can read this data from the object template but not from my custom template.
#foreach (var property in ViewData.ModelMetadata.Properties.Where(x => x.ShowForEdit))
{
if (!string.IsNullOrEmpty(property.TemplateHint))
{
#Html.Editor(property.PropertyName, property.TemplateHint)
}
else
{
#Html.Editor(property.PropertyName)
}
}
But please note that if you don't rely on the established conventions for resolving templates for complex collection types (a.k.a ~/Views/Shared/EditorTemplates/NameOfTheTypeOfCollectionElements.cshtml) and have used an UIHint on your collection property:
[UIHint("FooBar")]
public IEnumerable<FooViewModel> Foos { get; set; }
then the ~/Views/Shared/EditorTemplates/FooBar.cshtml editor template must be strongly typed to IEnumerable<FooViewModel> and not FooViewModel. So be careful, if this is your case, it's up to you to loop inside this custom template if you want to get to individual items of the collection. It will no longer be ASP.NET MVC that will automatically loop for you and invoke the editor template for each element.
UPDATE:
Still can't repro your issue.
Custom attribute:
public class ACustomAttribute : Attribute, IMetadataAware
{
private readonly string _templateHint;
public ACustomAttribute(string templateHint)
{
_templateHint = templateHint;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["foo"] = "bar";
metadata.TemplateHint = _templateHint;
}
}
Model:
public class MyViewModel
{
[ACustom("Something")]
public IEnumerable<int> Foos { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Foos = Enumerable.Range(1, 5)
};
return View(model);
}
}
View (~/Views/Home/Index.cshtml):
#model MyViewModel
#using (Html.BeginForm())
{
#Html.EditorForModel()
}
Editor template for the object type (~/Views/Shared/EditorTemplates/Object.cshtml):
#foreach (var property in ViewData.ModelMetadata.Properties.Where(x => x.ShowForEdit))
{
if (!string.IsNullOrEmpty(property.TemplateHint))
{
#Html.Editor(property.PropertyName, property.TemplateHint)
}
else
{
#Html.Editor(property.PropertyName)
}
}
Custom editor template (~/Views/Shared/EditorTemplates/Something.cshtml):
#model IEnumerable<int>
<h3>
#ViewData.ModelMetadata.AdditionalValues["foo"]
</h3>
#foreach (var item in Model)
{
<div>
#item
</div>
}
Result:
So as you can see the additional metadata we added is shown in the template.

Resources