I have a fairly simple model:
public class Delivery
{
public int DeliveryId { get; set; }
public int OverId { get; set; }
public int Ball { get; set; }
public int Runs { get; set; }
public Player Player { get; set; }
}
All I want to do is have my collection of Delivery objects grouped by Player so that I can then perform some stats calculations on the results in my MVC3 view.
I'm almost there, but between the L2S query and my model binding declaration, I just can't get the two to marry up.
Doing it this way almost works:
var batting = from d in deliveries
where d.Over.IsBatting == true
group d by d.Player into player
select player;
return View(batting);
But the view bindings are a mess.
Bit of help?
EDIT:
Here's my view:
#model IEnumerable<IGrouping<Cricket.Models.Player, Cricket.Models.Delivery>>
#{
ViewBag.Title = "Batting";
}
<h2>Batting</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>
OverId
</th>
<th>
Ball
</th>
<th>
Runs
</th>
</tr>
#foreach (var Item in Model) {
<tr>
<td>
#* #Html.ActionLink("Edit", "Edit", new { id=item.DeliveryId }) |
#Html.ActionLink("Details", "Details", new { id=item.DeliveryId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.DeliveryId })
*# </td>
<td>
#Item.Key
</td>
<td>
#*item.Ball *#
</td>
<td>
#Item.Sum(x => x.Runs)
</td>
</tr>
}
</table>
You can create a ViewModel like
public class VMPlayerRuns
{
public Player _Player{get;set;}
public int Runs{get;set;}
}
and you can modify your query little bit like
var batting = from d in deliveries
where d.Over.IsBatting == true
group d by d.Player into player
from p in player
select new VMPlayerRuns{Player = p.Key, p.Sum(x=>x.Runs)};
Now you can bind this viewmodel to your view rather than complex clumsy grouping.
*Note:*There may be some syntax errors in query but this is whole idea of projecting grouping to your viewmodels
Related
Student studying FullSD encountered an error whilst following lab that my teacher can't figure out.
Have a page where I can create an entry that can be displayed. But when I refresh to view the newly added entry, I get a loading error. When looking at it from Developer Tools, it calls System.nullreferenceexception. Despite this, the entry can still be viewed from datatable in Visual Studios
The error references a block of code starting at line 37 of my Index.razor for this page, which my lecturer narrowed down to being this:
protected async override Task OnInitializedAsync()
{
Bookings = await _client.GetFromJsonAsync<List<Booking>>($"{Endpoints.BookingsEndpoint}");
}
Entire Index.razor:
#page "/bookings/"
#inject HttpClient _client
#inject IJSRuntime js
#attribute [Authorize]
<h3 class="card-title">Car Bookings</h3>
<br />
<a href="/bookings/create" class="btn btn-secondary">
<span class="oi oi-plus"></span>
Create New Booking
</a>
<br />
<br />
#if (Bookings == null)
{
<div class="alert alert-info">Loading Bookings...</div>
}
else
{
<table class="table table-responsive">
<thead>
<tr>
<th>Booking Id</th>
<th>Customer License</th>
<th>Date</th>
<th>Duration in days</th>
<th>Plate Number</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
#foreach (var booking in Bookings)
{
<tr>
<td>#booking.Id</td>
<td>#booking.CustomerId</td>
<td>#booking.DateCreated.Date.ToString("dd/mm/yyyy")</td>
<td>#(booking.DateIn != nullDT ? (booking.DateIn - booking.DateOut).TotalDays.ToString() : "To Be Determined")</td>
<td>#booking.Vehicle.LicensePlateNumber</td>
<td>
<a href="/bookings/view/#booking.Id" class="btn btn-primary">
<span class="oi oi-book"></span>
</a>
<a href="/bookings/edit/#booking.Id" class="btn btn-warning">
<span class="oi oi-pencil"></span>
</a>
<button class="btn btn-danger" #onclick="#(()=>Delete(booking.Id))">
<span class="oi oi-delete"></span>
</button>
</td>
</tr>
}
</tbody>
</table>
}
#code {
private List<Booking> Bookings;
private DateTime nullDT = new DateTime(1, 1, 1, 0, 0, 0);
protected async override Task OnInitializedAsync()
{
Bookings = await _client.GetFromJsonAsync<List<Booking>>($"{Endpoints.BookingsEndpoint}");
}
async Task Delete(int bookingId)
{
var booking = Bookings.First(q => q.Id == bookingId);
var confirm = await js.InvokeAsync<bool>("confirm", $"Do you want to delete {booking.Id}?");
if (confirm)
{
await _client.DeleteAsync($"{Endpoints.BookingsEndpoint}/{bookingId}");
await OnInitializedAsync();
}
}
}
I expected the page to display the newly created entry as I have done with previously created pages in my Lab Workbook
Can anyone else provide some insight?
Edit: Here's my Booking class
using System;
namespace CarRentalManagement.Shared.Domain
{
public class Booking:BaseDomainModel
{
public DateTime DateOut { get; set; }
public DateTime DateIn { get; set; }
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
}
I have a API Json data that contains a lot of information, but I only need to map one attribute to my model class, say Programname, I don't care of other information. I am using Json converter to DeserializeObject the API data. Is it possible to only map partial Json data to my model class? Right now, I receive error message as below if I only map one attribute of the Json data. Thanks.
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List`1[WebApplication2.Program]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable`1[WebApplication2.Models.Program]'.
public class Program
{
public int Prog_id { get; set; }
public string Programname { get; set; }
}
Controller:
public async Task<IActionResult> Index()
{
var Client = new HttpClient();
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("appllication/json"));
HttpResponseMessage res = await Client.GetAsync("my url");
if (res.IsSuccessStatusCode)
{
var result = res.Content.ReadAsStringAsync().Result;
List<Program> programs = JsonConvert.DeserializeObject<List<Program>>(result);
return View(programs);
}
else
{
throw new Exception(res.ReasonPhrase);
}
}
View
#model IEnumerable<WebApplication2.Models.Program>
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
Program
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Programname)
</td>
</tr>
}
</tbody>
</table>
change view model to list and fix a namespace
#model List<WebApplication2.Program>
and IMHO use await instead of .Result
var result = await res.Content.ReadAsStringAsync();
List<Program> programs = JsonConvert.DeserializeObject<List<Program>>(result);
return View(programs);
I figured it out what the problem was now. The word "Program" is a reserved word in asp.net core. After I changed the Program to something else, it works. :/
I have a view where I loop through the model list and display data. I am trying to pass that model to a different controller/action on link click. The data being passed is null. How do I do this?
View:
#Model TransactionViewModel
<table class="table table-striped table-hover visible-lg visible-md visible-sm " style="white-space:nowrap;">
<thead>
<tr>
<th>Date</th>
<th>Amount</th>
<th>Tag Number</th>
<th>Payment Method</th>
<th>Prior Balance</th>
<th>Current Balance</th>
<th>Description</th>
<th>Comments</th>
<th>Receipt</th>
</tr>
</thead>
<tbody>
#if (Model != null && Model.Transactions != null)
{
#foreach (var Tran in #Model.Transactions)
{
<tr>
<td>#Tran.TimeStamp</td>
<td>#Tran.Fare</td>
<td>#Tran.FullTagNum</td>
<td>#Tran.PaymentMethod</td>
<td>#Tran.PreviousBalance</td>
<td>#Tran.NewBalance</td>
<td>#Tran.PaymentDescription</td>
<td>#Tran.Comments</td>
#if (Tran.Processing_ref_string != null)
{
<td>
Receipt
</td> /*how do I pass in the dynamic variable Tran*/
}
else
{
<td>Not Available</td>
}
</tr>
}
}
</tbody>
</table>
Controller Action:
public async Task<IActionResult> PrintReceipt(ReplenishmentRecordResponse ReceiptData){
//data manipulation
}
Model:
public class TransactionViewModel
{
[Display(Name = "From", Prompt = "Starting Date")]
public DateTime StartDate { get; set; }
[Display(Name = "To", Prompt = "Ending Date")]
public DateTime EndDate { get; set; }
public List<ReplenishmentRecordResponse> Transactions { get; set; }
}
I would utilize asp-route-id and asp-page-handler TagHelpers to route your ID back to your PrintReceipt() method.
You could have a button like:
<button id="btnDownload" class="btn btn-info" asp-route-id="#HttpContext.Request.Query["id"]" asp-page-handler="PrintReceipt" type="submit">Submit</button>
Your element needs to have name=id for this to work, but you can change id to be anything.
Simply pass in string id as your parameter in your Controller method.
public async Task<IActionResult> PrintReceipt(string id){
//do something
}
You may need to add #Tran.Tran.Processing_ref_string in your if block
Below are some good links that could also steer you in the right direction. I hope this helps!
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-3.1
TagHelper for passing route values as part of a link
https://www.learnrazorpages.com/razor-pages/tag-helpers/anchor-tag-helper
I'm new to MVC and getting this depressing error when I try to insert buttons into a table.
I have for my .cshtml ViewModel in EditorTemplates:
#model EditorForSample.Models.ProductViewModel
<tr>
<td>#Html.CheckBoxFor(m => m.Selected)</td>
<td colspan="1">
#Model.Name
#Html.HiddenFor(m => m.Name)
</td>
<td>
#Model.Password
#Html.HiddenFor(m => m.Password)
</td>
<td>
#Html.RadioButtonFor(e => e.Locked, true)</td>
<td>
#Html.RadioButtonFor(e => e.Locked, false)</td>
</tr>
And for the model:
public class ProductViewModel
{
public bool Selected{ get; set; }
public string Name { get; set; }
public string Password { get; set; }
public bool Locked { get; set; }
}
I'm getting a 404 error in the .cshtml even though I cannot determine why the syntax is wrong.
Edit: Okay, it turns out that the above actually does work when I manually change the URL and instead my problem is one of the routing randomly changing of its own accord and trying to redirect to the model view CSHTML.
You should send the viewmodel to the view like this.
ProductViewModel productViewModel= new ProductViewModel();
//populate productViewModel with values
View(productViewModel);
also make sure that you added the correct namespace at the top of your file
like this :
using Project.Models;
EDIT:
example for adding Radiobutton in view for same model property:
#Html.RadioButtonFor(model => model.Selected, "false")
#Html.RadioButtonFor(model => model.Selected, "true")
In controller it should be like:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return Content("IsFemale: " + model.Selected);
}
I think this will inspire you. Of course you have to modify it according to the way you need.
I want to pass the results of a query (JSON) from a controller to a partial view, that's why I created a strongly type as follows:
public class Suivi_Client
{
public string ClientID { get; set; }
public string Activite { get; set; }
public string ClientName { get; set; }
}
// list
public class Suivis
{
public List<Suivi_Client> List_Clients { set; get; }
}
Then the partial view :
#model IEnumerable<Project.Models.Suivi_Client>
<html>
<body>
<table border=1>
<thead>
<tr>
<th>
ID
</th>
<th>
Name
</th>
<th>
Activite
</th>
</tr>
</thead>
#foreach(var item in Model){
foreach (var pop in item.List_Clients)
{
<tr>
<td >
#Html.DisplayFor(modelItem => pop.ClientID)
</td>
< <td >
#Html.DisplayFor(modelItem => pop.ClientName)
</td>
<td >
#Html.DisplayFor(modelItem => pop.Activite)
</td>
</tr>
}
}
</table>
</body>
</html>
here is the action method:
public ActionResult Partial_suivi(string clients)
{
IEnumerable<Suivis> PopModel;
var activit = (from x in frh.productivites
join y in frh.Clients on x.action equals y.ClientName
where x.action.Equals(clients)
select new { x.actionID,x.Activité,y.ClientName,y.Responsable,y.TempsCible,x.tempsmoy_ }).Distinct().ToArray();
PopModel = activit;
return PartialView(PopModel);
}
but I have this error : Can not convert type 'AnonymousType # 1 []' to 'Project.Models.Suivis
how can I resolve this error ?
There's a couple issues here.
In your Action Method, you are trying to pass an IEnumerable<Suivis> to your view.
But your view is expecting an IEnumerable<Suivi_Client>.
The next problem is your linq query is selecting (transforming) into an anonymous object, but you're trying to put it into an IEnumerable<Suivis>.
I'm going to take a guess that what you want to do is make your linq query select into an IEnumerable<Suivi_Client> so that your view can do it's work. To do that you would change your code to something similar to this
IEnumerable<Suivi_Client> PopModel = (from x in frh.productivites
join y in frh.Clients on x.action equals y.ClientName
where x.Action.Equals(clients)
select new Suivi_Client
{
Activite = x.Activite,
ClientName = y.ClientName,
ClientID = ??
}).Distinct();
return PartialView(PopModel);
There are a lot of unknowns from the code you provided, and you're using objects that you didn't show in your code snippets. If you could explain what you want your linq query to do actually do, I'm sure someone could post a more complete/better example of how to achieve what you're after.