I am currently working on an assignment at university from which I unfortunatly lost some code to not long ago.
In particular it is where I have specific products display to a specific store, the code I have is not working
at all for me now, help would be appreciated
I have a web service and a local database in place from which the web service brings in the product information
and the local information has the store data and the store grade data.
Here is the code that I have in place for it to display on the details view page.
#model Part1MVC.ViewModels.GradeProductVM
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset><legend>GradeProductVM</legend>
<div class="display-label">#Html.DisplayNameFor(model => model.Gradeid)</div>
<div class="display-field">#Html.DisplayFor(model => model.Gradeid)</div>
<div class="display-label">#Html.DisplayNameFor(model => model.GradeName)</div>
<div class="display-field">#Html.DisplayFor(model => model.GradeName)</div>
</fieldset>
<div>There are #Model.Products.Count products</div>
#foreach (var prod in Model.Products) { <div>#prod.ProductName</div>}
<p>#Html.ActionLink("Edit", "Edit", new { id=Model.Gradeid }) |
#Html.ActionLink("Back to List", "Index")</p>
// This is the code for service1.cs to get grades product
public List<PhysicalProduct> GetProductsForGrade(int gradeid){
var list = new List<PhysicalProduct>();
try {
using (var db = new ProductsEntities()) {
var q = from prod in db.PhysicalProducts
join pg in db.ProductToGrades on prod.ProductId equals pg.ProductId
where pg.StoreGradeId == gradeid
select prod;
return q.ToList();
}
}
catch (Exception ex) {
return null;
}
return list;
}
////This is the controller code
public ActionResult Details(int id){
Grade grade = db.Grade.SingleOrDefault(x => x.GradeId == id);
//var products = ServiceLayer.GetProducts();
var products = ServiceLayer.GetProductsForGrade(id);
var vm = new ViewModels.GradeProductVM(id, grade.Description, products);
return View(vm);
}
//This is the View model Code
public class GradeProductVM {
public int Gradeid { get; set; }
public string GradeName { get; set; }
public List<PhysicalProduct> Products { get; set; }
public GradeProductVM() {
}
public GradeProductVM(int gradeid, string name, List<PhysicalProduct> prods){
Gradeid = gradeid;
GradeName = name;
Products = prods;
}
}
I can get all the products that are currently in the database to display to every store but not specific products to specific stores.
Thanks
Please post the database table structure, seems the query join may be wrong.
Rest seems correct!
Related
So I have two models, Product and Review. The Product model contains a navigation property called Review as seen below:
Public class Product
{
[HiddenInput(DisplayValue=False])
public int ProductID {get; set;}
[Required]
public string ProductName {get; set;}
[HiddenInput(DisplayValue=False)
public ICollection<Reviews> {get; set;}
}
The the Review model:
public class Review
{
[HiddenInput(DisplayValue=false)]
public int ReviewId { get; set; }
[Required]
public int ProductID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Subject { get; set; }
[Required]
public string Body { get; set; }
}
I have an Action ViewResult method for ProductDetails where it fetches all Products plus all the reviews which has the same FK ProductIDs as seen here below:
public ViewResult ProductDetails(int productId)
{
Product product = repository.Products
.Include(p => p.Reviews)
.FirstOrDefault(p => p.ProductID == productId);
return View(product);
}
Then there is a View Which contains very simple HTML elements you can see it below:
#model app.models.Product
#Html.DisplayFor(model => model.ProductName)
#foreach (var review in Model.Reviews)
{
#Html.Partial("_Reviews", review)
}
Within above view I called for a partial view to render all reviews belong to that specific product. In the Partial view i have a form where the user can submit a review. I want the user to submit a review for the Product which the name is at the top of the view. I know i have to create an action for this but the only thing makes me uncomfortable with it is that i can't figure out how to get the ProductID of that specific Product.
Edit:
As per Stephen's answer I had to put the form Html elements into the main view which is ProducDetails and had put some scripts to call Json result to save data in the database.
Controller method to save the Review:
[HttpPost]
public JsonResult CreateReview (Review review)
{
if (review.ReviewId == 0)
{
db.Reviews.Add(review);
}
else
{
Review dbEntry = db.Reviews.Find(review.ReviewId);
if (dbEntry != null)
{
dbEntry.ProductID = review.ProductID;
dbEntry.Name = review.Name;
dbEntry.Subject = review.Subject;
dbEntry.Body = review.Body;
}
}
db.SaveChanges();
return Json(true);
}
You're wanting to create a new Review for the Product so the form needs to be in the main view, not the partial. The following assumes you want to submit using ajax and update the list of existing reviews
#model app.models.Product
#Html.DisplayFor(model => model.ProductName)
// display existing reviews
<div id="reviews">
#foreach (var review in Model.Reviews)
{
#Html.DisplayFor(m => review.Body)
}
</div>
<h2>Create new Review</h2>
#Html.Partial("_NewReview", new Review(){ ProductID = Model.ProductID })
Where _NewReview.cshtml is
#model Review
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.ProductID)
#Html.EditorFor(m => m.Name)
#Html.EditorFor(m => m.Subject)
#Html.TextAreaFor(m => m.Body)
<input id="create" type="submit" value="Create" />
}
and delete the _Reviews.cshtml file
Then in the main view, add the following script
var url = '#Url.Action("Create", "Review")';
var reviews = $('#reviews');
var form = $('form');
$('#create').click(function() {
$.post(url, form.serialize(), function(response) {
if (response) {
reviews.append($('#Body').val()); // add the new Review to the existing reviews
form.get(0).reset(); // reset the form controls
}
}).fail(function (result) {
// oops
});
return false; // cancel the default submit
});
which will submit to (in ReviewController)
[HttpPost]
public JsonResult Create(Review model)
{
// Save the model
return Json(true); // return something to indicate success
}
As i can imagine ProductId is unique
In Your Partial View you can Write your code inside Ajax.BeginForm
#model Review
#Ajax.BeginForm("ActionName", "ControllerName", new { productId = Model.ProductId }, #*AjaxOptions Attribute*#)
{
Review Fields here
<input type="submit" value="Submit Review"/>
}
To get the ProductID, you have add the ForeignKey of the Product Table in the Review Table.
public class Review
{
[HiddenInput(DisplayValue=false)]
public int ReviewId { get; set; }
[Required]
public int ProductID { get; set; }
[Required]
[ForeignKey("ProductID")]
publiv virtual Product {get;set;}
}
hope this helps
So the beginning of my View is
#foreach ( var G in ViewBag.GroupedBySec )
{
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<table class="table table-striped assessment-table">
<tbody>
<tr>
<td class="black-n-white" colspan="4">#G.Key</td>
</tr>
<tr>
<td>Section</td><td>Component</td><td>Completeness Level (0-100%)</td><td>Readines</td>
</tr>
#var GroupedBySubsection = G.GroupBy(x => x.SubsectionTitle);
#foreach ( var g in GroupedBySubsection )
{
#foreach ( var qa in g )
{
and I'm getting errors on the
#var GroupedBySubsection = G.GroupBy(x => x.SubsectionTitle);
#foreach ( var g in GroupedBySubsection )
lines which say
The name 'var' does not exist in the current context
and
The name 'GroupedBySection' does not exist in the current context
Any idea what I'm doing wrong?
Alternatively, any suggestions for how I can get a C# object that has the entire groupings and subgroupings so that I don't have to write all this crap in my View?
My Controller method for this page is like
[HttpGet]
public ActionResult Peek ( Guid pid )
{
ViewBag.PartnerId = pid;
List<AnswerInfo> AllAnswers = this._Db.GetAnswersByPartner(pid);
ViewBag.GroupedBySec = AllAnswers.GroupBy(A => A.SectionTitle);
return View();
}
Your error occurs because your missing the braces around your var statement. It should be
#{ var GroupedBySubsection = G.GroupBy(x => x.SubsectionTitle); }
This will then throw a different error because you referring an item in ViewBag which is dynamic so you need to cast it as follows
#{ var GroupedBySubsection = ((IEnumerable<yourModel>)G).GroupBy(x => x.SubsectionTitle); }
making your view even uglier.
how I can get a C# object that has the entire groupings and subgroupings so that I don't have to write all this crap in my View?
Use a view model. Based on some of your previous question, you have a data model which (abbreviated) is
public class Answer
{
public string Section { get; set; }
public string SubSection { get; set; }
public int QuestionID { get; set; }
public string QuestionText { get; set; }
....
}
And that you want to group it in the view by Section and then SubSection. Your view models would then be
public class SectionVM
{
public string Title{ get; set; }
public List<SubSectionVM> SubSections { get; set; }
}
public class SubSectionVM
{
public string Title { get; set; }
public List<QuestionVM> Questions { get; set; }
}
public class QuestionVM
{
public int QuestionID { get; set; }
public string QuestionText { get; set; }
....
}
Your controller code would then be
var answers = db.Answers..... // your previous query
List<SectionVM> model = answers.GroupBy(x => x.Section).Select(x => new SectionVM
{
Title = x.Key,
SubSections = x.GroupBy(y => y.SubSection).Select(y => new SubSectionVM
{
Title = y.Key,
Questions = y.Select(z => new QuestionVM
{
QuestionID = z.QuestionID,
QuestionText = z.QuestionText,
....
}).ToList()
}).ToList()
}).ToList();
return View(model);
and in the view
#model List<SectionVM>
#foreach(var section in Model)
{
<h2>#section.Title</h2>
foreach(var subSection in section.SubSections)
{
<h3>#subSection.Title</h3>
foreach(var question in subSection.Questions)
{
<p>#question.QuestionText</p>
....
}
}
}
Side note: I have made the collection properties List<T> assuming that you might want to also generate a form for editing the Questions/Answers and to do so you will need a for loop which required the collection to implement IList. Alternatively you could save the extra overhead of .ToList(), keep them asIEnumerableand use a customEditorTemplate` for each view model type.
For an example of how an edit view might look (using the for loop option), refer to this answer.
I'm new to asp.net mvc and I'm doing this exercise for myself.
I created an edmx from Northwind Database.
I created a controller:
public ActionResult Index(int id)
{
var model = new IndexViewModel();
using (var db = new ProductDB())
{
model.Products = from p in db.Products
orderby p.ProductName
select new IndexViewModel.InfoProduct
{
ProductName = p.ProductName,
QuantityPerUnit = p.QuantityPerUnit,
UnitPrice = p.UnitPrice
};
}
return View();
}
...the view:
#model aspTest.Models.IndexViewModel
#{
Layout = null;
}
...
<div> <ul>
#foreach (var p in Model.Products){
<li>#p.ProductName</li>
}
</ul>
</div>
...and the ViewModel:
public class IndexViewModel
{
public IEnumerable<InfoProduct> Products { get; set; }
public class InfoProduct
{
public string ProductName { get; set; }
}
}
But this error keeps on appearing in this part:
#foreach (var p in Model.Products){#p.ProductName
Sorry, I know this might be noobish to most of you.
You are declaring in your model that it will work with the IndexViewModel class as:
#model aspTest.Models.IndexViewModel
but you are sending nothing to the View from Controller as :
return View();
Try using:
return View(model);
The error is quite true, you are trying to iterate on properties (Products) of an object (IndexViewModel) which you don't provide.
Besides the fact that you return no ViewModel to your view and shout use return View(model); there is something else fishy with your code:
public class InfoProduct
{
public string ProductName { get; set; }
}
Your class InfoProduct only contains a Productname, yet you also assign a Quantity and Price property in your select clause, this won't compile.
model.Products = from p in db.Products
orderby p.ProductName
select new IndexViewModel.InfoProduct
{
ProductName = p.ProductName,
};
Lastly, materialize your data using .ToList()
public ActionResult Index(int id)
{
var model = new IndexViewModel();
using (var db = new ProductDB())
{
model.Products = (from p in db.Products
orderby p.ProductName
select new IndexViewModel.InfoProduct
{
ProductName = p.ProductName,
}).ToList();
return View(model);
}
}
I have two tables TxtComment and Login.
I am displaying image urls from Login table and comments from TxtComment table where username in TxtComment equals username in Login.
I am using Db First approach using entityframework.
How can I concatenate these columns from different tables to one common view? I used ViewBag. I got a result.
Controller
public ActionResult Item(int id)
{
FoodContext db = new FoodContext();
ViewBag.FoodItems = db.FoodItems.Where(row => row.itemid == id);
ViewBag.TxtComments = (from user in db.TxtComments
from ff in db.Logins
where ff.username == user.username
select new { imgurl = ff.imgurl, txtcmt = user.txtcmt });
return View();
}
View
#for(var item in ViewBag.TxtComments)
{
<div>#item</div>
}
The result is {imgurl=http:/sdfsdf,txtcmt=sfsdfsdf}
I need each item seperate. How can I? I tried with #item.imgurl, it says error. Is view bag is better? If not, please help me this need with strongly type view.
Create your own ViewModel instead of putting the model inside the ViewBag.
ViewModel:
public class ViewModel
{
public List<ImageComment> ImageComments { get; set; }
public ViewModel()
{
ImageComments = new List<ImageComment>();
}
}
public class ImageComment
{
public string ImageUrl { get; set; }
public string Comment { get; set; }
}
Controller Action:
public ViewResult Item(int id)
{
FoodContext db = new FoodContext();
List<ImageComment> comments = (from user in db.TxtComments
from ff in db.Logins
where ff.username == user.username
select new ImageComment
{
ImageUrl = ff.imgurl,
Comment = user.txtcmt
}).ToList();
ViewModel vm = new ViewModel{ ImageComments = comments };
return View("MyView", vm);
}
View:
#model ViewModel
#{
ViewBag.Title = "Comments";
}
#foreach(ImageComment comment in Model.ImageComments)
{
<p>#comment.Comment</p>
<img src="#comment.ImageUrl" alt="img" />
}
I'm brand new to ASP.NET MVC, and I would appreciate any help with my question. I already did plenty of research (not enough apparently) on this topic. I need to bind a dropdownlist to a specific column in a table and then render it in the view. I already have the query to retrieve the table in the controller:
public ActionResult SelectAccountEmail()
{
var queryAccountEmail = (from AccountEmail in db.UserBases select AccountEmail)
var selectItems = new SelectList(queryAccountEmail);
return View(selectItems);
}
I get lost when it come to binding the query to a dropdownlist in the view.
#model RecordUploaderMVC4.Models.UserBase
#{
ViewBag.Title = "SelectAccountEmail";
}
<h2>SelectAccountEmail</h2>
#Html.LabelFor(model => model.AccountEmail);
#Html.DropDownList(Model.AccountEmail);
#Html.ValidationMessageFor(model => model.AccountEmail);
<input /type="submit" value="Submit">
I get this error when I run it:
Server Error in '/' Application.
--------------------------------------------------------------------------------
The model item passed into the dictionary is of type 'System.Web.Mvc.SelectList', but this dictionary requires a model item of type 'RecordUploaderMVC4.Models.UserBase'.
Any help will be appreciated.
Thanks in advance.
Few things wrong. Firstly, change your model to add the following properties (Looking at your view, it's RecordUploaderMVC4.Models.UserBase):
public class UserBase
{
public string AccountEmail { get; set; }
public SelectList Emails { get; set; }
//rest of your model
}
Then, build your model in your controller properly:
public ActionResult SelectAccountEmail()
{
UserBase model = new UserBase();
var queryAccountEmail = (from AccountEmail in db.UserBases select AccountEmail)
model.Emails = new SelectList(queryAccountEmail);
return View(model);
}
Then in your view you can do:
#Html.LabelFor(model => model.AccountEmail)
#Html.DropDownListFor(model => model.AccountEmail, Model.Emails)
#Html.ValidationMessageFor(model => model.AccountEmail)
Step 1:
First Create a model Like this to hold your ListofAccountEmail
public class AccountEmailViewModel
{
public int AccountEmailId { get; set; }
public string AccountEmailDescription { get; set; }
}
Step 2: Create your model class
public class UserBaseViewModel
{
public IEnumerable<SelectListItem> AccountEmail { get; set; }
public string AccountEmail { get; set; }
}
Step 3 :
In Controller
[HttppGet]
public ActionResult SelectAccountEmail()
{
var EmailAccounts = (from AccountEmail in db.UserBases select AccountEmail)
UserBase userbaseViewModel = new UserBase
{
AccountEmail = EmailAccounts.Select(x => new SelectListItem
{
Text = x.AccountEmailDescription,
Value = Convert.ToString(x.AccountEmailId)
}).ToList()
};
return View(userbaseViewModel);
}
Step 4 : In View
#model RecordUploaderMVC4.Models.UserBase
#{
ViewBag.Title = "SelectAccountEmail";
}
<h2>SelectAccountEmail</h2>
#Html.ValidationSummary()
<h2>SelectAccountEmail</h2>
#Html.LabelFor(model => model.AccountEmail )
#Html.DropDownListFor(x => x.AccountEmailId, Model.AccountEmail, "Please Select", "")
</div>
<input /type="submit" value="Submit">