I'm pretty new with ASP.NET Core Razor Pages and I would like your help on the following.
I have the following two classes:
public class Customer
{
[Key]
public int Id { get; set; }
[Required(ErrorMessage ="Please enter a name.")]
[Display(Name ="Customer Name")]
public string CustomerName { get; set; }
[Display(Name = "Customer Email")]
public string CustomerEmail { get; set; } = string.Empty;
[Display(Name ="Customer Phone Number")]
public string CustomerPhoneNumber { get; set; } = string.Empty;
public List<Invoice> Invoices { get; set; } = new();
}
and
public class Invoice
{
[Key]
public int Id { get; set; }
[Display(Name ="Invoice Number")]
public string InvNumber { get; set; }
[Display(Name = "Invoice Amount")]
public decimal InvAmount { get; set; }
[Display(Name = "Issued? (Yes/No)")]
public bool InvIssued { get; set; } = false;
[Display(Name = "Paid? (Yes/No)")]
public bool InvPaid { get; set; } = false;
public int CustomerId { get; set; }
}
The way I've set it up is for a one-to-many relationship. Now, two related issues are that during the Create
form for an invoice I also need to input a CustomerId
, otherwise I get an SQL exception error. However, for the life of me, I can't figure out how to bind the data, to the Customer table, so that I can retrieve the list of available customers and have it as an option during the creation of an invoice.
My .cshtml
file contains:
<div class="form-group">
<label asp-for="Invoice.CustomerId" class="control-label"></label>
<input asp-for="Invoice.CustomerId" class="form-control" value="3"/>
<span asp-validation-for="Invoice.InvNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Invoice.InvNumber" class="control-label"></label>
<input asp-for="Invoice.InvNumber" class="form-control" />
<span asp-validation-for="Invoice.InvNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Invoice.InvAmount" class="control-label"></label>
<input asp-for="Invoice.InvAmount" class="form-control" />
<span asp-validation-for="Invoice.InvAmount" class="text-danger"></span>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="InvIssued" id="InvIssued" value="true" checked="">
<label class="form-check-label" asp-for="Invoice.InvIssued">
The invoice has been issued.
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="InvNotIssed" id="InvNotIssed" value="false">
<label class="form-check-label" asp-for="Invoice.InvIssued">
The invoice has not been issued.
</label>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
and my page model is:
public class AddInvoiceModel : PageModel
{
private readonly InvoicesAppContext InvoiceContext;
public AddInvoiceModel(InvoicesAppContext contextInvoices)
{
InvoiceContext = contextInvoices;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Invoice Invoice { get; set; }
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
InvoiceContext.Invoice.Add(Invoice);
await InvoiceContext.SaveChangesAsync();
return RedirectToPage("../Index");
}
}
So my questions are:
AddInvoice
Page Model?CustomerId
is an int
and not the actual name of the customer. How do I retrieve the names and not the id?Thank you all for your help. And sorry for this basic stuff. I am still learning.
Usually, when creating an invoice, you know who the customer is, and therefore their ID. You assign this to the Invoice in OnGet
:
public IActionResult OnGet()
{
Invoice = new Invoice{ CustomerId = id };
return Page();
}
It's then a question of adding that ID to the invoice form so that it is posted along with the rest of the invoice details. You'd add it to the form as a hidden field:
<input asp-for="Invoice.CustomerId" type="hidden" />
If you don't know who the customer is, you provide a select list containing customers so that the user can select one for the invoice. You bind the select element to the Invoice.CustomerId
property:
<select asp-for="Invoice.CustomerId" asp-items="Model.CustomerOptions"></select>
The CustomerOptions
is a SelectList
that you populate in the OnGet
handler:
public SelectList CustomerOptions { get; set; }
public async Task<IActionResult> OnGet()
{
CustomerOptions = new SelectList(await db.Customers.Select(x => new SelectListItem{
Value = x.CustomerId.ToString(),
Text = x.CustomerName
}).ToListAsync(), nameof(SelectListItem.Value), nameof(SelectListItem.Text));
return Page();
}