MVC5 - How to retrieve count of related rows to view? - c#

new MVC programmer here. Really enjoying it so far, but I have been caught on a snag and I am hoping to get pointed in the right direction.
I have two tables in my Data Connections:
Guests
- Id (Key)
Name
partyId
Party
- Id (Key)
Name
isRSVP
Currently, I am returning the data from the Party table via a ViewModel into a View that displays a table which iterates through the rows of Party and displays the information for each row.
What I would like to do is get a COUNT of the rows where Party.Id = Guest.partyId, and return the count to that same view. So if Party A had three Guest and Party B had two guest, that would be reflected in my View.
Thanks!
Edited with code snippets:
Controller Index Method -
// GET: Parties
public ActionResult Index()
{
var viewModel = new PartyViewModel
{
Parties = _context.Parties.ToList(),
Guests = _context.Guests.ToList()
};
return View("Index",viewModel);
}
PartyViewModel -
public class PartyViewModel
{
public IEnumerable<Party> Parties { get; set; }
public IEnumerable<Guest> Guests { get; set; }
public int guestCount { get; set; }
}
Table from Index view that I am populating:
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Party's Name</th>
<th>Party Size</th>
<th>RSVP</th>
</tr>
</thead>
<tbody>
#foreach (var party in Model.Parties)
{
<tr>
<td>#Html.ActionLink(party.Name, "EditPartyStatus", "Parties", new { id = party.Id }, null)</td>
<td>INSERT COUNT HERE</td>
<td>#party.isRSVP</td>
</tr>
}
</tbody>
</table>
Screenshot of what im trying to do:
http://imgur.com/a/JCpqv

Where you have "INSERT COUNT HERE" in your view just add the following line:
#Model.Guests.Count(g => g.PartyId == party.Id)

Related

How to load filtered data in html table using jquery & .net

I've this structure of c# class
public class test : PageModel
{
public JArray Transactions { get; set; }
public void OnGet(int filterid)
{
Transactions = GetTableValue(filterid);
}
}
actually my table works fine when it's load first time on page load.but when I tried to pass some filter values to onget method their I'm getting require response Transactions but it's not reflecting in table
this is the sample syntax i'm using.. please let me if you've any solutions
#page
#model IndexModel
#{
Layout = "_Layout";
}
function SubmitFilter()
{
var transactionNumb = $("#transactionNumber").val();
$.get("https://localhost:7197/Transactions?filterid="+transactionNumb , response=> {
});
}
<table id="tblTransactions" class="table table-hover">
<thead>
<td scope="col">Type</td>
<td scope="col">Status</td>
</thead>
<tbody id="tbody">
</tbody>
<tbody>
#foreach (dynamic transaction in #Model.Transactions)
{
<tr>
<td>#transaction.type</td>
<td>#transaction.status</td>
</tr>
}
</tbody>
</table>
}

ASP.NET Core MVC - editing a list of entities

I'm trying to dip my toe into frontend development with ASP.NET Core 5 MVC - but I'm not really having much success so far... I'm more of a backend developer - give me a SQL Server database, and a ASP.NET Core Web API, and I'm happy - but this frontend wizardry is not quite my strong suit ...
OK, so I'm trying something extremely simple - a Razor page to edit a list of something, add a numerical value to each of those somethings, and then storing them.
I have a model/DTO class like:
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
Of course, in reality, it has many more properties - but those aren't relevant here. What is: name and city are given, and I need to add the CustomerId to it (in our case, the CustomerId is handled by SAP - so we need to manually add those after the customer has been created there).
I have a really simple Razor page which basically shows the list of customers, allows me to enter the CustomerId in the last column, and then I have a POST method on the same Razor page that gets hit when the user clicks on the Update (submit) button.
Here's my view:
#page
#model IndexModel
<h3 class="display-4">Customers</h3>
#if (!string.IsNullOrWhiteSpace(#Model.Message))
{
<div class="container">
<span class="#Model.MessageClass mt-4 mb-5">#Model.Message</span>
</div>
}
<div class="container">
<form method="post">
<table class="table table-striped table-bordered table-hover table-sm">
<thead class="thead-dark">
<tr>
<th scope="col-md-2">Name</th>
<th scope="col-md-2">City</th>
<th scope="col-md-1">CustomerId</th>
</tr>
</thead>
<tbody>
#for (int index = 0; index < Model.Customers.Count; index++)
{
<tr>
<td>#Model.Customers[index].Name</td>
<td>#Model.Customers[index].City</td>
<td>
<input type="number" asp-for="Customers[index].CustomerId" id="Customers[#index]" />
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="Update" class="btn btn-primary" />
</form>
</div>
and this is my "code-behind" for this Razor page:
public class IndexModel : PageModel
{
public string Message { get; set; }
public string MessageClass { get; set; }
public List<Customer> Customers { get; set; }
public async Task OnGetAsync()
{
Customers = CustomerProvider.GetCustomers();
}
public async Task OnPostAsync()
{
Customers = CustomerProvider.GetCustomers();
if (await TryUpdateModelAsync(Customers))
{
Message = "Customers successfully updated";
MessageClass = "alert-success";
}
else
{
Message = "Customer update did not work";
MessageClass = "alert-danger";
}
}
}
Nothing too fancy here - I basically get a list of customers from somewhere (a database, in reality), I display that list, I can enter customer id values into the grid, and I was expecting to get back the updated Customers in my OnPostAsync method.
Now the code runs fine, shows the list of customers, I can enter values into the CustomerId column, and I can click on "Update". The OnPostAsync method gets called, I fetch the customers again, and I was expecting the await TryUpdateModelAsync to update my customers with the CustomerId values that I have entered.
But it does not do that - after my GetCustomers call, I have my four test customers - as expected - but after the TryUpdateModelAsync, that list is empty... The call to TryUpdateModelAsync works - it returns true - but the list of customers isn't updated with the information entered on screen - quite the contrary, the list is wiped out ...
I also tried to use
public async Task OnPostAsync([FromForm] List<Customer> updatedCustomers)
hoping that the MVC data binding would return back the list of updated customers - but this updatedCustomers is null and doesn't send back the entered data...
But when I look at HttpContext.Request.Form - I do see the values that were entered:
but somehow, those aren't handled properly and not applied to the Customers list...
Any ideas? I must be missing something really silly somewhere - but I just cannot find it...
You can bind the values in two ways:
1. Using [BindProperty]
Add a property to your model and annotate it with [BindProperty]. When you build inputs with asp-for="#Model.MyList[i].AProp" it will be bound to form values when submitted.
Note: You still need to render read-only properties in HTML with hidden inputs (<input type="hidden" />) for those values to be available when the form is submitted, otherwise you'll get sentinel/null values.
Assuming you have a Razor template as follows:
<form method="POST">
#Html.AntiForgeryToken()
<table>
<thead>
<tr>
<th>Customer Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.Customers.Count; i++)
{
<tr>
<td>
<input type="text"
readonly
value="#Model.Customers[i].CustomerId"
asp-for="#Model.Customers[i].CustomerId"/> <!-- asp-for attributes are indexed for each item -->
</td>
<td>
<input type="text"
value="#Model.Customers[i].Name"
asp-for="#Model.Customers[i].Name"/>
</td>
</tr>
}
</tbody>
</table>
<button type="submit">Save</button>
</form>
you need a model with a bound property:
public record Customer(string CustomerId, string Name);
public class HomeModel : PageModel
{
[BindProperty]
public List<Customer> Customers { get; set; }
// ...
}
When rendered, you should have inputs with indexed name attributes:
<input type="text" value="Bob" id="Customers_1__Name" name="Customers[1].Name"/>
When you submit the form, Model.Customers will be populated with the values.
2. Using [FromForm] attribute
You can also accept a parameter of the same name as input names. This means if the input names are like Customers[1].Name, the parameter name must be customers (case insensitive) (not updatedCustomers like you have). Or you can specify a different name using [FromForm(Name = "customers")] updatedCustomers.
// this works
public ActionResult OnPost([FromForm]List<Customer> customers)
{
return Page();
}
// this also works
public ActionResult OnPost([FromForm(Name = "customers")]List<Customer> updatedCustomers)
{
return Page();
}
If the model has a bound property ([BindProperty]), it will also be populated with the form values in addition to the parameter.
Further info
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-5.0#the-input-tag-helper
Ah if I understand this case right then you are missing a very little part.
So you want to send a list/array type parameter to your POST method, but your POST method does not know about the object which is coming as a parameter. So you should define as a name attribute onto your input.
<input type="number" name="customerIds" asp-for="Customers[index].CustomerId" id="Customers[#index]" />
and your POST method should meet the parameter as an int[] type.
public async Task OnPostAsync(int[] customerIds)
{
//Now you have edited customerIds as an integer array type and you can manuplate it.
}

How to display many differents values splitted by a new line in one cell

I'been trying to figure this out but can't.
I've got a model which has let's say a one-to-many relationship.
public virtual IList<ListModels.listaIdInstrumentos> listaIdInstrumentos { get; set; }
A pretty plane controller:
public ActionResult Index()
{
informeModelContext db = new informeModelContext();
var model = db.Informe.ToList();
return View(model);
}
And a scaffolded View:
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.listaCalibracion)
</td>
...
The "listaCalibracion" is a List of string that for example could be something like 2 strings named "ABC" and "XYZ"
although i CAN display the values correctly in my page, it will display ("ABCXYZ") and what i want to show is (ABC /n/n XYZ) meaning one under another.
Sorry if i can't make myself clear. English is not my first Lenguage.
Could you help me?
Thanks!
#foreach (var item in Model)
{
#foreach (var subItem in item.listaCalibracion)
{
<tr>
<td>
#Html.DisplayFor(modelItem => subItem )
</td>

linq to sql geting data from 2 tables

I'm trying to get data from 2 table using Linq , that one table had FK to the second table but not necessary has data (table review could have for each review comments (many)) what i'm trying to get is: in a single view get all the reviews and if there are any comments display them related to the review Id
trying to use join get me error in my view (model pass is wrong i tried each table model) this is my code :
public ActionResult ttt()
{
var model = from rev in db.reviews
join com in db.Comments
on rev.ReviewId equals com.ReviewId into JoineRevCom
from com in JoineRevCom.DefaultIfEmpty()
select new
{
rev.ReviewBody,
rev.ReviewHeadLine,
Comments = com != null ? com.CommentBody : null
};
return View(model);
}
#model IEnumerable< SiteMvcPro.Models.Review>
As always I would start by writing a view model for this view containing the information that I would like to display and never send anonymous objects to your view like you did in your code.
Let's suppose that you want to display a list of reviews and for each review the list of corresponding comments. So your view model might look something along those lines:
public class ReviewViewModel
{
public int ReviewId { get; set; }
public string ReviewBody { get; set; }
public string ReviewHeadLine { get; set; }
public IList<CommentViewModel> Comments { get; set; }
}
public class CommentViewModel
{
public string CommentBody { get; set; }
}
with this defined you could perform your LINQ query to extract the necessary data and project to this view model:
IEnumerable<ReviewViewModel> viewModel =
from review in db.reviews
join comment in db.Comments
on review.ReviewId equals comment.ReviewId into joinedReviewComment
select new ReviewViewModel // <-- Always project to a view model and never to an anonymous object
{
review.ReviewBody,
review.ReviewHeadLine,
Comments = joinedReviewComment.Select(c => new CommentViewModel
{
CommentBody = c.CommentBody,
}).ToList(),
};
return View(viewModel.ToList()); // <-- Always pass a view model to your view
And now all that's left is to display this information in your strongly typed view:
#model IList<ReviewViewModel>
<table>
<thead>
<tr>
<th>Review id</th>
<th>Review body</th>
<th>Review headline</th>
<th>Review comments</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>#Html.DisplayFor(x => x[i].ReviewId)</td>
<td>#Html.DisplayFor(x => x[i].ReviewBody)</td>
<td>#Html.DisplayFor(x => x[i].ReviewHeadLine)</td>
<td>
#for (var j = 0; j < Model[i].Comments.Count; j++)
{
<div>
#Html.DisplayFor(x => x[i].Comments[j].CommentBody)
</div>
}
</td>
</tr>
}
</tbody>
</table>
This being said projecting is one thing but filtering your data is another. Suppose that you have millions of reviews and each review has millions of comments. Making the aforementioned query will simply bring your server down pretty quickly. So think about that when designing your application and views. Don't hesitate to use the Where, Skip and Take operators to filter your result-sets down into a meaningful collection of data that is reasonable enough to be displayed on a single view.

Getting error: Object reference not set to an instance of an object [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
Can anyone help me with this:
I need to display dynamic data in my _DeliveryDetailsPatial.cshtml. This is called every time the user is in the Delivery Information page or New Address page. Every time I am to navigate to either of these pages i keep getting this ERROR:
Object reference not set to an instannce of an object
How can I solve this?
Thank you!
Here's my code:
_DeliveryDrtailsPartial:
#model QuiznosOnlineOrdering.Models.StoreViewModel
<table id="orderTable" class="table">
<tr>
<td class="t">Item</td>
<td class="t">Quantity</td>
<td class="t">Item Price</td>
</tr>
#foreach (var item in Model.StoreAddress)
{
<tr>
<td>#Html.DisplayFor(model => item.NOM)</td>
<td>#Html.DisplayFor(model => item.ADRESSE)</td>
<td>#Html.DisplayFor(model => item.VILLE)</td>
</tr>
}
</table>
StoreViewModel:
public IEnumerable<Store> StoreAddress { get; set; }
public IEnumerable<StoreHour> StoreHour { get; set; }
public IEnumerable<ReferenceAcceptedPayment> StoreAcceptedPayment { get; set; }
DeliveryController:
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View();
}
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View(store);
}
You haven't passed model
You are never actually injecting the model into the view.
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View(store);
}
As a result, when you try to read properties on your model, you get an exception since the model is null.
You need to pass the model like this
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View(store);
}
Also following are the links which will help you also in passing views to partial view also.
return PartialView("_ViewPage",model);
Setting models in asp.net mvc views and partial views

Categories