How can I utilize JavaScript in a Razor Page to link a table field based on a dropdown choice?

I'm currently developing an application that involves three key tables: Clients, Attendance, and Panels.

The Panels table allows for the assignment of Attendance to Clients. On the page for creating Attendance records, there's a dropdown list that displays the names of the available Panels. Below this dropdown, I've set up fields to show the panel cost, the amount already paid by the client, and the remaining outstanding balance.

Within the Panels table, there are details such as the date, name, and the cost (Panel Fee) associated with each panel.

My goal for the Create Attendance page is to populate the Panel Cost field automatically when a user selects a Panel Name from the dropdown and clicks outside it. It should retrieve the associated Panel Cost from the Panels table based on the selected option.

Once the Panel Cost is populated in this field, which should be read-only, I will input the Amount Paid, and the script should then calculate and display the Amount Outstanding.

As I lack JavaScript knowledge, I have made some progress with external help and through research, but I am unsure how to properly reference the Panel Name and Panel Cost fields to achieve this functionality.

Below is my current code configuration:

Attendance Create.cshtml:

@page
@model SampleApp.Pages.Attendances.CreateModel

    

Add Client to Panel


---Select Client Id---
---Select Panel---
---Status---
Add Panel -> Return to Client Return to Client

@section Scripts
{

function populatePanelCost() {
var selectedPanel = document.getElementById(“PanelDropdown”).value;
if (selectedPanel) {
var cost = panelCosts[selectedPanel];
document.getElementById(“PanelCostField”).value = cost;
}
}

    $(document).ready(function () {
        function calculateOutstanding() {
            var panelCost = parseFloat($('#PanelCostField').val()) || 0;
            var amountPaid = parseFloat($('#AmountPaidField').val()) || 0;
            $('#OutstandingAmountField').val(panelCost - amountPaid);
        }

        $('#PanelCostField, #AmountPaidField').on('input', calculateOutstanding);
    });
</script>
@{ 
    await Html.RenderPartialAsync("_ValidationScriptsPartial");
}

}

Additionally, in the Attendances Create.cs file:

namespace SampleApp.Pages.Attendances;

[BindProperties]

public class CreateModel : PageModel
{
private readonly ApplicationDbContext _db;

public Attendance Attendance { get; set; } = new Attendance();
public Client Client { get; set; }
public Panel Panel { get; set; }
public CreateModel(ApplicationDbContext db)
{
    _db = db;
}

public IEnumerable<Panel> DisplayPanelData { get; set; }
public IEnumerable<Client> DisplayClientData { get; set; }
public IEnumerable<Status> DisplayStatusData { get; set; }

public async Task OnGet(int clientid)
{
    Attendance.ClientId = clientid;

    await _db.Panel.Select(a => a.PanelName).ToListAsync();
    DisplayPanelData = await _db.Panel.ToListAsync();
    await _db.Client.Select(a => a.Id).ToListAsync();
    DisplayClientData = await _db.Client.ToListAsync();
    await _db.Status.Select(a => a.StatusDesc).ToListAsync();
    DisplayStatusData = await _db.Status.ToListAsync();
}

public async Task<IActionResult> OnPost()
{
    if (ModelState.IsValid)
    {
        _db.Attendance.Add(Attendance);
        await _db.SaveChangesAsync();
        TempData["success"] = "Client Panel Attendance added successfully.";
        ViewData["clientid2"] = Attendance.ClientId;
        return RedirectToPage("/Clients/Edit", new { id = ViewData["clientid2"] });
    }
    return Page();
}

}

Information about the Panel model:

namespace SampleApp.Model
{
public class Panel
{
[Key]
[Required]
public int Id { get; set; }

    [Display(Name = "Panel Name")]
    public string? PanelName { get; set; }

    [Display(Name = "Panel Date")]
    [DataType(DataType.Date)]
    public DateTime? PanelDate { get; set; }

    [Display(Name ="Fee")]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(6,2)")]
    public decimal? PanelFee { get; set; }
}

}

I would be grateful for any guidance you could provide. Thank you!

UPDATE: My current JavaScript code is:

    
$(document).ready(function () {
const panelCosts = {
@foreach (var p in Model.DisplayPanelData) {
@p.PanelName”: “@p.PanelFee”.ToString(System.Globalization.CultureInfo.InvariantCulture),
}
};

function populatePanelCost() {
    const cost = panelCosts[$("#PanelDropdown").val()];    
    $("#PanelCostField").val(cost).trigger('input');
}

function calculateOutstanding() {
    const panelCost = parseFloat($('#PanelCostField').val()) || 0;
    const amountPaid = parseFloat($('#AmountPaidField').val()) || 0;
    $('#OutstandingAmountField').val(panelCost - amountPaid);
}

$('#PanelCostField, #AmountPaidField').on('input', calculateOutstanding);
    }
</script>

This implementation does not seem to work. What am I doing wrong? After selecting an option in the Panel Assigned dropdown and moving away from it, the Panel Cost field remains empty. Furthermore, while entering the Amount Paid, the Outstanding Amount stays blank, likely because the Panel Cost is never assigned correctly. Do I need to adjust the updatePanelBalance function to something other than ‘input’?

To effectively link your table field based on dropdown selections in a Razor Page, it's crucial to ensure that your JavaScript is manipulating the DOM elements and data correctly. Let's break down a unique approach to resolving your issue:

  1. Verify JavaScript Object Initialization: Ensure that your panelCosts object correctly maps panel names to their respective panel fees. Pay special attention to formatting. Note that you should ensure the correct handling of decimal points and quotation marks.
  2. Synchronization of Dropdown and Input Fields: Modify your JavaScript to handle not only the selection via dropdown changes but also reactivity from initial loads. Here's an approach you might consider:
  3. $(document).ready(function () {
        const panelCosts = {
            @foreach (var panel in Model.DisplayPanelData) {
                "@panel.PanelName": "@panel.PanelFee"
            }
        };
    
        $('#PanelDropdown').change(function () {
            const selectedPanel = $(this).val();
            updatePanelCost(selectedPanel);
        });
    
        $('#AmountPaidField').on('input', function () {
            calculateOutstanding();
        });
    
        function updatePanelCost(selectedPanel) {
            const cost = panelCosts[selectedPanel];
            $('#PanelCostField').val(cost);
            calculateOutstanding();
        }
    
        function calculateOutstanding() {
            const panelCost = parseFloat($('#PanelCostField').val()) || 0;
            const amountPaid = parseFloat($('#AmountPaidField').val()) || 0;
            $('#OutstandingAmountField').val(panelCost - amountPaid);
        }
    });
    
  4. Error Handling and Debugging: Use browser console tools to ensure panelCosts is being populated correctly. You can add console.log() statements to both check the selected panel name and the panel cost returned.
  5. Keep the Inputs Responsive: Make sure panelCost and amountPaid values are updated in real-time. This requires watching for both click events on the dropdown and input events on the AmountPaid field.

By following these tips and ensuring proper data linkage and reactivity, you should be able to appropriately link the table fields based on dropdown choices in your application.

To link your table field with the dropdown selection efficiently in Razor Pages, you'll need to ensure your JavaScript functions work seamlessly with your assigned data. Here’s a straightforward approach you can adopt:

  1. Ensure the Data Mapping is Correct: Verify that your HTML page renders the JavaScript object panelCosts correctly. This object should accurately map each panel name to its respective cost using the syntax foreach statement.
  2. Check Element IDs: Ensure that the element IDs referenced in your JavaScript correspond exactly to those in your Razor Page.
  3. JavaScript Code Adjustments: Here is an optimized and slightly modified JavaScript code snippet that should work:
  4. $(document).ready(function () {
        const panelCosts = {
            @foreach (var panel in Model.DisplayPanelData) {
                "@panel.PanelName": "@panel.PanelFee".
            }
        };
        
        // Populate panel cost based on dropdown selection
        $('#PanelDropdown').change(function () {
            const selectedPanel = $(this).val();
            const cost = panelCosts[selectedPanel];
            $('#PanelCostField').val(cost);
            calculateOutstanding(); // recalculate outstanding
        });
    
        // Calculate outstanding amount
        $('#AmountPaidField').on('input', function () {
            calculateOutstanding();
        });
    
        function calculateOutstanding() {
            const panelCost = parseFloat($('#PanelCostField').val()) || 0;
            const amountPaid = parseFloat($('#AmountPaidField').val()) || 0;
            const outstanding = panelCost - amountPaid;
            $('#OutstandingAmountField').val(outstanding);
        }
    });
    
  5. Ensure Field Reactivity: Trigger the calculation function not only on input but also when the dropdown changes to account for any dynamic values.
  6. Debugging: Use browser developer tools to check if panelCosts is being correctly populated and ensure console.log() statements within your functions to trace the flow of data.

By following these steps, you should achieve the desired automatic field update and calculation for your application.