Selecting data out of the nth td element - javascript

I'm attempting to get the data("borgid") out of the following html:
<tr style="cursor:default;" class="odd">
<td class=" ">1</td>
<td class=" ">What was your favorite childhood pet's name?</td>
<td data-borgid="1" class=" ">Generic Hospital Networks</td>
<td class=" ">5173</td>
<td style="text-align:right;" class=" "><input type="button" value="Remove" name="1" class="deleteMeCQ" style="cursor:pointer;"></td>
</tr>
I have tried both $(':nth-child(2)', $(this)).data("borgid") and $tds.eq(2).data("borgid"). Both return "undefined". Thanks in advance.
See also: Is there a way to combine $(this) with :nth-child?
var a = [];
$("#ChallengeQuestionsTable tbody tr").each(function () {
var $tds = $(this).children('td');
var questionid = '';
var question = '';
var borgid = '';
if ($tds.length == 5) {
questionid = $tds.eq(0).html();
question = $tds.eq(1).html();
borgid = $(':nth-child(2)', $(this)).data("Borgid");
a.push('{ "questionid" : "' + questionid + '", "question" : "' + question + '", "borgid" : "' + borgid + '" }');
}
});

If you want to get borgid, you can select by existing attribute:
borgid = $($(this).find("[data-borgid]").get(0)).attr("data-borgid");

In general if you want to select the nth td you could go with
$("td:eq(1)")
e.g. to select the second td.
If you want to iterate over all <tr> and its <td> and say, you want to select the 2nd one, you would do it as follows:
$("tbody").find("tr").each(function(){
$(this).find("td:eq(1)").html("changed")
};
Here is a Fiddle to play with. And here is the documentation of :eq().

Does this work, if you grab the data by an attribute selector?
var borgid = $(this).find("td[data-borgid]").data("borgid");
It could also be beneficial to avoid ":nth-child", shall you change your HTML later.

Related

JavaScript TypeError: Cannot read property 'id' of undefined

Preface:
I have an HTML table where user fills in Name and URL of social networks where they have account. Each row has a checkbox. With the help of jQuery and JavaScript, on pressing Add Row button, a row is dynamically added to the table and on pressing delete row button those rows are deleted for which checkbox is checked.
Objective:
When selected rows are deleted, I want to assign id to input elements and checkboxes of every remaining row in serial manner, so that the rows are always serially sound.
Problem:
I am not able to find what makes it throw error, as childNodes[] do not seem to lead to unavailable element. Please help!
Snippet:
// variable to keep track of rows(records)
var social_recs_num = 1;
$(document).ready(function () {
$("#social_add_rec").click(function () {
social_recs_num++;
var markup = "<tr> <th scope=\"row\"> <div class=\"form-group\"> <div class=\"form-check\"> <input type=\"checkbox\" class=\"form-check-input\" id=\"social_rec" + social_recs_num + "\" name=\"social_rec\"> <label class=\"form-check-label\" for=\"social_rec" + social_recs_num + "\"> " + social_recs_num + "</label> </div></div></th> <td> <div class=\"form-group shadow-sm\"> <label for=\"name_social" + social_recs_num + "\">Select or Type</label> <input type=\"text\" list=\"name_social" + social_recs_num + "\" class=\"form-control\" placeholder=\"Name\"> <datalist id=\"name_social" + social_recs_num + "\"> <option value=\"Wikipedia\">Wikipedia</option> <option value=\"Youtube\">Youtube</option> <option value=\"Facebook\">Facebook</option> <option value=\"Twitter\">Twitter</option> <option value=\"Pinterest\">Pinterest</option> </datalist> </div></td><td> <div class=\"form-group shadow-sm\"> <textarea class=\"form-control\" id=\"url_social" + social_recs_num + "\" cols=\"30\" rows=\"1\" placeholder=\"URL\"></textarea> </div></td></tr>"; //in case of id we need to do it like: "min_sysreq" +social_recs_num...as social_recs_num has been incremented priorly it will be the row number of row to be added
$("table tbody").append(markup);
});
// Find and remove selected table rows...only condition is that there must be present attribute name='sysreq_rec' in input element for checkbox of every row
$("#social_delete_rec").click(function () {
$("table tbody").find('input[name="social_rec"]').each(function () {
if ($(this).is(":checked")) {
social_recs_num = social_recs_num - $(this).length;
$(this).parents("tr").remove();
}
});
// to be run when a row is deleted...this assigns ids to input elements in serial manner
var table = document.getElementById("mytab1");
var rowCount = table.rows.length;
// i has been initiated with 1, as header row is the 0th row
for (var i = 1; i < rowCount; i++) {
var row = table.rows[i];
// on this line, getting error: `Uncaught TypeError: Cannot read property 'id' of undefined`
row.childNodes[0].childNodes[0].childNodes[0].childNodes[0].id = "social_rec" + i;
row.childNodes[0].childNodes[0].childNodes[0].childNodes[1].for = "social_rec" + i;
row.childNodes[0].childNodes[0].childNodes[0].childNodes[1].innerHTML = " " + i;
row.childNodes[1].childNodes[0].childNodes[0].for = "name_social" + i;
row.childNodes[1].childNodes[0].childNodes[1].list = "name_social" + i;
row.childNodes[1].childNodes[0].childNodes[2].id = "name_social" + i;
row.childNodes[2].childNodes[0].childNodes[0].id = "url_social" + i;
//iterate through rows
//rows would be accessed using the "row" variable assigned in the for loop
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table table-bordered" id="mytab1">
<thead>
<tr>
<th scope="col">
#
</th>
<th scope="col">
Name
</th>
<th scope="col">
URL
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<div class="form-group">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="social_rec1" name="social_rec">
<label class="form-check-label" for="social_rec1"> 1</label>
</div>
</div>
</th>
<td>
<div class="form-group shadow-sm">
<label for="name_social1">Select or Type</label>
<input type="text" list="name_social1" class="form-control" placeholder="Name">
<datalist id="name_social1">
<option value="Wikipedia">Wikipedia</option>
<option value="Youtube">Youtube</option>
<option value="Facebook">Facebook</option>
<option value="Twitter">Twitter</option>
<option value="Pinterest">Pinterest</option>
</datalist>
</div>
</td>
<td>
<div class="form-group shadow-sm">
<textarea class="form-control" id="url_social1" cols="30" rows="1" placeholder="URL"></textarea>
</div>
</td>
</tr>
</tbody>
</table>
<button class="btn btn-primary" type="button" id="social_add_rec">Add Row</button>
<button class="btn btn-primary" type="button" id="social_delete_rec">Delete Row</button>
P.S. :
I have used jQuery and Bootstrap.
this question seemed close, but I think I don't have the same mistake.
Edit:
I need to display(or store) inputs by user, for which I wrote following JavaScript code.
var social = function () {
var val = "social:\n";
for (x = 1; x <= social_recs_num; x++) {
//where social_recs_num is number of rows
val = val + "\s\s-\n";
val = val + "\s\s\s\s" + "name: " + getElementById("name_social" + x) + "\n";
val = val + "\s\s\s\s" + "url: " + getElementById("url_social" + x) + "\n";
}
return val;
}
function social returns the value input by user in YAML format. For this code, when selected rows are deleted, I want to assign id to input elements and checkboxes of every remaining row in serial manner.
The Problem:
The issues you are seeing is because you are trying to get the 'childNodes' property of an html element. In order to access that property, you would have to cast the element as a jQuery object by adding '$( )' around it. In this case, that would be '$(row)'.
However, if you do that with your code, you still get errors because of the mess of nested .childNodes[0]. You could get it working using that existing code, however...
Suggested Refactoring:
...As other stated, there are more elegant ways to approach this problem. There are a number of ways you could tackle it, but given your current html I would refactor to something like this:
//...
// to be run when a row is deleted...this assigns ids to input elements in serial manner
$('#mytab1 tbody tr').each(function() {
var rowNum = $(this)[0].rowIndex;
var formcheck = $(this).find('.form-check');
formcheck.find('.form-check-input')[0].id = 'social_rec' + rowNum;
formcheck.find('.form-check-label')[0].for = 'social_rec' + rowNum;
formcheck.find('.form-check-label')[0].innerHTML = ' ' + rowNum;
var formName = $(this).find('td')[0];
$(formName).find('label')[0].for = 'social_rec' + rowNum;
$(formName).find('input')[0].list = 'social_rec' + rowNum;
$(formName).find('datalist')[0].id = 'social_rec' + rowNum;
var formUrl = $(this).find('td')[1];
$(formUrl).find('textarea')[0].id = 'social_rec' + rowNum;
});
//...
This replaces your for loop with a jquery .each loop and then uses the .find() function to loop up each control you want to manipulate. You'll also note that it is using the rowIndex() function to determine what number to assign the row.
I think the advantage to using an approach like this is that it's much easier to read the code and determine what controls are being affected. You could also additionally refactor your html to use classes that are unique to the controls you want to target, then you could just use the class selector to change those controls.
Hope that helps!

Two html objects (list, input) should generate a third list

I edited my question and started afresh.
I have a html form which contains 2 dropdown lists (#selProvincie, #selRegiune). when a new option from List1 is selected by user, List2 must change accordingly. The lists are generated thru PHP from MySQL querying two tables that have a foreign key relationship (this code is not shown for brevity).
HTML
<div class="input_frm">
<form method="post" action="<?php print data_clean($_SERVER["PHP_SELF"]);?>">
<table class="input_tbl">
<tr>
<td class="a">Select province</td>
<td class="b"><select id="selProvincie" name="Alfa" onchange="provincieChg()"></select></td>
<td class="c"><input class="button_face" type="submit" value="Submit"></td>
</tr>
<tr>
<td class="a">Select region</td>
<td class="b"><select id="selRegiune" name="Beta" onchange="regiuneChg()"></select></td>
<td class="c"></td>
</tr>
</table>
</form>
JavaScript
$(document).ready(function()
{
$.getJSON("/scripts/031A_GetProvincie.php", success = function(data)
{
var str_options = "";
for (var i=0; i < data.length; i++)
{
str_options += "<option value='" + data[i] + "'>" + data[i] + "</option>";
}
$("#selProvincie").append(str_options);
$("#selProvincie").change();
});
$("#selProvincie").change(function()
{
$.getJSON("/scripts/031B_GetProvRegiune.php?provincie=" + $(this).val(), success = function(data)
{
var str_options = "";
for (var i=0; i < data.length; i++)
{
str_options += "<option value='" + data[i] + "'>" + data[i] + "</option>";
}
$("#selRegiune").html("");
$("#selRegiune").append(str_options);
$("#selRegiune").change();
});
});
$("#selRegiune").change(function()
{
$.getJSON("/scripts/031C_GetProvRegiuneZona.php?regiune=" + $(this).val(), success = function(data)
{
var str_options = "";
for (var i=0; i < data.length; i++)
{
str_options += "<option value='" + data[i] + "'>" + data[i] + "</option>";
}
});
});
});
Using the above as an example (I'm new to JavaScript) I want to write a new form, which has a text input field (Text1) inserted between List1 and List2. List2 is generated from the option selected in List1 AND the text in Text1. But I really don't know how to use the process the input text in JavaScript to make the whole thing work.
HTML
<div class="input_frm">
<form method="post" action="<?php print dataclean($_SERVER["PHP_SELF"]);?>">
<table class="input_tbl">
<tr>
<td class="a">Select county</td>
<td class="b"><select id="selJudet" name="Alfa" onchange="judetChg()"></select></td>
<td class="c"><input class="button_face" type="submit" value="Submit"></td>
</tr>
<tr>
<td class="a">Zone wildcard text</td>
<td class="b"><select id="selText" name="Beta" onchange="textChg()"></select></td>
<td class="c"></td>
</tr>
<tr>
<td class="a">Select zone</td>
<td class="b"><select id="selZona" name="Gamma" onchange="zonaChg()"></select></td>
<td class="c"></td>
</tr>
</table>
</form>
</div>
Question: What's the JavaScript for this form ? List2 should change anytime a change occurs in either a new option is selected from List1 OR a new the string in Text1 changes.
Your question is still a little confusing, but I'm working on the assumptions that:
Users will select a country
The available regions will be filtered to show only regions within the selected country
The regions can also be filtered by entering an optional keyword
The "zones" (?) will be filtered based on the above three selections, and displayed to the user
With that in mind, this combination should achieve what you need. I've stripped back the HTML to the bare essentials. I've also change the id of the fields to match (what I think) you're trying to achieve.
The script could be optimised further, but this example should set you on the right path, but let me know if you have additional questions.
I've created a JsFiddle demonstrating how this works.
HTML
<form method="post" action="">
Country: <select id="selectCountry" name="Alfa"></select>
<br>
Region: <select id="selectRegion" name="Gamma"></select>
<br>
Wildcard: <input id="selectText" name="Beta">
</form>
Javascript
$(document).ready(function() {
// Change to match your URL
$.getJSON("/echo/json/", function(data) {
// Override with fake data because I can't see what the PHP generates
data = ['Australia', 'Japan', 'Uganda'];
var str_options = "";
for (var i=0; i < data.length; i++) {
str_options += "<option value='" + data[i] + "'>" + data[i] + "</option>";
}
$("#selectCountry").append(str_options);
});
// Filter regions based on the selected country
filterRegions = function() {
country = $("#selectCountry").val();
wildcard = $("#selectText").val();
console.log('Search for regions that match ' + country + ' and ' + wildcard);
// Change to match your PHP url
$.getJSON(" /echo/json/?country=" + country + "&wildcard=" + wildcard, function(data) {
// Override with fake data
data = ['California', 'Florida', 'Nevada'];
var str_options = "";
for (var i=0; i < data.length; i++) {
str_options += "<option value='" + data[i] + "'>" + data[i] + "</option>";
}
$("#selectRegion").html(str_options);
});
};
// Filter results based on the selected region and any text search
filterResults = function(){
country = $("#selectCountry").val();
wildcard = $("#selectText").val();
region = $("#selectRegion").val();
console.log('Search for zones that match ' + country + ' and ' + wildcard + ' and ' + region);
// Change to match your PHP url
$.getJSON("/echo/json/?country=" + country + "&region=" + region + "&wildcard=" + wildcard, function(data) {
// Display results as you need
});
};
// Attach event handlers to relevant DOM elements (instead of using inline change="Chg()" style functions)
$("#selectCountry").on("change", filterRegions);
$("#selectText").on("keyup", filterRegions);
$("#selectRegion").on("change", filterResults);
});
Notes:
You will need to update the URLs being used for each getJson() request. The URLs will need to pass the values from the <input> and <select> tags as $_GET variables.
In my example, I've used fake data as an example, so remove this from your script when testing it. E.g.
data = ['California', 'Florida', 'Nevada'];
You do not need to specify $_SERVER['PHP_SELF'] because a <form> tag defaults to itself in the absence of any action attribute. E.g.
<form method="post" action="<?php print data_clean($_SERVER["PHP_SELF"]);?>">
Can simply be:
<form method="post" action="">

jquery efficient way to select tablerow data

I have a table with multiple rows of the same pattern:
<tr role="row" class="even">
<td><input type="checkbox" id="valj4"></td>
<td>Generell grupp</td>
<td>IKT Ipad11- Mirko</td>
<td>Grundinställningar</td>
</tr>
Each row has a checkbox with unique ID, what would be the most efficient way to get a list of UUIDs for the rows with a checked checkbox. I would like to use jQuery.
$(function() {
var texts = [];
$('tr td:has(input:checkbox:checked) ~ td > a').each(function(i, e) {
texts.push($(e).attr('href'));
});
$('#result').html(texts.join('<br/>'));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr role="row" class="even">
<td>
<input type="checkbox" id="valj4" checked>
</td>
<td>Generell grupp</td>
<td>IKT Ipad11- Mirko (...5)
</td>
<td>Grundinställningar</td>
</tr>
<tr role="row" class="even">
<td>
<input type="checkbox" id="valj4">
</td>
<td>Generell grupp</td>
<td>IKT Ipad11- Mirko (...6)
</td>
<td>Grundinställningar</td>
</tr>
<tr role="row" class="even">
<td>
<input type="checkbox" id="valj4" checked>
</td>
<td>Generell grupp</td>
<td>IKT Ipad11- Mirko (...7)
</td>
<td>Grundinställningar</td>
</tr>
</table>
<div id="result"/>
Getting the UUID is then an easy exercise in string chopping.
I assume your table has an id and it's "#table-id":
$("#table-id").find(":checked")
would get you all the checked checkboxes and radio boxes.
$("#table-id").find("input[type='checkbox']:checked")
would get you all the checked checkboxes.
var ids = "";
$("#table-id").find("input[type='checkbox']:checked").each(function(){
ids += $(this).attr("id") + ",";
});
would give you a comma seperated list containing the ids of checked checkboxes in the table.
and the UUIDS list:
var UUIDs = "";
$("#table-id").find("input[type='checkbox']:checked").each(function(){
var href = $(this).closest("tr").find("td > a").first().attr("href");
var UUID = href.split('?')[1];
UUIDS += UUID + ",";
});
I would try the following
var ids = [];
$("#table input:checkbox:checked").each(function () {
var uuid = getParameter($(this).closest('tr').find('a').eq(0).attr('href'))
ids.push(uuid);
});
function getParameter(url) {
var regex = new RegExp("[\\?&]uuid=([^&#]*)"),
results = regex.exec(url);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
where #table is the id of your table
Example
jQuery('#formId').find('tr[class=even]').each(function () {
var rowId = "";
this.find('input[type=checkbox]').each(function() {
if(this.checked) {
rowId = "row" + $(this).val();
}
});
$(this).attr('id', rowId);
});
Create a new list of UUIDs.
var listOfUUIDs = [];
Get the checked input, go up to grandparent (the tr), then find the a inside it.
Go through the list of a's, adding UUIDs to the list.
$("tr input[checked=checked]").parent().parent().find("td a").each(function(){
listOfUUIDs.push(
$(this).prop('href').substr(indexOf("uuid=") + 5)
)
});
This should give you what you need.
$('tr').each(function(index) {
var $this = $(this),
input = $this.find('input'),
result = '';
if ( input.is(':checked') ) {
var uuid = $this.find('a').attr('href').replace(/^\/Home\/DeviceDetails\?uuid=/g, ""),
result = result + index + '. ' + input.attr('id') + ' has the uuid: ' + uuid + '<br />';
}
$('#result').html(result);
});
try this
$( "input[type=checkbox]" ).change(function() {
if($(this).is(":checked")) {
alert($(this).attr("id"));
}
});

How can append child elements of an element within the same element with some changes

I have the following html code
<button id="button_id" class="scalable add" title="Add email" type="button" onclick="emailsControl.addItem()" style="">
<tbody id="email_chain_container">
<tr>
<td class="nobr">
<input type="file" id="chain_Image_1" name="Image[1]" class="input-text" />
</td>
<td class="last"><input type="hidden" class="delete" name="email_chain[delete][]" />
<button onclick="emailsControl.deleteItem(event);return false" class="scalable delete icon-btn delete-product-option" title="Delete Image"><span><?php echo $this->__('Delete')?></span>
</button>
</td>
</tr>
</tbody>
when click on the button, i want to get the elements inside tbody and change the index in input element to index+1 and then append the element again to the tbody. This is the rough code i have used for it. However its not working
emailsControl = {
addItem: function ()
{
var chainParent = document.getElementById('email_chain_container');
var index = chainParent.childNodes.length; //get the number of tr elements present in tbody
var repeat = chainParent.innerHTML;
var newHTML = repeat.replace(index, (index + 1)).
replace('Image[' + (index) + ']', 'Image[' + (index + 1) + ']');
document.chainParent.appendChild(newHTML);
},
}
How can I do it in most effective way?Please suggest your ideas. Thanks in advance
Finally I have done it. Dont know whether this is the best method. But it worked !!!
<script type="text/javascipt">
emailsControl =
{
addItem : function ()
{
var chainParent = document.getElementById( 'email_chain_container' );
var trElements = chainParent . getElementsByTagName("tr");
var index = trElements . length;
var childElements = trElements[0] . innerHTML;
var newHTML = childElements . replace( /1/g , (index+1))
var tr = document . createElement('tr');
tr . innerHTML = newHTML;
chainParent . appendChild (tr);
},
}
</script>

How to append new rows to a table more than once?

I have a table within a form that I want to append new rows as the user enters input in the last row of the table.
$('table.form-table').on('input', function() {
var tableID = '#' + $(this).closest('table').attr('id');
if(jQuery(this).closest('tr').is(':last-child')) {
var currTR = $(this).closest('tr');
var currTRhtml = '<tr>' + currTR.html() + '</tr>';
var nextRow = jQuery(currTRhtml);
var checkBox = jQuery('<td class="border-right checks"><input type="checkbox" name="del_000" value="000"></td>');
jQuery(tableID).append(nextRow);
checkBox.appendTo(currTR);
}
});
And the html code if needed (simplified/trimmed):
<table class="form-table" id="XXX" border="1" cellspacing="0" cellpadding="3">
<thead>
<tr class="main"><th nowrap colspan="3" align="left"
class="border-left border-top border-right">
<h3>XXX</h3></th>
</tr>
<tr>
<th>header</th>
</tr>
</thead>
<tbody>
<tr>
<input type="hidden" name="isnew" value="">
<td >
<input type="text"
name="new_text"
value="">
</td>
</tr>
</tbody>
</table>
The problem is that this works only once and does not continue appending new rows. It's as if the last-child filtering does not get reset...
Any thoughts?
The problem is that you need to use the event's target, rather than "this". Right now "this" refers to the current table, but you need to refer to the current input box and then use closest() to find its parent tr (and :first-child to make sure it's the last one). So your code needs to look more like this:
$('table.form-table').on('input', function(e) {
var tableID = '#' + $(this).closest('table').attr('id');
if ($(e.target).closest('tr').is(':last-child')) {
var currTR = $(e.target).closest('tr');
var currTRhtml = '<tr>' + currTR.html() + '</tr>';
var nextRow = $(currTRhtml);
var checkBox = $('<td class="border-right checks"><input type="checkbox" name="del_000" value="000"></td>');
$(tableID).append(nextRow);
checkBox.appendTo(currTR);
}
});
Notice I'm passing the event as "e" and then referencing the current input box with $(e.target).
Here's a working JS fiddle.
I suspect the problem is that you need to delegate the input event as the appended rows do not exist on $(document).ready(). Try doing something like this to delegate the handler:
$(document).ready(function () {
$('table.form-table tbody').on('input', 'tr', function () {
var self = $(this),
tableID = '#' + self.closest('table').attr('id'),
currTR = self.closest('tr'),
currTRhtml = '<tr>' + currTR.html() + '</tr>',
nextRow = $(currTRhtml),
checkBox = $('<td class="border-right checks"><input type="checkbox" name="del_000" value="000"></td>');
if (currTR.is(':last-child')) {
$(tableID).append(nextRow);
checkBox.appendTo(currTR);
}
});
});
Fiddle: http://jsfiddle.net/KW7ET/

Categories