So basically I have a model for all my recipes and I want to create a view that shows a list of all the recipes with a boolean if the current logged in user can edit the recipe. I've made a Presentation Model to do this. However, when I click 'Add View' in the controller and generate a new view with this presentation model, the view only shows the boolean, fields of 'recipe'. What should I do to generate a view with the bool and all fields of 'recipe'.
Model 'Recipe':
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ReceptenApp.Models
{
public class Recept
{
public int Id { get; set; }
public int Category { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Cook { get; set; }
}
}
Presentation Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ReceptenApp.Models.PresentationModels
{
public class PMReceptListItem
{
public PMReceptListItem()
{
recept = new ReceptWithCats();
}
public ReceptWithCats recept { get; set; }
public bool ShowEdit { get; set; }
}
}
View after generating it:
#model IEnumerable<ReceptenApp.Models.PresentationModels.PMReceptListItem>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ShowEdit)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ShowEdit)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
Since your view is listing all the Recept's, Let's update your presentation model(view model) to reflect that. We will also create a new viewmodel (ReceptViewModel) to represent the Recept entity. We will add ReceptList in the ReceptListViewModel which a List of our new ReceptViewModel so that we can pass a list of Recept's to the view.
public class ReceptViewModel
{
public int Id {set;get;}
public string Title {set;get;}
public string Description {set;get;}
public string Cook {set;get;}
}
public class ReceptListViewModel
{
public PMReceptListItem()
{
ReceptList = new List<ReceptViewModel>();
}
public List<ReceptViewModel> ReceptList { get; set; }
public bool ShowEdit { get; set; }
}
and in your GET action,read the data from your db and load to an object of our ReceptListViewModel
public ActionResult Index()
{
var vm= new ReceptListViewModel();
vm.ReceptList = db.Recepts.Select(x=>new ReceptViewModel {
Id=s.Id,
Title=x.Title,
Description=x.Description,
Cook=x.Cook }).ToList();
vm.ShowEdit = true ; //Set this value based on your condition
return View(vm);
}
and in your GET view
#model List<ReceptListViewModel>
<h2>List of Recepts</h2>
<table>
#foreach(var r in Model.ReceptList)
{
<tr>
<td>#r.Title</td>
<td>#r.Description</td>
<td>#r.Cook</td>
#if(Model.ShowEdit)
{
<td>#Html.ActionLink("Edit","Edit",new { id=r.Id})</td>
<td>#Html.ActionLink("Delete","Delete",new { id=r.Id})</td>
}
</tr>
}
</table>
Related
Can anyone help me regarding the below issue I'm facing in the attached image. I'm trying to go to this url: http://localhost:49849/Customers but I couldn't. Thanks in advance... Just to let you know I;m following Mosh's Cource.
enter image description here
Here is the Model code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations; //this is a namespace
namespace Vidly2.Models
{
public class Customers
{
public int id { get; set; }
[Required] // we cal changing the conventions dataannotations
[StringLength(255)]
public string name { get; set; }
public bool IsSubscribedToNewsletter { get; set; }
public MembershipType MembershipType { get; set; } // we call it navigation property because it allows us to navigate to another type
public byte MembershipTypeId { get; set; } //Fk
}
}
here is the Controller code:
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Vidly2.Models;
namespace Vidly2.Controllers
{
public class CustomersController : Controller
{
public ViewResult Index()
{
var customers = GetCustomers();
return View(customers);
}
public ActionResult Details(int id)
{
var customer = GetCustomers().SingleOrDefault(c => c.id == id);
if (customer == null)
return HttpNotFound();
return View(customer);
}
private IEnumerable<Customers> GetCustomers()
{
return new List<Customers>
{
new Customers { id =1, name = "John Smith" },
new Customers { id =2, name = "Mary Williams" }
};
}
}
}
and here is the view code which has the mentioned error regarding compiling the project:
#using System.Web.Mvc.Html;
#model IEnumerable<Vidly2.Models.Customers>
#*
Note: I've set the model for this view to IEnumerable<Customer>.
This is a simple interface implemented by the list class. Since
in this view we only want to iterate over this list, and we don't
need any of the operations in the List class (eg Add, Remove, etc),
it's better to use the IEnumerable interface, which allows use to
iterate over the list. If in the future, we replace the List with a
different data structure, as long as it is enumerable, our view code
will remain unchanged.
*#
#{
ViewBag.Title = "Customers";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Customers</h2>
#if (!Model.Any())
{
<p>We don't have any customers yet.</p>
}
else
{
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Customer</th>
</tr>
</thead>
<tbody>
#foreach (var customer in Model)
{
<tr>
<td>#Html.ActionLink(customer.Name, "Details", "Customers", new { id = customer.id }, null)</td>
</tr>
}
</tbody>
</table>
}
You have property mismatch for name, Like in your model it is in small case name, but in view you are using customer.Name which should be customer.name
#Html.ActionLink(customer.name, "Details", ...
public ActionResult Details(int id)
{
//Employee employee = new Employee()
//{
// EmployeeId = 101,
// Name = "rehan",
// Gender = "Male",
// City = "Hafizabad"
//};
//return View(employee);
EmployeeContext employeeContext = new EmployeeContext();
Employee employee= employeeContext.Employees.Single(emp => emp.EmployeeId == id);
return View(employee);
}
I can't got the table's values in view
namespace NewMvcDemo.Models
{
[Table("tblEmploee")]
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
}
}
And this is my view
#model NewMvcDemo.Models.Employee
#{
ViewBag.Title = "EmployeeDetails";
}
<h2>EmployeeDetails</h2>
<table style="font-family:Arial">
<tr>
<td>EmployeeId</td>
<td>#Model.EmployeeId</td>
</tr>
<tr>
<td>EmployeeName</td>
<td>#Model.Name</td>
</tr>
<tr>
<td>EmployeeGender</td>
<td>#Model.Gender</td>
</tr>
<tr>
<td>EmployeeCity</td>
<td>#Model.City</td>
</tr>
</table>
<ul>
#foreach (string strcountry in ViewBag.Countries)
{
<li>#strcountry</li>
}
</ul>
So please help me to use the entity framework in the write way
There is the error during the rendring.There is no compilation error
ViewBag.Countries never defined in your controller!
I suggest you to use ViewModel to pass your data from controller to view.
Question: How and where the extension method "Include", used in the Index() action method, in the following PostController used in the Inxex.cshtml view shown below? As I understand _context.Posts.Include(p => p.Blog) means include all posts that relate to blogs table. But I don't see use of blog class or blogId property in the Index.cshtml view below?
Background: In an ASP.NET MVC Core - Code First project I'm following this ASP.NET official site tutorial where they have following Model classes for Blog (parent) and Post (child). I then created a controller (shown below) using MVC Controller with Views, using Entity Framework wizard where I selected Post model in the Model dialogbox.:
Model:
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace EFGetStarted.AspNetCore.NewDb.Models
{
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
PostController:
public class PostsController : Controller
{
private readonly BloggingContext _context;
public PostsController(BloggingContext context)
{
_context = context;
}
// GET: Posts
public async Task<IActionResult> Index()
{
var bloggingContext = _context.Posts.Include(p => p.Blog);
return View(await bloggingContext.ToListAsync());
}
}
Index.cshtml view for Index() action in PostController:
#model IEnumerable<ASP_Core_Blogs.Models.Post>
#{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Content)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.PostId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.PostId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.PostId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Since you're not accessing the Blog property, it's better not to use Include(p => p.Blog). This will add an extra join that isn't required.
However, if you'll reference it in each table row, then it's preferred to include it to avoid lazy loading issues.
I am trying to get total on my view.
I am confused what should i do? Please help me out..
I am not understanding where should i use query and ofc I need it in my view to show but how?
Model class
namespace BOL1
{
public class ADetailsVm
{
public List<BOL1.tbl_Transiction> Payables { get; set; }
public List<BOL1.tbl_Transiction> Reciveables { get; set; }
}
}
DbContext
public partial class bankingEntities : DbContext
{
public bankingEntities()
: base("name=bankingEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<tbl_Accounts> tbl_Accounts { get; set; }
public virtual DbSet<tbl_Transiction> tbl_Transiction { get; set; }
public virtual DbSet<tbl_TransictionType> tbl_TransictionType { get; set; }
public DbSet<ADetailsVm> ADetailsVm { get; set; }
}
}
Controller
public class Details : Controller
{
private TransictionBs objbs;
public Details()
{
objbs = new TransictionBs();
}
// GET: Shinwari/AccountDetails
[HttpGet]
public ActionResult Index(int accountid)
{
ADetailsVm v = new ADetailsVm();
//Load both the collection properties
v.Payables = objbs.GetALL().Where(p => p.AId == accountid && p.tbl_TransictionType.Type.Contains("Payable")).ToList();
v.Reciveables = objbs.GetALL().Where(r => r.AId==accountid && r.tbl_TransictionType.Type.Contains("Reciveable")).ToList();
return View(v);
View
#model BOL1.ADetailsVm
#{
ViewBag.Title = "Index";
}
<h2>AccountDetails</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table id="Payables" class="table">
<tr>
<th>
Date
</th>
<th>
Discription
</th>
<th>
Amount
</th>
</tr>
#foreach (var item in Model.Payables)
{
<tr>
<td>
#item.Date
</td>
<td>
#item.TDiscription
</td>
<td>
#item.Amount
</td>
</tr>
}
</table>
Use the LINQ Sum extension method on the Amount property(assuming it is of numeric type) of your Payables collection property of the view model.
<h2> #Model.Payables.Sum(s=>s.Amount) </h2>
Or if you do not like adding so much C# code in razor views(like me :)), You may add a new property to store the total in your view model.
public class ADetailsVm
{
public decimal TotalPayableAmount { set;get;}
public List<BOL1.tbl_Transiction> Payables { get; set; }
public List<BOL1.tbl_Transiction> Reciveables { get; set; }
}
and in your action method, call the Sum method and set the value to our new TotalPayableAmount property.
public ActionResult Index(int accountid)
{
var v = new ADetailsVm();
v.Payables = objbs.GetALL().Where(p => p.AId == accountid &&
p.tbl_TransictionType.Type.Contains("Payable")).ToList();
v.Reciveables = objbs.GetALL().Where(r => r.AId == accountid &&
r.tbl_TransictionType.Type.Contains("Reciveable")).ToList();
v.TotalPayableAmount= v.Payables.Sum(s=>s.Amount)
return View(v);
}
and in your view
#model ADetailsVm
<h2>#Model.TotalPayableAmount</h2>
I have a web page that have two task
1) add new products
2) display existing products in a table (refer below image)
also i have two classes for each above task
for display existing details and save new product
public class VMProduct
{
public List<Product>ProductList { get; set; }
}
public class Product
{
public String ProductID { get; set; }
public String ProductName { get; set; }
public String Uom1 { get; set; }
public String Uom2 { get; set; }
public String ProductCategoryID { get; set; }
}
my problem is i can display data by using VMProduct.ProductList model but how i can save new product items using "product" model ?
how can i use both Models in One view?
if i use "product" model's properties in VMProduct model it is duplication codes right?
can anyone have a Solution for this?
thanks in advance
It looks like VMProduct is already a custom view model (I'm mostly guessing by its name), so just add a property to it of the type you need:
public class VMProduct
{
public List<Product> ProductList { get; set; }
public Product NewProduct { get; set; }
}
Though, unless I'm misunderstanding something about your UX, this might not even be necessary. The model used to render a view doesn't necessarily need to be the same model received from any given form on that view. So you might continue to render the view using the VMProduct object you have now, and the form for adding a product can still post an instance of Product to the controller action which invokes the add operation. Something like:
public ActionResult Add()
{
// create your view model
return View(someVMProduct);
}
[HttpPost]
public ActionResult Add(Product newProduct)
{
// add the product to the backing data store
return RedirectToAction("Add");
}
Here explained how to implement 2 model in 1 view in MVC 4. Sometimes its required to implement a page where 2 forms exist in a single view (page) like Login & Registration in a same view.
You can get complete tutorial here : http://dotnetawesome.blogspot.com/2013/09/2-model-in-1-view-in-mvc-4.html
Here is the sample code :
A ViewModel Created :
public class UsersLoginRegister
{
public User User { get; set; }
public Login Login { get; set; }
}
User Entity
public partial class User
{
public int UserID { get; set; }
[Required]
public string Username { get; set; }
[Required]
[DataType(System.ComponentModel.DataAnnotations.DataType.Password)]
public string Password { get; set; }
[Required]
public string FullName { get; set; }
}
Login Entity
public class Login
{
[Required]
public string UserName { get; set; }
[Required]
[DataType( System.ComponentModel.DataAnnotations.DataType.Password)]
public string Password { get; set; }
}
In the view (Html) code :
<table>
<tr>
<td><b>Login</b></td>
<td><b>Register</b></td>
</tr>
<tr>
<td>
#using (Html.BeginForm("Login", "Home", FormMethod.Post))
{
<table>
<tr>
<td>Username : </td>
<td>#Html.TextBoxFor(a => a.Login.Username)</td>
</tr>
<tr>
<td>Password : </td>
<td>#Html.EditorFor(a => a.Login.Password)</td>
</tr>
<tr>
<td></td>
<td> <input type="submit" value="Submit" /></td>
</tr>
</table>
}
</td>
<td>
#using (Html.BeginForm("Register", "Home", FormMethod.Post))
{
<table>
<tr>
<td>Fullname : </td>
<td>#Html.TextBoxFor(a => a.User.FullName)</td>
</tr>
<tr>
<td>Username : </td>
<td>#Html.TextBoxFor(a => a.User.Username)</td>
</tr>
<tr>
<td>Password : </td>
<td>#Html.EditorFor(a => a.User.Password)</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Submit" />
</td>
</tr>
</table>
}
</td>
</tr>