javascriptjquerycssasp.net-corerazor

Modal popup not showing within foreach divs but is displayed outside of the divs


So I've been learning asp.net core and razor, and it's been awesome. I finally created the div structure bound to my sql data, and that was pretty cool.

My next step is to display a modal popup when I click on one of the divs generated in the foreach loop.

I added the input button just before the foreach, and the modal popup is displayed. When I try to implement this within the divs created in the @foreach, the popup doesn't show.

What am I doing wrong? The references to the jquery css and js libraries are in _Layout.cshtml.

As an additional mini-question: how can I make the background darker when the modal popup is shown?

    @page
    @model Products.Pages.IndexModel
@{
}
<input type="button" id="btnModalPopup" value="Modal Popup before foreach loop" />
<br />
<br />
@foreach (var product in Model.availableProducts)
{

    <div style="float: left;display: inline-block; vertical-align: top>
        <div>
            <input type="button" id="btnModalPopup" value="Modal Popup in foreach loop" />
            @* <input type="image" src="@product.ImageUrl" id="btnModalPopup" alt="Submit" width="240" height="240"> *@
        </div>
        <div style="float: left;height: 60px">
            <div>@product.ProductName</div>
        </div>

        <div>$@product.Price</div>
    </div>
}
<script type="text/javascript">
    $("#btnModalPopup").on("click", function () {
        $("#modal_dialog").dialog({
            title: "jQuery Modal Dialog Popup",
            buttons: {
                Close: function () {
                    $(this).dialog('close');
                }
            },
            modal: true
        });
    });
</script>
<div id="modal_dialog" style="display: none">
    Modal panel popup
</div>

Solution

    1. Duplicate IDs
    2. You need to delegate from the nearest static container (useful if you use Ajax)
    3. Use data attributes instead of IDs

    $("#productsContainer").on("click", ".openProductModal", function() {
      var productId = $(this).data("product-id");
      $("#selectedProductId").text(productId); // Update modal with product ID
      $("#modal_dialog").dialog({
        title: "Product Details",
        buttons: {
          Close: function() {
            $(this).dialog('close');
          }
        },
        modal: true
      });
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.14.1/jquery-ui.min.js"></script>
    @page
    @model Products.Pages.IndexModel
    @{
    }
    <input type="button" id="btnModalPopupBefore" value="Modal Popup before foreach loop" />
    <br />
    <br />
    <div id="productsContainer">
      @foreach (var product in Model.availableProducts) {
      <div style="float: left;display: inline-block; vertical-align: top">
        <div>
          <button class="openProductModal" data-product-id="@product.ProductId">View Details</button>
          @* You could also use an image button: *@
          @* <button class="openProductModal" data-product-id="@product.ProductId" style="border:none; background:none; padding:0;">
                            <img src="@product.ImageUrl" alt="Product Image" width="240" height="240">
                        </button> *@
        </div>
        <div style="float: left;height: 60px">
          <div>@product.ProductName</div>
        </div>
        <div>$@product.Price</div>
      </div>
      }
    </div>
    <div id="modal_dialog" style="display: none">
      Product ID: <span id="selectedProductId"></span><br />
    </div>