The goal
Iterating between two queries within a single view.
The problem
In my application there is a comparison list of a specific product. At the top of the page, there is details of this product as its name, min/max price, photo and some other details.
What I need is something like this:
#modelComparisonList List<MyApp.Models.Products>
#modelProduct MyApp.Models.Products
#{
ViewBag.Title = "Comparing " + modelProduct.name;
}
<h1>There is #modelProduct.quantity products to compare</h1>
<table>
#foreach (var item in modelComparisonList)
{
<tr>
<p>#item.productName</p>
</tr>
<tr>
<p>#item.productPrice</p>
</tr>
<tr>
<p>#item.marketName</p>
</tr>
}
</table>
Can you understand my case?
I don't know how to perform a solution to resolve this. Can someone give me an idea?
Just make a wrapper class that contains both, ie simply:
public class TheViewModel
{
public List<MyApp.Models.Products> Item1 { get; set; }
public MyApp.Models.Products Item2 { get; set; }
}
Yes you can do it by using a view model. View models are there to represent your data on the view. Your view model can be a "concatenation" from multiple models.
Below is a couple of tips as well regarding your classes and properties.
Your product domain model will look like this:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string MarketName { get; set; }
public decimal Price { get; set; }
// Other properties not mentioned above
}
Your view model could look something like this:
public class ProductViewModel
{
public IEnumerable<Product> Products { get; set; }
public Product Product { get; set; }
}
Your action method could look something like this:
public ActionResult Compare(int id)
{
ProductViewModel viewModel = new ProductViewModel
{
Product = productRepository.GetBuId(id),
Products = productRepository.GetAll()
};
return View(viewModel);
}
And your view could look something like this:
#model YourProject.ViewModels.Products.ProductViewModel
#{
ViewBag.Title = "Comparing " + #Model.Product.Name;
}
<h1>There is #Model.Product.Quantity products to compare</h1>
<table>
#foreach (var product in Model.Products)
{
<tr>
<td>#product.Name</td>
</tr>
<tr>
<td>#product.Price</td>
</tr>
<tr>
<td>#product.MarketName</td>
</tr>
}
</table>
I hope this helps.
Related
Edit My view is using the Employer model. Employer and JobPosting have a 1:M relationship. I will share more of the view for context.
Context: In my application, I want to show the Employer the number of applicants who applied for their JobPosting. The code that I currently have written is not returning any value. It's not throwing any errors- but it's not working either. I'm pretty sure the issue is in my controller, but I'll provide the Model and View as well.
Controller:
public ActionResult AppCount()
{
foreach (var app in db.JobPostings.ToList())
{
int id = app.JobPostingID;
int count= db.Applications.Where(a => a.JobPostingID == id).Count();
app.AppCount = count;
ViewBag.AppCount = count;
}
return View();
}
View:
#model InTurn_Model.Employer
.
.
.
<h2>My Job Postings</h2>
<p>
#Html.ActionLink("Create New", "Create", "JobPostings", null, null)
</p>
<div id="employeeContainer"></div>
<table class="table table-striped">
<tr>
<th>Position</th>
<th>Job Type</th>
<th>Number of Applicatiosn</th>
<th></th>
</tr>
#foreach (var item in Model.JobPostings)
{
if (item.EmployerID == Model.EmployerID)
{
<tr>
<td>
#Html.DisplayFor(model => item.Position)
</td>
<td>
#Html.DisplayFor(model => item.JobType)
</td>
<td>#ViewBag.AppCount</td>
<td>#Html.ActionLink("Details", "Details", "JobPostings", new { id = item.JobPostingID }, null) </td>
</tr>
}
}
</table>
Model:
[MetadataType(typeof(JobPostingMetaData))]
public partial class JobPosting
{
public int AppCount { get; set; }
private sealed class JobPostingMetaData
{
[Display(Name = "Job Posting ID")]
public int JobPostingID { get; set; }
[Display(Name = "Employer ID")]
public int EmployerID { get; set; }
[Display(Name = "Description")]
public string Desc { get; set; }
[Display(Name = "Job Type")]
public JobType JobType { get; set; }
[Display(Name = "Employment Type")]
public TimeType TimeType { get; set; }
[DataType(DataType.Currency)]
public decimal Wage { get; set; }
}
}
There are two problems that I see.
First, you are not passing Model from controller to view. However, you are iterating through Model.JobPostings. It is empty.
Second, you assign ViewBag.AppCount in the loop. So, all values, except for the last one are lost. But if you fix the first problem (use Model instead of ViewBag) - the second might go away by itself.
You need to specify the model in the view with #model:
#model YourNameSpace.JobPosting
Then return that model to the view:
public ActionResult AppCount()
{
foreach (var app in db.JobPostings.ToList())
{
int id = app.JobPostingID;
int count= db.Applications.Where(a => a.JobPostingID == id).Count();
app.AppCount = count;
ViewBag.AppCount = count;
}
return View(app);
}
This will make the values in the model available to the view. There is no need to use ViewBag, as AppCount is part of the model.
I was overthinking this. I just needed to set this up from the JobPosting model, and then the rest worked, I didn't need to iterate through the Controller at all.
public int AppCount => Applications.Count;
I'm trying to develop an application using Asp.net C#, MVC, Codefirst approach.
I have two classes as Actors and Movies, which has many to many relationships. (An actor can have many movies, a movie can have many actors)
Now i'm facing a problem, I can retrieve data from both tables but not as expected, I believe something is going wrong at somewhere with the logic of my code.
For instance, I can retrieve a list of movies from database and when i click on each movie it redirects me to the page that belongs to that particular movie which makes sense up to this point, but now i want to retrieve the list of actors that has played role in this particular movie and here i fail. (I can retrieve the whole list of actors that exist in database but not the particular actors that has played role in a particular movie).
These are my models:
This is the Actor Class:
public class Actors
{
public int Id { get; set; }
public string Actor_Name { get; set; }
public string Country { get; set; }
public virtual ICollection<Movies> mvzz { get; set; }
}
And this is the movies class:
public class Movies
{
public int Id { get; set; }
public string Movie_title { get; set; }
public string genre { get; set; }
public virtual ICollection<Actors> actzz { get; set; }
}
This is the controller:
public ActionResult Index()
{
var mvz = _context.mvz;
return View(mvz);
}
public ActionResult Details(int? Id)
{
var movies_Detail = _context.mvz.Include(a=> a.actzz).SingleOrDefault(i=> i.Id==Id);
var actors = _context.act.ToList();
var ViewModel = new MoviesActorsViewModel()
{
Movies = movies_Detail,
Actors = actors
};
return View(ViewModel);
}
}
}
This is the Index View which shows the list of Movies and has a link for the details of each movie individually:
#model IEnumerable<mtmmmmmm.Models.Movies>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<table class="table table-bordered table-hover table-responsive">
#foreach (var mvz in Model)
{
<tbody>
<tr>
<td>#mvz.Id</td>
<td>#Html.ActionLink(mvz.Movie_title, "Details","Movies", new { Id = mvz.Id },null)</td>
</tr>
</tbody>
}
This is the the details view that has to shows the detailed information of of each movie, very particularly It has to show the list of Actors that has played role in that particular movie.
#model mtmmmmmm.ViewModel.MoviesActorsViewModel
#{
ViewBag.Title = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>The list of Actors that has played role in #Model.Movies.Movie_title</h2>
<table class="table table-bordered table-hover table-responsive">
#foreach (var actors in Model.Actors)
{
<tbody>
<tr>
<td>#actors.Id</td>
<td>#actors.Actor_Name</td>
<td>#actors.Country</td>
</tr>
</tbody>
}
And Finally this is the View Model:
public class MoviesActorsViewModel
{
public List<Actors> Actors { get; set; }
public Movies Movies { get; set; }
public MoviesActorsViewModel()
{
Actors = new List<Actors>();
Movies = new Movies();
}
}
I know that something is wrong with the LINQ logic that i'm writing to retrieve the list of actors in the controller class.
If anyone having expertise in this regard is reading this post, Kindly guide me with the correct logic that i should use for LINQ or any other apporach that helps me get the result.
Many thanks in advance for taking your time and reading this post.
I think you need to change
var actors = _context.act.ToList();
to
var actors = movies_Detail.actzz.ToList();
I'm trying to build a teacher recommendation web app using sessions for lab, and have gotten to a particular point where I need to view the recommendations that a particular teacher has.
app
When I click on the number of recommendations, it should take me to a view that lists all the recommendations that particular person has, but instead I get an error page saying
'Lab3Models.Models.Person' does not contain a definition for 'Rating'
Here's some of my code, hopefully someone can point me in the right direction.
Recommendation Controller
using Lab3Models.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Lab3Models.Controllers
{
public class RecommendationController : Controller
{
private static IDictionary<string, Person> _people = null;
public ActionResult Add(string id)
{
if (Session["people"] != null)
{
_people = (Dictionary<string, Person>)Session["people"];
}
else
{
_people = new Dictionary<string, Person>();
Session["people"] = _people;
}
return View(_people[id]);
}
[HttpPost]
public ActionResult Create(string personId, Recommendation recommendation)
{
if (personId == null)
{
return HttpNotFound("Error, ID not found");
}
else
{ _people[personId].Recommendations.Add(recommendation);
return RedirectToAction("Index", "Home");
}
}
public ActionResult Show(string id)
{
if (Session["people"] != null)
{
_people = (Dictionary<string, Person>)Session["people"];
}
else
{
_people = new Dictionary<string, Person>();
Session["people"] = _people;
}
return View(_people);
}
}
}
Person & Recommendation Models
public class Person
{
public string Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public ICollection<Recommendation> Recommendations { get; set; }
public Person()
{
Recommendations = new List<Recommendation>();
}
public int NumberOfRecommendations
{
get
{
return Recommendations.Count;
}
}
public class Recommendation
{
public string Id { get; set; }
public int Rating { get; set; }
public string Narrative { get; set; }
public string RecommenderName { get; set; }
public Person ThePerson { get; set; }
}
}
When I put #model IDictionary<string, Lab3Models.Models.Person> in the top of my Show I get the error message 'Person' does not contain a definition for 'Rating' and no extension method 'Rating' accepting a first argument of type 'Person' could be found
If I put #model IDictionary<string, Lab3Models.Models.Recommendation> in the top of my view I get the error message ERROR
If anyone could help me out, it'd be greatly appreciated.
EDIT
#model IDictionary<string, Lab3Models.Models.Recommendation>
#{
ViewBag.Title = "Show";
}
<h2>Show</h2>
<table class="table">
<tr>
<th>
...
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#item.Value.Id
</td>
<td>
#item.Value.Rating
</td>
<td>
#item.Value.Narrative
</td>
<td>
#item.Value.RecommenderName
</td>
<td>
Delete |
</td>
</tr>
}
</table>
EDIT 2
I have #model IDictionary<string, Lab3Models.Models.Recommendation> at the top of my view and have changed the code in my view to look like this:
#foreach (var item in Model)
{
foreach (var rec in item.Recommendations)
{
var rating = rec.Rating;
var narr = rec.Narrative;
...
<tr>
<td>#rating</td>
<td>#narr</td>
<td>#recName</td>
<td>
Delete
</td>
</tr>
}
}
But I'm getting errors in my code specifically on Model in this statement #foreach (var item in Model) and on Value in the delete link. #item.Value.Id When I load the view, I get an error saying
'KeyValuePair' does not contain a definition for 'Recommendations' and no extension method 'Recommendations' accepting a first argument of type 'KeyValuePair'
Did I goof up somewhere logically?
You do want to use #model IDictionary, as that's the type you are using. The issue is that you are getting a type Person out of the dictionary, and attempting to display rating directly from that type. Without seeing your front-end code I can't pinpoint exactly how the issue is presenting, but can tell you what your issue is. Essentially, you are attempting to get the Rating property from the person object, but the Rating property is part of the Person object's Recommendation Collection.
I'm assuming here that you are iterating through each Person in the dictionary to build out the display. You also need to iterate through each Recommendation for each person if you want to access the Rating.
roughly
foreach(var person in #model) {
//person specific display things
foreach(var recommendation in person.Recommendations) {
var rating = recommendation.Rating;
// display rating things
}
}
I'm still working on my asp.net app. I have a page where orders table is displayed and i would like to include "details"column, so someone can choose order and then look up it's details.
Here is my View code:
<table id="example" class="table table-striped table-bordered" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Seat</th>
<th>Movie</th>
<th>Date</th>
<th>Details</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.OrderList.results)
{
<tr>
<td>#item.objectId</td>
<td>#item.Seat</td>
<td>LOTR</td>
<td>#item.createdAt</td>
<td>Details</td>
</tr>
}
</tbody>
</table>
Ofcourse Url.Action is just for testing. Here is my controller method:
public ActionResult Details(OrderModel model)
{
return View(model);
}
Results is a List of OrderModel objects. I'd like to pass one OrderModel object that corresponds with chosen table row. The whole point is to display OrderModel object contents on Details page. Can someone explain me how to do that?
EDIT: My model:
OrderModel
public class OrderModel
{
/*class representing Order data*/
public string Seat { get; set; }
public string objectId { get; set; }
public DateTime? createdAt { get; set; }
public DateTime? updatedAt { get; set; }
}
My root for ordermodel(needed for json deserialization to list of objects)
public class OrderRootModel
{
public List<OrderModel> results { get; set; }
}
My baseviewmodel orderlist line(viewmodel is shared along all sites - i'm using shared layout):
public OrderRootModel OrderList { get; set; }
EDIT2:
Alright so after looking at my code i modified it, so Details page recieves BaseViewModel instead of ordermodel(i'm using shared layout).
BaseViewModel:
public class BaseViewModel
{
public OrderModel Order { get; set; }
public OrderRootModel OrderList { get; set; }
}
OrdersController:
public ActionResult Details(OrderModel order)
{
BaseViewModel model = new BaseViewModel();
model.Order = order;
return View(model);
}
Alright guys. I think i didn't get enough sleep so my thought process was a little bit off. As #user1672994 suggested i can just pass order id to details view(if i remember right passing whole object between view and controller is not recommended).
So if anyone is interested here is a solution:
View:
#foreach (var item in Model.OrderList.results)
{
<tr>
<td>#item.objectId</td>
<td>#item.Seat</td>
<td>LOTR</td>
<td>#item.createdAt</td>
<td>Details</td>
</tr>
}
Controller:
public ActionResult Details(string id)
{
ApiModel data = new ApiModel();
BaseViewModel model = new BaseViewModel();
model.Order = data.GetOrderData(id);
return View(model);
}
Model:
public OrderModel GetOrderData(string id)
{
OrderModel model = new OrderModel();
string url = "https://api.parse.com/1/classes/Orders" + "/" + id;
model = JsonConvert.DeserializeObject<OrderModel>(getParseIdData(url));
return model;
}
It works perfect. Thank you guys.
Pretty new to MVC and the like. I have a class the looks like this:
public class SomeExampleModel
{
public int Id { get; private set; }
public string Name { get; private set;}
public string Street { get; private set; }
public IList<Contact> Contacts { get; private set; }
...
}
Where Contact looks like:
public class Contact
{
public int Id { get; private set; }
public int SomeExampleModelId { get; private set; }
public ContactType Type { get; private set; }
public string ContactValue { get; private set; }
...
}
Now the problem is, I have a Post Create action and Create.cshtml view to add new SomeExampleModel to my database. It works great for all the basic properties, but there isn't anything for the Contacts property (which is a separate table in the database).
How would I be able to add contacts (single for now, plural in the future) using forms on my view?
EDIT: I am sorry if I was not clear. The problem is not getting data to save in the database correctly. I have tested that already and it works fine if I just manually insert a SomeExampleModel record into the database with the SomeExampleContext. What I dont know is how to draft my View so that it allows users to add Contacts to the record
Here is one approach using an EditorTemplate. I have made minor changes to your model classes (this works; however, note that this is only for you to understand the concept. You can extend upon this)
Models
public class SomeExampleModel
{
public int Id { get; set; }
public string Name { get; set;}
public string Street { get; set; }
public IList<Contact> Contacts { get; set; }
}
public class Contact
{
public int Id { get; set; }
public int SomeExampleModelId { get; set; }
public ContactType Type { get; set; }
public string ContactText { get { return Type.ToString(); } }
public string ContactValue { get; set; }
}
public enum ContactType
{
email,
Phone,
mobile,
fax
}
Make a note that I've created a property ContactText that returns the enum text (for display purposes)
Create a editor template for Contact (named Contact.cshtml; Template name must match the class name). Find below the screen shot on where to place your editor template.
Here is the code for Contact.cshtml
#model Test1.Models.Contact
<table>
#Html.HiddenFor(a=>a.Type)
<tr>
<td>#Html.Label(Model.ContactText)</td>
<td>#Html.TextBoxFor(a => a.ContactValue)</td>
</tr>
</table>
Here is the code for the 'Create' view (ExampleCreateView.cshtml in my case)
#model Test1.Models.SomeExampleModel
#{
ViewBag.Title = "ExampleCreateView";
}
<h2>ExampleCreateView</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>SomeExampleModel</legend>
#Html.HiddenFor(model=>model.Id)
<table>
<tr>
<td>#Html.LabelFor(model=>model.Name)</td>
<td>#Html.EditorFor(model=>model.Name)</td>
</tr>
<tr>
<td>#Html.LabelFor(model=>model.Street)</td>
<td>#Html.EditorFor(model=>model.Street)</td>
</tr>
<tr>
<td>#Html.LabelFor(model=>model.Contacts)</td>
<td>#Html.EditorFor(model=>model.Contacts)</td>
</tr>
</table>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Make a note on how I've used #Html.EditorFor for the Contacts property.
Here is how the Get, Post actions will look like
public ActionResult ExampleCreateView()
{
SomeExampleModel model = new SomeExampleModel();
Contact contactEmail = new Contact();
contactEmail.Type = ContactType.email;
Contact contactFax = new Contact();
contactFax.Type = ContactType.fax;
Contact contactPhone = new Contact();
contactPhone.Type = ContactType.Phone;
Contact contactMobile = new Contact();
contactMobile.Type = ContactType.mobile;
List<Contact> contacts = new List<Contact>();
contacts.Add(contactEmail);
contacts.Add(contactFax);
contacts.Add(contactPhone);
contacts.Add(contactMobile);
model.Contacts = contacts;
return View(model);
}
[HttpPost]
public ActionResult ExampleCreateView(SomeExampleModel model)
{
//Your operations
return View(model);
}
Run the application. This is how the view looks like
Screen shot of what you will get in the POST action
The way I would do it is to have two separate actions - one that does the initial create of SomeExampleModel, and a separate action for adding a Contact to that model.
That way your create SomeExampleModel view would just have Name and street, and when it saved you would show a readonly version of the SomeExampleModel . The readonly version of SomeExampleModel would list all related contacts in a table below the Name and Street, with an edit and delete link, and an 'add new' contact link under the table
e.g.
<table>
#foreach (var contact in Model.Contacts)
{
<tr>
<td>#contact.ContactType</td>
<td>#contact.ContactValue</td>
<td>#Html.Action("Edit", "Edit", "Contact", new { id = contact.Id }</td>
<td>#Html.Action("Delete", "Delete", "Contact", { id = contact.Id }</td>
</tr>
}
</table>
#Html.Action("Add new contact", "Add", "Contact" new { id = Model.Id }
Initially, there would be no contacts listed, then later you would have multiple contacts.