Home » Jquery » javascript – data- attribute not working to grab dynamic id from foreach-Exceptionshub

javascript – data- attribute not working to grab dynamic id from foreach-Exceptionshub

Posted by: admin February 24, 2020 Leave a comment

Questions:

I am using JS in a razor page to grab a dynamic ID from a col in a foreach.

In the past, I have used this and it worked fine. However, it seems that it is currently only grabbing the ID from the first col no matter which one I click.

Can someone please tell me if I am still doing this right? Or if I am missing something. Thank you.

View:

            <div class="list-group container" id="JobRequestMonitorTable">
            <div class="row list-group-item list-group-item-heading container divTableHeading" style="margin-bottom:0px;">
                <div class="col-md-4"> Job Code </div>
                <div class="col-md-4"> Description </div>
                <div class="col-md-2"> Schedule </div>
                <div class="col-md-1"> Running </div>
                <div class="col-md-1"></div>
            </div>
            @if (!string.IsNullOrEmpty(ViewBag.ErrorMessage))
            {
                <div class="row list-group-item-danger">
                    <div class="col-md-1 text-center">@ViewBag.ErrorMessage</div>
                </div>
            }
            @foreach (var item in Model.JobRequests)
            {
                <div class="row list-group-item container">
                    <div class="hidden" data-id="@item.JobRequestId" id="requestId">@item.JobRequestId</div>
                    <div class="col-md-4">@item.JobCode</div>
                    <div class="col-md-4">@item.Description</div>
                    <div class="col-md-2">@item.Schedule</div>
                    @if (@item.IsRunning == true)
                    {
                        <div class="col-md-1" style="margin-left:25px;"><span class="glyphicon glyphicon-ok"></span></div>
                        <div class="col-md-1"></div>
                    }
                    else
                    {
                        <div class="col-md-1"></div>
                        <div class="col-md-1">
                            <button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn"></button>
                        </div>
                    }
                </div>
            }
        </div>

JS:

        $("button").click(function () {

            var col = $('#requestId');
            var jobRequestId = col.data('Id');

             $.ajax({
                url: '@Url.Action("JobPollerParameters", "Tools")',
                 data: { "jobRequestId": jobRequestId},
                 success: function (results) {

                    $modal = $('#paramsModal');
                    $modal.modal("show");               

                     var arr = results;
                     //loop through arr created from dictionary to grab key(s)
                     for (var key in arr) {
                         if (arr.hasOwnProperty(key)) {
                             var myKey = key;
                         }
                     }

                     var name = myKey;
                     var value = results[myKey];

                    $('#modalName').text(name);
                     $('#modalMessage').text(value);

                }
            });
        });

Really the only important part to see in the JS is var col = $('#requestId');
var jobRequestId = col.data('Id');

But I suppose I will include the whole script just in case people ask.

How to&Answer:

Your loop is creating multiple #requestId and #paramModalBtn elements when id attributes have to be unique within the DOM. Change the logic to use common classes instead. Then you can traverse the DOM to find the elements related to the button which was clicked. Try this:

$("button").click(function() {
  var $col = $(this).closest('.row').find('.requestId');
  var jobRequestId = $col.data('id');
  console.log(jobRequestId);
  
  // AJAX request...
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">

<div class="row list-group-item container">
  <div class="hidden requestId" data-id="foo-bar">Job #1</div>
  <!-- other content... -->
  <div class="col-md-1">
    <button class="glyphicon glyphicon-list-alt btn btn-primary" name="paramsBtn"></button>
  </div>
</div>

<div class="row list-group-item container">
  <div class="hidden requestId" data-id="lorem-ipsum">#Job #2</div>
  <!-- other content... -->
  <div class="col-md-1">
    <button class="glyphicon glyphicon-list-alt btn btn-primary" name="paramsBtn"></button>
  </div>
</div>

Answer:

All of your items inside the loop are getting the same id attribute, it is hard-codded

id="requestId"

the jQuery selector $('#requestId') is getting back the first one, this is by design.

I would add a data-id to each button and select the relevant col with that id.

For example the button will get:

<button data-col-id="@item.JobRequestId" class="glyphicon glyphicon-list-alt btn btn-primary"></button>

And then, its easy to grab that info on click:

$("button").click(function () {

            var jobRequestId = $(this).data('col-id');

             $.ajax({
                url: '@Url.Action("JobPollerParameters", "Tools")',
                 data: { "jobRequestId": jobRequestId},
                 success: function (results) {

                    $modal = $('#paramsModal');
                    $modal.modal("show");               

                     var arr = results;
                     //loop through arr created from dictionary to grab key(s)
                     for (var key in arr) {
                         if (arr.hasOwnProperty(key)) {
                             var myKey = key;
                         }
                     }

                     var name = myKey;
                     var value = results[myKey];

                    $('#modalName').text(name);
                     $('#modalMessage').text(value);

                }
            });
        });

I like this solution as you are not depended on your HTML structure and hierarchy thus selectors won’t break often.

Answer:

Once you have a button for each item, you could also store the data into the button value attribute, which leads to a simple implementation in the JS:

$("button").click(function (e) {

    var jobRequestId = $(e.target).val();
    console.log(jobRequestId);

    $.ajax({
        url: '@Url.Action("JobPollerParameters", "Tools")',
         data: { "jobRequestId": jobRequestId},
         success: function (results) {

            $modal = $('#paramsModal');
            $modal.modal("show");               

             var arr = results;
             //loop through arr created from dictionary to grab key(s)
             for (var key in arr) {
                 if (arr.hasOwnProperty(key)) {
                     var myKey = key;
                 }
             }

             var name = myKey;
             var value = results[myKey];

            $('#modalName').text(name);
             $('#modalMessage').text(value);

        }
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="1">Job 1</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="2">Job 2</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="3">Job 3</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="4">Job 4</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="5">Job 5</button>

Obs.: value must be equal to @item.JobRequestId like so: <button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="@item.JobRequestId">Job 5</button>