I am new to mvc and cannot figure out how to pass a single column of data to the view.
I have connected my db with ado.net entity model to models.
Then in my controller I have :
public class HomeController : Controller
{
shdesignEntities2 _db;
public ActionResult Index()
{
_db = new shdesignEntities2();
ViewData.Model = _db.tblKategoris.ToList();
return View();
}
}
In the view :
#foreach(var m in ViewData.Model)
{
<p>Kategori Ad :</p><p> #m.kategori_ad </p>
}
When I do like this , I pass the whole table data to the view where I only need a single column of information.
How can I only pass data from the column kategori_ad ?
Use Select:
ViewData.Model = _db.tblKategoris.Select(x => x.kategori_ad).ToList();
You can use LINQ to find the object that you want and then pass it to the view, do something like this:
public ActionResult Index()
{
_db = new shdesignEntities2();
ViewData.Model = _db.tblKategoris.Select(x => x.kategori_ad).ToList();
return View();
}
That way ViewData.Model only has the object that matches the linq query.
Here you can find more about Linq to retrieve data from a collection in C#: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
In Controller
ViewData["Rows"] = (from c in _db.tblKategoris
select c.kategori_ad).ToList();
View
#foreach(var m in (List<string>)ViewData["Rows"])
{
<p>Kategori Ad :</p><p> #m </p>
}
You may look at ViewModels. Also by this way you can use smaller part of data exposed.
For example
public class KategoriViewModel
{
public IEnumerable<Kategori> Kategoriler { get; set; }
}
Then you should add a controller action like
public ActionResult Something()
{
var model = new KategoriViewModel;
model.Kategoriler = your query..;
return View(model);
}
In view
#model KategoriViewModel
#foreach(var m in ViewData.Model)
{
<p>Kategori Ad :</p><p> #m.kategori_ad </p>
}
Related
I am in the habit of using nested loops in classic. Data from the first record set is passed to the second record set. How would I accomplish the same thing in MVC? As far as I can tell, I can only have one model passed to my view.
<%
rs.open "{Call usp_SalesOrder}",oConn
Do While (NOT rs.EOF)
%>
<div><% = rs("SalesOrderNumber")%></div>
<%
rs2.open "{Call usp_SalesOrderLines(" & rs("SOKey") & ")}",oConn
Do While (NOT rs.EOF)
%>
<div><% = rs2("SalesOrderLineNumber")%></div>
<%
rs2.MoveNext
Loop
rs2.close
%>
<%
rs.MoveNext
Loop
rs.close
%>
My suggestion would be to build a more robust model. It is true that you can only pass one model to your view, but your model can contain the results of multiple data sets, provided you have gathered those data sets in your controller and assigned them to the model.
I also suggest staying away from the ViewBag. It's an easy trap to fall into. Trust me when I say you'll regret it later.
For your example, maybe a model defined like this:
public class MyModel
{
public List<SalesOrder> SalesOrders = new List<SalesOrder>();
}
public class SalesOrder
{
public string SOKey = string.Empty;
public List<SalesOrderLine> SalesOrderLines = new List<SalesOrderLine>();
}
And the code to populate the sales orders in the controller:
public Action Index()
{
MyModel model = new MyModel();
model.SalesOrders.AddRange(CallUspSalesOrder());
foreach (SalesOrder salesOrder in model.SalesOrders)
{
salesOrder.SalesOrderLines.AddRange(CallUspSalesOrderLines(salesOrder.SOKey));
}
return View(model);
}
That way, you have access to all sales orders (and their sales order lines) within the view.
I would say that Nathan's post is a good start. Here is what I would do from beginning to end.
This is how I would do my model:
public class SalesOrderModel
{
public List<SalesOrderLines> SOLines = new List<SalesOrderLines>();
public List<SalesOrder> SOHeader = new List<SalesOrder>();
}
My Controller would then do this:
public ActionResult Index()
{
List<SalesOrder> SalesOrder = callSalesOrderUSP.ToList();
List<SalesOrderLines> SalesOrderLines = new List<SalesOrderLines>();
foreach (var thing in SalesOrder)
{
SalesOrderLines.AddRange(callSalesOrderLinesUSP(thing.SOKey).ToList());
}
SalesOrderModel salesOrderModel = new SalesOrderModel
{
SOHeader = SalesOrder,
SOLines = SalesOrderLines
};
return View(salesOrderModel);
}
Then in your view you can do this:
#foreach(var something in Model.SOHeader)
{
foreach (var thing in Model.SOLines.Where(i => i.SOKey == something.SOKey))
{
//display info here
}
}
You can use ViewBag to pass elements not relevant to your model. Also do not be afraid of creating your own ModelView objects that can work between your View and Controller. Your views should not be restricted to what your model has to offer.
Take a look at this for how you can implement a ViewModel in MVC.
And perhaps look at this to see how you can use ViewBag to pass values to your view, not relevant to your model.
I have a view that loads a record with a certain record number. Once the page is loaded, it gives the user an opportunity to login for additional information. Once the login logic is performed, I need to return to that same view with the same record number intact. I am passing the record number to the action using a hidden input in the form. What I can't seem to figure out is how to return to that same view and provide it with that record #. The code I am trying below is not working. I know this is MVC 101 stuff but a hint in the right direction would be appreciated, or feel free to scrap my method and suggest something better!
Form in view:
<form action="/MyView/Authenticate/#item.ID" method="post" enctype="multipart/form-data">
<input name="form_id" type="hidden" value="#item.ID">
.....
Form action:
[HttpPost]
public ActionResult Authenticate()
{
int myid = Convert.ToInt16(Request["form_id"]);
.....
return View("Index", new { id = myid } );
}
EDIT:
It turns out that the correct view is being returned, but it is expecting a model item type of "JobSummaryModel" per the Index action result below. So the question I actually need answered is, how do I pass both the record id and this view model to it?
public ActionResult Index(int id = 0)
{
List<JobSummaryModel> jdata;
ViewBag.IsResults = false;
if (id != 0)
{
ViewBag.IsResults = true;
}
jdata = db.Jobs.Where(c => c.ID == id).Select(c => new JobSummaryModel() { ID = c.ID, Name = c.Name, City = c.City, PostalCode = c.PostalCode, JobDescription = c.PositionDescription }).ToList();
return View(jdata);
}
EDIT:
Thanks Reddy, your suggestions worked! My only remaining issue is that when I return to my Index view from the Authenticate action, I do not seem to have my "jdata". Is my Index action result not being rerun when I return the Index view via my Authenticate action? I am coming from a web forms background where, in an instance like this, the Load/Init events would automatically run when a form is loaded. Do I need to bind my "jdata" in the Authenticate action and include it in the viewmodel?
EDIT: Resolved. Changed my "return View" to a "return RedirectToAction" to resolve my final issue. Thanks everyone!
Answer For your after Edit:
All you want to pass to view is a int Id and your List<JobSummaryModel> jdata right?
So create a ViewModel JObSummaryModelHelper
Public class JObSummaryModelHelper
{
public int Id {get;set;}
public List<JobSummaryModel> jdata {get;set;}
}
Now in your controller
public ActionResult Index(int id = 0)
{
JObSummaryModelHelper jobDetails = new JObSummaryModelHelper();
jobDetails.Id = id;
ViewBag.IsResults = false;
if (id != 0)
{
ViewBag.IsResults = true;
}
jobDetails .jdata = db.Jobs.Where(c => c.ID == id).Select(c => new JobSummaryModel() { ID = c.ID, Name = c.Name, City = c.City, PostalCode = c.PostalCode, JobDescription = c.PositionDescription }).ToList();
return View(jobDetails );
}
Now make sure your view is set to expect this new viewmodel
#model JObSummaryModelHelper
carry on with your manipulation......
You are better off creating a ViewModel for this like so:
Create a View Model class i.e.
public class AuthViewModel
{
public int MyId { get; set; }
}
In your View put the following directive at the top:
#model AuthViewModel
In your initial [HttpGet] method return the view model:
[HttpGet]
public ActionResult Authenticate()
{
var model = new AuthViewModel { MyId = 123 };
return View("Index", model );
}
It's best to use Html helpers in your view, so you can change it to this:
#using(Html.BeginForm()
{
#Html.HiddenFor(m => m.MyId)
...
}
The above uses naming conventions to post back to the action that you are on.
Then return it to your view like this:
[HttpPost]
public ActionResult Authenticate(AuthViewModel model)
{
int myid = model.MyId;
return View("Index", model );
}
Then you can output using this razor syntax #Model.MyId
It's really worth doing some tutorials to learn the conventions, a small amount of time invested in this will save you a lot of time in the future.
Instead of
return View("Index", new { id = myid } );
could you do
return Index(myid);
So I created a project to test DI in MVC 4. Yeah, that was the easy part. I have a controller that looks like this.
public class CompanyManagementController : Controller
{
private ICompanyService companyService;
public CompanyManagementController(ICompanyService companyService)
{
this.companyService = companyService;
}
public ActionResult Index()
{
return View(companyService.GetCurrentCompanies());
}
}
What I can't figure out is how to tell the view Index.cshtml that I have this List that I am returning to it. When I have just a POCO it's easy. I did this
[HttpGet]
public ActionResult Create()
{
var company = new Company();
return View(company);
}
[HttpPost]
public ActionResult Create(Company company)
{
using(var context = new InventoryContext())
{
context.Companies.Add(company);
context.SaveChanges();
}
return View("Create");
}
That was super easy because I just said
#model MvcInventoryManager.Models.Company
in the Create.cshtml file.
Any hints? What I want to do is be able to loop through the list of companies that get returned.
Thanks!
What is the return type of companyService.GetCurrentCompanies()? That would be the type you'd want to use for binding the Model in the view. For example, if the type is IEnumerable<Company> then in your view you would declare this:
#model IEnumerable<MvcInventoryManager.Models.Company>
That way the type of the Model property would match what's being passed to the view and you could loop through the Model:
foreach (var company in Model)
after declaring your model in the view just loop through it like so:
#foreach (var company in Model)
{
Html.DisplayFor(modelItem => company.companyID)
Html.DisplayFor(modelItem => company.CompanyName)
}
It is said that the models should be fat and the Views should be thin.We put our business logic inside the Model (https://stackoverflow.com/questions/235233/asp-net-mvc-should-business-logic-exist-in-controllers).We normally write the LINQ inside the controller,but is it possible that we should write the query in models,If yes then how we will get the results in the View?
Second Question
public ActionResult Index()
{
using (NORTHWNDEntities c = new NORTHWNDEntities())
{
var x = c.Employees.Count();
ViewData["count"] = x;
return View(x);
}
}
When we do this are we passing the variable x to the View?
I tried to access the ViewData in View
<% ViewData["count"] %>
But it gives an error error ,Anyone who can help me with this
Thanks
If you are trying to display the value of ViewData["count"] in your view, you can use the following syntax:
<%= ViewData["count"] %>
Note the = in the opening tag. This is the equivalent of
<% Response.Write(ViewData["count"]) %>
there is better approach for doing this.and is very straight forward.create a Model that meets your needs and pass it to view.
public class MyModel
{
public int Count{get;set;}
}
and your controller can looks like
public ActionResult Index()
{
using (NORTHWNDEntities c = new NORTHWNDEntities())
{
var x = c.Employees.Count();
var model = new MyModel{Count = x};
return View(model);
}
}
and then create an strongly typed view
Razor Syntax :
#model MyModel
#Model.Count
ASPX syntax :
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.MyModel>" %>
<%= Model.Count %>
and the code can get even better if you do the following:
public class EmployeeService
{
public int GetEmployeeCount()
{
using (NORTHWNDEntities c = new NORTHWNDEntities())
{
var count = c.Employees.Count();
return count;
}
}
}
and the controller most change as well:
public ActionResult Index()
{
EmployeeService srvc = new EmployeeService();
var x = srvc.GetEmployeeCount();
var model = new MyModel{Count = x};
return View(model);
}
The query have to be into the Data Access Layer and the logic in MVC is into the Controller, not into the Model.
Here you can find an example of a layered architecture with MVC.
At the end you have always to use a Model into the View, don't pass data using the ViewData.
I am trying to get started learning MVC. I built the MVC Music Store project that I found on the Microsoft site. http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-1.
I got it working pretty well but I ran into trouble when I tried to modified it. I want to put the data in a separate project. I used Linq to Entities for the data access.
Here is my class to access the data
public class clsUtilities
{
Utilities.MVCMusicStoreEntities db = new Utilities.MVCMusicStoreEntities();
public object GetAlbums(string GenreName)
{
var query = from tags in db.vieAlbumArtists
where tags.GenreName.Equals(GenreName)
select tags;
return query;
}
}
In my Controller my code is
public ActionResult Browse2(string genre)
{
// retrieve Genre and its associated albums from the database
var genreModel = mcloUtilities.GetAlbums(genre);
return View(genreModel);
}
I generate a cshtml file in my view
#model Utilities.vieAlbumArtist
#{
ViewBag.Title = "Browse2";
}
This all compiles ok but when I run it I get:
The model item passed into the dictionary is of type System.Data.Objects.ObjectQuery'1[Utilities.vieAlbumArtist], but this dictionary requires a model item of type Utilities.vieAlbumArtist.
Change
#model Utilities.vieAlbumArtist
to
#model IEnumerable<Utilities.vieAlbumArtist>
You are returning a list of vieAlbumArtist, not just a single instance.
You might also want to change
public object GetAlbums(string GenreName)
to
public IEnumerable<Utilities.vieAlbumArtist> GetAlbums(string GenreName)
Passing objects around is not the best idea.
This is your problem:
public object GetAlbums(string GenreName)
You're returning the data as an object. But the view expects to receive an item of type Utilities.vieAlbumArtist. Either change the GetAlbums() method to return the appropriate type, or make sure you cast it in the controller to the type the view is expecting.
I was able to solve this with the help of the hints you guys gave me.
From clsUtilies
public class clsUtilities
{
Utilities.MVCMusicStoreEntities db = new Utilities.MVCMusicStoreEntities();
public IEnumerable<Utilities.vieAlbumArtist> GetAlbums(string GenreName)
{
IEnumerable<vieAlbumArtist> query = from tags in db.vieAlbumArtists
where tags.GenreName.Equals(GenreName)
select tags;
foreach (var n in query)
{
}
return query;
}
From Controller
public ActionResult Browse2(string genre)
{
// retrieve Genre and its associated albums from the database
var genreModel = mcloUtilities.GetAlbums(genre);
return View(genreModel );
}
From Views
#model IEnumerable< Utilities.vieAlbumArtist>
#{
ViewBag.Title = "Browse Albums";
}
#foreach(var album in Model)
{
<ul>
<a href="#Url.Action("Details", new { id=album.AlbumId})">
<img alt="#album.Title" src="#album.AlbumArtUrl" />
<span>#album.Title ( #album.Name ) </span> </a>
</ul>
}
}
To display a list of albums try this:
<ul>
#foreach(var item in vieAlbumArtist)
{
<li>item.Name</li> //Not sure if you actually have a name property
}
</ul>