I come from a procedural PHP background. I am trying to learn how to do the same stuff I used to do in php and do it in asp.net. I need to sort my orders under their perspective Customer name.
Right now my layout is:
Sams Club
Order 1
Sams Club
Order 2
Walmart
Order 1
Walmart
Order 2
Walmart
Order 3
I need my layout more like:
Sams Club
Order 1
Order 2
Walmart
Order 1
Order 2
Order 3
I can easily do this with PHP but am struggling to figure out how to do this in an MVC type of application.
This is how my cshtml page looks.
<table class="table table-condensed" style="border-collapse:collapse;">
<thead>
<tr>
<th><input type="checkbox" name="CheckOrders" />Select All </th>
<th>Bill to Name</th>
<th>Qty Ordered</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr data-toggle="collapse" data-target="##Html.DisplayFor(model => item.customer_number)" class="accordion-toggle">
<td><input type="checkbox" name="checkAllCus" value="#Html.DisplayFor(model => item.customer_number)"/></td>
<td>
#Html.DisplayFor(model => item.Bill_to_Name)
</td>
<td>
#Html.DisplayFor(model => item.Quantity_Ordered)
</td>
</tr>
<tr>
<td colspan="12" class="hiddenRow">
<div class="accordian-body collapse" id="#Html.DisplayFor(model => item.customer_number)">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Order Number</th>
<th>Bill to Name</th>
<th>Qty Ordered</th>
<th>Ship Date</th>
<th>Item #</th>
<th>Description</th>
<th>State</th>
<th>Carrier</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" name="orders[]" value="#Html.DisplayFor(model => item.order_no)" /></td>
<td>
#Html.DisplayFor(model => item.order_no)
</td>
<td>
#Html.DisplayFor(model => item.Bill_to_Name)
</td>
<td>
#Html.DisplayFor(model => item.Quantity_Ordered)
</td>
<td>
#Html.DisplayFor(model => item.Ship_Date)
</td>
<td>
#Html.DisplayFor(model => item.item_no)
</td>
<td>
#Html.DisplayFor(model => item.descr1)
</td>
<td>
#Html.DisplayFor(model => item.shipstate)
</td>
<td>
#Html.DisplayFor(model => item.shipper)
</td>
<td>
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ })
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
}
</tbody>
</table>
Below is my Model
namespace OpenCustomerOrder3.Models
{
using System;
public partial class spOrderDetails_Result
{
public string cusNo;
public string customer_number { get; set; }
public string shipper { get; set; }
public string user_def_fld_5 { get; set; }
public string item_no { get; set; }
public string descr1 { get; set; }
public string location1 { get; set; }
public string Bill_to_Name { get; set; }
public Nullable<decimal> Quantity_Ordered { get; set; }
public string Requested_Date { get; set; }
public string Ship_Date { get; set; }
public string Status { get; set; }
public string order_no { get; set; }
public string shipstate { get; set; }
}
}
This really comes down to what your domain model looks like.
It looks like the model type being passed to the view at the moment is simply an IEnumerable<Order> or similar. If you really have to do this way, one way to achieve what you want is by grouping your orders by CustomerName using the GroupBy method in System.Linq.
However, a better model would be to let a Customer model have many orders, i.e. between Customer and Order there is a 1..* relationship. For example,
public class Customer
{
public string Name { get; set; }
public IEnumerable<Order> Orders { get; set; }
}
Then what you want is to pass an IEnumerable<Customer> instead to your view.
Related
I am trying build a project while self learning but have been stuck in one place.
I have this class Roles:
namespace IC2021.Models
{
public partial class Roles
{
public Roles()
{
Staffs = new HashSet<Staffs>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Staffs> Staffs { get; set; }
}
}
And another called Staffs:
namespace IC2021.Models
{
public partial class Staffs
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
public int? RoleId { get; set; }
public string Archived { get; set; }
public virtual Roles Role { get; set; }
}
}
This is my RolesController:
namespace IC2021.Controllers
{
public class RolesController : Controller
{
private readonly ICOctober2021Context _context;
public RolesController(ICOctober2021Context context)
{
_context = context;
}
// GET: Roles
public async Task<IActionResult> Index()
{
return View(await _context.Roles.ToListAsync());
}
public async Task<IActionResult> RolesWithStaffs()
{
var iCOctober2021Context = _context.Roles.Include(s => s.Staffs);
return View(await iCOctober2021Context.ToListAsync());
}
}
}
And finally I'm trying to view it from RolesWithStaffs:
<!-- model declaration -->
#model IEnumerable<IC2021.Models.Roles>
#{
ViewData["Title"] = "RolesWithViewController";
}
<h1>RolesWithViewController</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
Role
</th>
<th>
Staff Name
</th>
<th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Staffs)
</td>
#*<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="#item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>*#
</tr>
}
</tbody>
</table>
So here in the view when I tried to access from Staffs, I am not able (for example item.Staffs.FirstName, or anything else from Staffs). Whereas I can do it other way, I mean from staffs view I can access Roles.Name or Id).
Can anyone please help me? Any help will be highly appreciated.
Your view model looks quite unusual, IMHO you can try this
public async Task<IActionResult> RolesWithStaffs()
{
var model= await _context.Set<Staffs>().Include(s => s.Role).ToListAsync();
return View(model);
}
and view
<table class="table">
<thead>
<tr>
<th>
First Name
</th>
<th>
Last Name
</th>
<th>
Role
</th>
<th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(item=> item.FirstName)
</td>
<td>
#Html.DisplayFor(item=> item.LastName)
</td>
<td>
#Html.DisplayFor(item => item.Role.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="#item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
I have gone through lot of posts however unable to resolve this issue.
I input some values on the View and click the Submit button
My repo calculates the payment schedule based on the criteria and displays the list (that's what I am trying to achieve)
This is where I am having issues.
On the initial load my Model is null and I get the null reference exception.
I have just started coding with asp so please ignore the basics in this case.
Any suggestions would be helpful
#model FinanceApplication.ViewModels.LoanViewModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<div>
<table style="width: 35%;" class="style1">
<tr>
<td>Enter Price</td>
<td>#Html.TextBoxFor(model => model.Amount)</td>
</tr>
<tr>
<td>Enter Deposit</td>
<td>#Html.TextBoxFor(model => model.Deposit)</td>
</tr>
<tr>
<td>Finance Option</td>
<td>
#Html.DropDownListFor(model =>
model.Term, new SelectList(Enum.GetValues(typeof(Options))),
"Select Option",
new { #class = "form-control" })
</td>
</tr>
<tr>
<td>Delivery Date</td>
<td>
#Html.EditorFor(model => model.Deliverydate)
</td>
</tr>
<tr>
<td>Arrangement Fee</td>
<td>#Html.TextBoxFor(model => model.ArrangementFee)</td>
</tr>
<tr>
<td>Completion Fee</td>
<td>#Html.TextBoxFor(model => model.CompletionFee)</td>
</tr>
<tr>
<td>
<input type="submit" id="btnSubmit"
value="Submit" onclick="myFunction();" />
</td>
</tr>
</table>
</div>
<div id="loan-form" class="text-left">
<h1>Payment Schedule</h1>
<table>
<tr>
<td>Amount (£) </td>
<td>#Html.DisplayFor(model => model.Amount)</td>
</tr>
<tr>
<td>Loan Amount (£) </td>
<td>#Html.DisplayFor(model => model.LoanAmount)</td>
</tr>
<tr>
<td>Deposit (£) </td>
<td>#Html.DisplayFor(model => model.Deposit)</td>
</tr>
<tr>
<td>Term (years) </td>
<td>#Html.DisplayFor(model => model.Term)</td>
</tr>
<tr>
<td>Delivery Date</td>
<td>#Html.DisplayFor(model => model.Deliverydate)</td>
</tr>
<tr>
<td>
<table class="table table-striped">
<thead>
<tr>
<th>Payment Date</th>
<th>Payment Amount (£) </th>
<th>Total Paid (£) </th>
<th>Balance (£) </th>
</tr>
</thead>
<tbody>
if(Model != null)
{
#foreach (var item in Model.PaymentSchedule)
{
<tr>
<td> #Html.DisplayFor(modelItem =>
item.PaymentDate) </td>
<td> #Html.DisplayFor(modelItem =>
item.PaymentAmount) </td>
<td> #Html.DisplayFor(modelItem =>
item.TotalPaid) </td>
<td> #Html.DisplayFor(modelItem =>
item.RemainingBalance) </td>
</tr>
}
}
else
{
<tr>
<td>No Items found</td>
</tr>
}
</tbody>
</table>
</td>
</tr>
</table>
</div>
}
{
private IPaymentScheduleRepository _paymentScheduleRepository;
public HomeController(IPaymentScheduleRepository paymentScheduleRepository)
{
_paymentScheduleRepository = paymentScheduleRepository; }
[HttpGet]
public IActionResult Index()
{ return View(new LoanViewModel()); }
[HttpPost]
public async Task<IActionResult> Index(LoanViewModel requestParameters)
{ LoanViewModel output = await _paymentScheduleRepository.GetPaymentSchedule(requestParameters);
return View("Index", output);}}
//ViewModel
public class LoanViewModel
{
[Required(ErrorMessage = "Please enter the loan amount.")]
[Range(1, 100000000,
ErrorMessage = "Loan amount must be between 1,000 and 1000,000.")]
public decimal Amount { get; set; }
[Required(ErrorMessage = "Please enter the deposit amount.")]
[Remote(action: "VerifyDeposit", controller:"Home")]
public decimal Deposit { get; set; }
[Required(ErrorMessage = "Please select the term of the loan.")]
public string Term { get; set; }
[Required(ErrorMessage = "Please select the delivery date.")]
[DataType(DataType.Date)]
[Display(Name = "Delivery Date")]
[DisplayFormat(ApplyFormatInEditMode = true,
DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime Deliverydate { get; set; }
public decimal ArrangementFee { get; set; }
public decimal CompletionFee { get; set; }
public decimal LoanAmount
{
get { return (Amount - Deposit); }
}
[Display(Name = "Payment Schedule")]
public List<SheduledPayments> PaymentSchedule { get; set; }
}
//PaymentSchedule
public class SheduledPayments
{
public DateTime PaymentDate { get; set; }
public decimal PaymentAmount { get; set; }
public decimal RemainingBalance { get; set; }
public decimal TotalPaid { get; set; }
}
On the initial load your view model returns null - hint.
You should have a method for loading the view i.e get and a method for posting the view i.e. post.
Depending on context you need to work with the model in both action methods.
Check this and post the action method on your initial load.
For the decimal values you can use the ?? operator, for the date you can use the ternary operator ?:
. . .
<td>#Html.DisplayFor((modelItem => (item.PaymentDate == null ? new DateTime(1900,1,1):item.PaymentDate)))</td>
<td>#Html.DisplayFor(modelItem => item.PaymentAmount ?? 0)</td>
. . .
see this for more informations.
Otherway If the problem is the first call, your model is not defined so you must initialize the parameters in the model constructor.
I'm struggling with (perhaps) a simple challenge.
I have the following classes:
public class Product
{
public int ID { get; set; }
[Display(Name ="Product Name")]
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int? CategoryID { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public int ID { get; set; }
[Display(Name = "Category Name")]
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
To store the data I'm using EF Core
public class StoreContext : DbContext
{
public StoreContext(DbContextOptions<StoreContext> options) : base(options) { }
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
And in my ProductsController I have the following GET method:
public async Task<IActionResult> Index(int category, string search)
{
var storeContext = _context.Products.Include(p => p.Category) as IQueryable<Product>;
if (category != 0)
{
storeContext = storeContext.Where(p => p.Category.ID == category);
}
if (search != null)
{
storeContext = storeContext.Where(p => p.Category.Name == search);
}
var categories = storeContext.OrderBy(p => p.Category.Name).Select(p => p.Category.Name).Distinct();
if (!String.IsNullOrEmpty(search))
{
storeContext = storeContext.Where(p => p.Name.Contains(search)||
p.Description.Contains(search) ||
p.Category.Name.Contains(search));
ViewBag.Search = search;
}
ViewBag.Category = new SelectList(categories);
return View(await storeContext.ToListAsync());
}
My Index.cshtml looks like as follows:
#model IEnumerable<BabyStore.Models.Product>
#{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-action="Index" asp-controller="Products" method="get">
<div class="form-group">
<table>
<tr>
<td>
<label>Filtered by Category: </label>
</td>
<td>
<select class="form-control" asp-items="ViewBag.Category">
<option value="">-- Select Category --</option>
</select>
</td>
<td>
<input type="submit" value="Filter" id="search"/>
<input type="hidden" name="search" id="search"/>
</td>
</tr>
</table>
</div>
</form>
<br />
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Category.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Category.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="#item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="#item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Pushing the "Filter" button should cause refreshing the View and filtering by Category.Name
But, unfortunately it does not work.
In my browser I read
http://localhost:53827/Products?search=
So no parameter has been passed to search.
If I enter by hand
http://localhost:53827/Products?search=clothes
it works perfectly
In the Startup.cs I have the following Route
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Any idea how to solve it?
I want to pass a model to the controller after klicking on a row.
this is my code which doesn't work.
<table class="table">
<tr>
<th>
<p>Sender</p>
</th>
<th>
<p>Subject</p>
</th>
<th>
<p>Received</p>
</th>
<th>
<p>HasAttachment</p>
</th>
<th></th>
</tr>
#foreach (var item in Model.Inbox) {
<tr class="mail-row" onclick="location.href = '#(Html.ActionLink ("", "MailViewer", "Profile", new { mail = item }, null ))'">
<td>
#Html.DisplayFor(modelItem => item.Sender)
</td>
<td>
#Html.DisplayFor(modelItem => item.Subject)
</td>
<td>
#Html.DisplayFor(modelItem => item.Received)
</td>
<td>
#Html.DisplayFor(modelItem => item.HasAttachment)
</td>
</tr>
}
</table>
I tried to use Url.Action but i got only the Object Type in the url and not the actual object.
I try to send this object:
public class Mail
{
public string Sender { get; set; }
public string Subject { get; set; }
public DateTime Received { get; set; }
public bool HasAttachment { get; set; }
public string content { get; set; }
}
it is possible with json but you will but you should send id and get the data in action based on that id but with json you can do it like this
My action link will be
#Html.ActionLink("senddata", "MailViewer",new{ #data = Json.Encode(item) } )
and my action will be something like this
public ActionResult MailViewer(string data)
{
var result = System.Web.Helpers.Json.Decode<Mail>(data);
return View();
}
I have the following view model
public class ResourceProjectedCapacitiesModel
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
public string Manager { get; set; }
public string Role { get; set; }
public string Project { get; set; }
public decimal Capacity { get; set; }
public System.DateTime Date { get; set; }
}
In my GET action i display all these in the view.
[HttpPost]
public ActionResult Index(List ResourceProjectedCapacitiesModel> list)
{
foreach (ResourceProjectedCapacitiesModel item in list)
{
....
}
....
}
In the view there is the following editor but when the form is submitted the binding doesnt work, list is null
#Html.EditorFor(modelItem => item.Capacity)
#Html.HiddenFor(modelItem => item.ID)
#model List<CapacityPlanner.ViewModels.ResourceProjectedCapacitiesModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using(Html.BeginForm())
{
<table class="table">
<tr>
<th>
First Name
</th>
<th>
Last Name
</th>
<th>
Location
</th>
<th>
Manager
</th>
<th>
Role
</th>
<th>
Project
</th>
<th>Apr</th>
<th>May</th>
<th>Jun</th>
<th>Jul</th>
<th>Aug</th>
<th>Sep</th>
<th>Oct</th>
<th>Nov</th>
<th>Dec</th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Location)
</td>
<td>
#Html.DisplayFor(modelItem => item.Manager)
</td>
<td>
#Html.DisplayFor(modelItem => item.Role)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project)
</td>
#for(var i = 1; i <= 12; i++)
{
<td>
#if(item.Date.Month == i)
{
#Html.EditorFor(modelItem => item.Capacity)
}
</td>
}
<td>
#Html.HiddenFor(modelItem => item.ID)
</td>
</tr>
}
</table>
<input type="submit" value="Save" class="btn btn-default" />
}
I have inserted the code of my view
You should use for instead of foreach.
#for (int i = 0; i < Model.Items.Count; i++)
{
#Html.EditorFor(model => Model.Items[i].Amount)
#Html.HiddenFor(model => Model.Items[i].Amount)
}
Then all filled will get different id.