asp.net-corerazor-pagescalculated-field

Add or Subtract Fields on a Create Razor Page and Display Result on Page?


Let's say I have a Model:

using System.ComponentModel.DataAnnotations;

namespace Test.Model
{
    public class Balance
    {
        [Key]
        public int Id
        [Display(Name = "Invoice Amount")] 
        public int? InvoiceAmount { get; set; }
        [Display(Name = "Payment Amount")] 
        public int? PaymentAmount { get; set; }
        public int Balance {get; set; }
        {
             InvoiceAmount - PaymentAmount
        }
    }
}

I don't need to store the Balance in the database, as I can always calculate it, but how would I display it on a create page when someone is creating a record and inputting the InvoiceAmount and PaymentAmount?

How would I do that BEFORE I have submitted the form and committed the InvoiceAmount and PaymentAmount to the database?

And what if they change either the InvoiceAmount or PaymentAmount after entering them? How can I have the Balance change on the fly like that? I'm thinking both the InvoiceAmount and the PaymentAmount would need some type of event (is that the right word - I'm not a programmer) tied to them?

I've searched here, but haven't found anything explained that has been for a Create page. Only fields that are already bound and being reported on.

Looking to understand how this works using this very basic example.


Solution

  • I don't need to store the Balance in the database, as I can always calculate it,

    If you want to have a property in your model class without being stored in database, you can use the [NotMapped] attribute to ignore the property.

    but how would I display it on a create page when someone is creating a record and inputting the InvoiceAmount and PaymentAmount?

    How would I do that BEFORE I have submitted the form and committed the InvoiceAmount and PaymentAmount to the database?

    And what if they change either the InvoiceAmount or PaymentAmount after entering them?

    You define the calculation in the model, this way requires server-side interaction or a page refresh which can update the value. To achieve real-time updates of the Balance field, you can use Jquery to listen for changes in the InvoiceAmount and PaymentAmount input fields.

    A working demo you could follow:

    Model

    public class Balance
    {
        [Key]
        public int Id { get; set; }
        [Display(Name = "Invoice Amount")]
        public int? InvoiceAmount { get; set; }
        [Display(Name = "Payment Amount")]
        public int? PaymentAmount { get; set; }
        [NotMapped] // This will ensure that Balance is not created in the database
        public int BalanceAmount { get; set; }
    }
    

    View

    @model Balance
    <form>
        Invoice Amount: <input asp-for="InvoiceAmount"><br>
        Payment Amount: <input asp-for="PaymentAmount"><br>
        Balance: <span id="balanceDisplay">0</span><br>
    </form>
    @section Scripts
    {
        <script type="text/javascript">
            $(document).ready(function () {
                function updateBalance() {
                    var invoiceAmount = parseInt($('#InvoiceAmount').val()) || 0;
                    var paymentAmount = parseInt($('#PaymentAmount').val()) || 0;
    
                    var balance = invoiceAmount - paymentAmount;
                    $('#balanceDisplay').text(balance);
                }
    
                $('#InvoiceAmount, #PaymentAmount').on('input', updateBalance);
            });
        </script>
    }
    

    Update:

    I could not get this to work in my own app until I added id="InvoiceAmount" to <input asp=for"Balance.InvoiceAmount"> and likewise id="PaymentAmount" to

    The tag helper asp-for will generate the id and name attribute by default, the value of your tag helper is Balance.InvoiceAmount, it will generate the id="Balance_InvoiceAmount" and name="Balance.InvoiceAmount". Any way, your solution to define id to override the tag hepler generated id is also a good solution.