OmniOwl
OmniOwl

Reputation: 5709

Looping through table returns undefined results

I have to make a dropdown of activities that a user can delete. The activities are held in a table which I'm trying to iterate over but I feel like I am almost there. I use Bootstrap 3 and jQuery. I'm still new to jQuery.

Here is the HTML I use to create a modal window, so I can put the control in there:

<div id="delete-activity-modal" class="modal fade" role="dialog">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h1>Delete Activity</h1>
            </div>
            <div class="modal-body">
                <div class="input-group">
                    <span class="input-group-addon" id="add-addon-styling">Choose Activity</span>
                    <select class="form-control" id="delete-activity-modal-dropdown">
                        <!-- Options Added via content-controller.js -->
                    </select>
                    <span class="input-group-addon" data-toggle="tooltip" data-placement="top"
                          title="Choose the activity from the drop-down menu you want to delete.">
                        <b>?</b>
                    </span>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-danger btn-bg" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>

Result

As you see above, that's what I get out. I should have had 6 results and they should have an activity ID and a Name but they come back as undefined so I'm probably doing it wrong :P

Here is the function I use to make the dropdown content:

function CreateActivityDeleteDropdown() {
    var dropdown = $('#delete-activity-modal-dropdown');
    $('#activityTable').each(function() {
        var activityId = $(this).attr("#activityId");
        var activityName = $(this).attr("#activityName");
        var dropdownDescription = activityId + " | " + activityName;
        var dropdownElement = '<option value="' + activityId + '">' + dropdownDescription + '</option>';
        $(dropdown).append(dropdownElement);
    });
}

This function is only called when you press a button, so the table does exist when I do this. The table that I need to look through is dynamically added when the website loads like this:

function GetActivityAbstracts() {
    $.getJSON(, function (testData) {
        var object = $.parseJSON(testData);
        var activityTable = '<tbody id="activityTable"></tbody>';
        $.each(object, function () {
            var activityId = this['ActivityId'];
            var activityName = this['ActivityName'];
            var activityResponsible = this['Responsible'];
            var activityEstimatedSavings = parseFloat(this['EstimatedSavings']).toFixed(2);
            var activityEstimatedStart = this['EstimatedStart'];
            var activityEstimatedEnd = this['EstimatedEnd'];
            var activityStatus = this['Status'];
            // TODO: Make more user-friendly Status Descriptions instead of C# enum values.
            var tableElement =
                    '<tr>' +
                    '<td id = "activityId" style = "vertical-align: middle; align: center;">'
                    + activityId + '</td>' +
                    '<td style = "vertical-align: middle;">' +
                    '<div class="status-circle" data-toggle="tooltip" data-placement="right"' +
                    'title=" ' + activityStatus + '" style="background-color:' +
                    GetColumnColor(activityStatus) + ';"></div></td>' +
                    '<td id = "activityName" style = "vertical-align: middle;">'
                    + activityName + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityResponsible + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedSavings + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedStart + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedEnd + '</td>' +
                    '</tr>';
            activityTable += tableElement;
        });
        $('#current-data-table').append(activityTable);

        /* This call is necessary because the table is added dynamically */
        $('[data-toggle="tooltip"').tooltip();
    });
}

The result:

enter image description here

Some JSON Sample data:

"{\"1\":{\"ActivityId\":1,\"ActivityName\":\"Noget Med Penge\",\"Responsible\":\"Name\",\"EstimatedSavings\":9001.0,\"EstimatedStart\":\"19-11-2015\",\"EstimatedEnd\":\"01-01-2016\",\"Status\":\"NA\"},\"2\":{\"ActivityId\":2,\"ActivityName\":\"We need to shut down the bluetooth RAM hard drive!\",\"Responsible\":\"Name\",\"EstimatedSavings\":24589.0,\"EstimatedStart\":\"23-05-2014\",\"EstimatedEnd\":\"10-12-2015\",\"Status\":\"ON_TRACK\"},\"3\":{\"ActivityId\":3,\"ActivityName\":\"We need to encode the wireless RAM interface!\",\"Responsible\":\"Name\",\"EstimatedSavings\":874561.0,\"EstimatedStart\":\"11-04-1970\",\"EstimatedEnd\":\"22-01-2016\",\"Status\":\"DONE\"},\"4\":{\"ActivityId\":4,\"ActivityName\":\"We need to reboot the open-source PNG program!\",\"Responsible\":\"Name\",\"EstimatedSavings\":812654.0,\"EstimatedStart\":\"18-08-2000\",\"EstimatedEnd\":\"19-04-2016\",\"Status\":\"ISSUE\"},\"5\":{\"ActivityId\":5,\"ActivityName\":\"We need to program 
the mobile CPU bus!\",\"Responsible\":\"Name\",\"EstimatedSavings\":-47998.0,\"EstimatedStart\":\"29-07-1982\",\"EstimatedEnd\":\"22-05-2016\",\"Status\":\"BEHIND\"},\"6\":{\"ActivityId\":6,\"ActivityName\":\"We need to network the optical GB port!\",\"Responsible\":\"Name\",\"EstimatedSavings\":74511.0,\"EstimatedStart\":\"23-10-1992\",\"EstimatedEnd\":\"27-09-2016\",\"Status\":\"ABANDONED\"}}"

Upvotes: 0

Views: 340

Answers (2)

Guruprasad J Rao
Guruprasad J Rao

Reputation: 29683

First of all GetActivityAbstracts will create duplicate ids as I said. In the above code <td id = "activityId" and <td id = "activityName" inside $.each will be duplicate. Also use .find instead of .attr to find the elements inside each tr So you either change id to class or add index from .each to generate unique ids.

function GetActivityAbstracts() {
    $.getJSON(, function (testData) {
        var object = $.parseJSON(testData);
        var activityTable = '<tbody id="activityTable"></tbody>';
        $.each(object, function (index,value) {
            //index here is used to generate unique ids
            var activityId = this['ActivityId'];
            var activityName = this['ActivityName'];
            var activityResponsible = this['Responsible'];
            var activityEstimatedSavings = parseFloat(this['EstimatedSavings']).toFixed(2);
            var activityEstimatedStart = this['EstimatedStart'];
            var activityEstimatedEnd = this['EstimatedEnd'];
            var activityStatus = this['Status'];
            // TODO: Make more user-friendly Status Descriptions instead of C# enum values.
            var tableElement =
                    '<tr>' +
                    '<td id = "activityId_'+index+'" style = "vertical-align: middle; align: center;">'
                    + activityId + '</td>' +
                    '<td style = "vertical-align: middle;">' +
                    '<div class="status-circle" data-toggle="tooltip" data-placement="right"' +
                    'title=" ' + activityStatus + '" style="background-color:' +
                    GetColumnColor(activityStatus) + ';"></div></td>' +
                    '<td id = "activityName_'+index+'" style = "vertical-align: middle;">'
                    + activityName + '</td>' +
                    //Add index for ids here
                    '<td style = "vertical-align: middle;">'
                    + activityResponsible + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedSavings + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedStart + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedEnd + '</td>' +
                    '</tr>';
            activityTable += tableElement;
        });
        $('#current-data-table').append(activityTable);

        /* This call is necessary because the table is added dynamically */
        $('[data-toggle="tooltip"').tooltip();
    });
}

Now once you have this unique elements generated you can loop through each trs as below:

function CreateActivityDeleteDropdown() {
    var dropdown = $('#delete-activity-modal-dropdown');
    $('tbody#activityTable tr').each(function() {
        var activityId = $(this).find("td [id^='activityId']").text();
        //get value from the td whose id starts with activityId
        var activityName = $(this).find("td [id^='activityName']").text();
        //get value from the td whose id start with activityName
        var dropdownDescription = activityId + " | " + activityName;
        var dropdownElement = '<option value="' + activityId + '">' + dropdownDescription + '</option>';
        $(dropdown).append(dropdownElement);
    });
}

Now if you change td's id to class as below:

function GetActivityAbstracts() {
    $.getJSON(, function (testData) {
        var object = $.parseJSON(testData);
        var activityTable = '<tbody id="activityTable"></tbody>';
        $.each(object, function () {
            var activityId = this['ActivityId'];
            var activityName = this['ActivityName'];
            var activityResponsible = this['Responsible'];
            var activityEstimatedSavings = parseFloat(this['EstimatedSavings']).toFixed(2);
            var activityEstimatedStart = this['EstimatedStart'];
            var activityEstimatedEnd = this['EstimatedEnd'];
            var activityStatus = this['Status'];
            // TODO: Make more user-friendly Status Descriptions instead of C# enum values.
            var tableElement =
                    '<tr>' +
                    '<td class = "activityId" style = "vertical-align: middle; align: center;">'
                    + activityId + '</td>' +
                    '<td style = "vertical-align: middle;">' +
                    '<div class="status-circle" data-toggle="tooltip" data-placement="right"' +
                    'title=" ' + activityStatus + '" style="background-color:' +
                    GetColumnColor(activityStatus) + ';"></div></td>' +
                    '<td class= "activityName" style = "vertical-align: middle;">'
                    + activityName + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityResponsible + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedSavings + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedStart + '</td>' +
                    '<td style = "vertical-align: middle;">'
                    + activityEstimatedEnd + '</td>' +
                    '</tr>';
            activityTable += tableElement;
        });
        $('#current-data-table').append(activityTable);

        /* This call is necessary because the table is added dynamically */
        $('[data-toggle="tooltip"').tooltip();
    });
}

You can just use .find again to get respective td with its class as below:

function CreateActivityDeleteDropdown() {
    var dropdown = $('#delete-activity-modal-dropdown');
    $('#activityTable tr td').each(function() {
        var activityId = $(this).find(".activityId").text();
        var activityName = $(this).find(".activityName").text();
        //getting using class
        var dropdownDescription = activityId + " | " + activityName;
        var dropdownElement = '<option value="' + activityId + '">' + dropdownDescription + '</option>';
        $(dropdown).append(dropdownElement);
    });
}

Update

Some more problems identified while creating DEMO

You were having var activityTable = '<tbody id="activityTable"></tbody>'; and then at the end, once you create a row you use to do activityTable += tableElement;. Since 'activityTablevariable already hadactivityTable +=used to append as...'which is why a newtbodywas getting created when appended toDOM. So either make ittbody` object by doing as below:

var activityTable = $('<tbody id="activityTable"></tbody>');

and then you can use .append to append the tr inside the created tbody as below:

$(activityTable).append(tableElement); 

instead of activityTable += tableElement;

OR

If you prefer to keep your way then just append </tbody> once all the rows have been added as below:

var activityTable = '<tbody id="activityTable">'; //remove from here

and after $.each finishes you can just do

activityTable+="</table>";

Upvotes: 1

L Ja
L Ja

Reputation: 1506

Edit (example):

HTML:

<table>
    <thead>
        <th>
            Activity ID
        </th>
        <th>
            Status
        </th>
        <th>
            Activity name
        </th>
    </thead>
    <tbody id="activityTable">
    </tbody>
</table>

<select>
</select>

JS:

$(document).ready(function(){
    var JSONData = [[1,1,"name1"], [2,1,"name2"]];
    var html = "";
    var count = 0;
    $.each(JSONData, function(){
        html += "<tr>";
        html += "<td data-type='id'>" + JSONData[count][0] + "</td>";
        html += "<td data-type='status'>" + JSONData[count][1] + "</td>";
        html += "<td data-type='name'>" + JSONData[count][2] + "</td>";
        html += "</tr>";
        count++;
    });
    var createOption;
    $("#activityTable").html(html);
    $("select").html("");
    $("#activityTable tr").each(function(){
        var data_id = $(this).find("td[data-type=id]").html();
        var data_name = $(this).find("td[data-type=name]").html();
        createOption = "<option>" + data_id + " | " + data_name;
        $("select").append(createOption);
    });
});

Output:

enter image description here

Demo: Click

Upvotes: 0

Related Questions