not correctly traversing through DOM in table - javascript

The simplified code below is supposed to add a value in cell-row 2-colum 2 in a table depending on the value selected in row 1 colum 2 of this table. The (jquery) handler for this writing is triggered correctly (tested by console), but writing to the div element (using html() ) does not work, and I strongly suspect I dont traverse through the DOM correctly. I tried a few options (see comments) but none of them works. Where do I go wrong?
<table border="1"> <!--table ProductMain with only 1 row en 2 cells -->
<!--table ProductMain; cell r1c1-->
<tr>
<td>cell r1c1</td>
<!--table ProductMain; cell r1c2-->
<td>
<select class="eprodtype" name="ecorp_productid4">
<option selected="selected" value="" ></option>
<option value="val1" > val1</option>
<option value="val2" > val2</option>
</select>
</td>
</tr>
<!--table ProductMain; cell r2c1; -->
<tr>
<td>
<table border ='1'>
<tr class="r2"> <td> aval1 </td> <td> aval2 </td></tr>
</table>
</td>
<!--table ProductMain; cell r2c2;-->
<td class="r2c2">
<div class="ecorpproductwrapper"></div>
</td>
</tr>
</table>
$(document).ready(function(){
$("body").on("change", ".eprodtype", function() {
var selectedvalue = $( this ).val();
console.log("SELECT selectedvalue "+selectedvalue);
//NONE OF THE FOLLOWING OPTIONS WORK
//$(this).parent().children("td.r2c2").children("div.ecorpproductwrapper").html("<p> Chosen: " + selectedvalue + "</p>");
//$(this).parent().children("tr.r2").children("td.r2c2").children("div.ecorpproductwrapper").html("<p> Chosen: " + selectedvalue + "</p>");
$(this).parent().parent().find("div.ecorpproductwrapper").html("<p> Chosen: " + selectedvalue + "</p>");
//$(this).parent().children("div.ecorpproductwrapper").html("<p> Chosen: " + selectedvalue + "</p>");
});
}); //$(document).ready

You needed one more parent call to go up to the table. However, you can clean the code by using closest instead to get the table, then find within that:
$(this).closest('table').find("div.ecorpproductwrapper").html("<p>Chosen: " + selectedvalue + "</p>");
Example fiddle

Related

Changing innerHTML doesn't update the page

I am trying to get the contents of a table cell to change when I click on it. Here is the page source:
function cellClick(c) {
alert(c + " is {" + document.getElementById(c).innerHtml + "}");
document.getElementById(c).innerHtml = "<b>It Works</b>";
alert(c + " is now {" + document.getElementById(c).innerHtml + "}");
}
<table border="1">
<tr>
<td id="Cell1" onclick='cellClick("Cell1")'>
Row 1
</td>
</tr>
<tr>
<td id='Cell2' onclick="cellClick('Cell2')">
Row 2
</td>
</tr>
</table>
Yes, I am aware that the calls in Cell1 and Cell2 switch the single and double-quotes around; I was testing that as well.
Anyway, the first time I click on a cell, its innerHtml value returns "undefined" (instead of "Row 1" or "Row 2"), and after it is set in the function, it shows the set value; when I click on that cell again, the value previously set by the function is there. However, the value on the page itself never changes.
This has been tried on:
Firefox (64-bit) 65.0.1
IE 11.2791 (which won't show the alerts)
Edge 38.14393
but all of them do the same thing - the value is set, but the page doesn't change.
What am I missing?
you have written badly innerHtml innerHTML
Your code does not work because on innerHTML case.
Secondly it will be tedious to add id to every td and pass argument with onclick. So you can use querySelectorAll then iterate this and add click event listener to it. On click get the innerHTML from the target and alert it
function cellClick(c) {
alert(c + " is {" + document.getElementById(c).innerHTML + "}");
document.getElementById(c).innerHtml = "<b>It Works</b>";
alert(c + " is now {" + document.getElementById(c).innerHTML + "}");
}
<table border="1">
<tr>
<td id="Cell1" onclick='cellClick("Cell1")'>
Row 1
</td>
</tr>
<tr>
<td id='Cell2' onclick="cellClick('Cell2')">
Row 2
</td>
</tr>
</table>
document.querySelectorAll('td').forEach((cell) => {
cell.addEventListener('click', (e) => {
let text = e.target.innerHTML.trim();
alert(text)
})
})
<table border="1">
<tr>
<td>
Row 1
</td>
</tr>
<tr>
<td>
Row 2
</td>
</tr>
</table>
document.querySelectorAll('td').forEach((cell) => {
cell.addEventListener('click', function(e) {
let text = this.innerHTML.trim();
alert(text)
})
})
<table border="1">
<tr>
<td>
Row 1
</td>
</tr>
<tr>
<td>
Row 2
</td>
</tr>
</table>
You can take the benefits of event delegation here.
It will create less number of event handlers in memory.
It is scalable and will have better performance.
Here is the code snippet for it.
function cellClick(e) {
if (e.target.tagName === "TD") { //e.target.tagname.toLowerCase() === "td")
console.log(e.target.innerHTML);
e.target.innerHTML = "<b>It Works</b>"
}
}
<table border="1" onclick='cellClick(event)'>
<tr>
<td id="Cell1">
Row 1
</td>
</tr>
<tr>
<td id='Cell2'>
Row 2
</td>
</tr>
</table>
Thanks!

how to trigger change event on current table rows index in jquery

The Tbody of below table was cloned more than 2 or 3 so I will get more than 2 tbody that contain Class selector .mbody and two of rows in a tbody. However I to used Jquery Change event to get the provinces data when a country selection was selected.
<div class="table-responsive">
<table class="table" id="addressList">
<thead>
<tr>
<th>{{ trans('multiple.country') }}</th>
<th>{{ trans('multiple.province') }}</th>
</tr>
</thead>
<tbody class="mbody">
<tr>
<td>
<select class="country" name="country[]">
<option value="">-</option>
#foreach($country as $vals)
<option value="{{$vals['iso_code_3']}}"
data-id="{{$vals['id']}}">
{{$detail['name']}} {{$vals['id']}}
</option>
#endforeach
</select>
</td>
<td>
<select class="provinces" id="provinces" name="provinces[]" style="width: 100%"></select>
</td>
<td></td>
</tr>
<tr>
<td>
<label> Fields Khmer</label>
<textarea class="form-control" name="fields_kh"></textarea>
</td>
<td>
<label>Fields English </label>
<textarea class="form-control" name="fields_en"></textarea>
</td>
</tr>
</tbody>
</table>
</div>
Javascript:
I want to get the provinces data after country was selected on the current rows of this tables
$(document).on('change', 'tbody.mbody tr td', function (e) {
"use strict";
if(typeof country === 'undefined')return;
var provinces = $('.provinces');
var pro = '<option value="">-</option>';
if ($(this).children('select').hasClass('country')) {
var countryId = parseInt($(".country").select2("data").element[0].dataset['id'])
provinces.select2('val', '');
$.each(country, function (inx, vals) {
if (parseInt(vals.id) === countryId) {
$.each(vals.provinces, function (inx, prov) {
pro += '<option value="' + prov.prov_gis + '" data-id="' + prov.id + '"> ' + prov.eng_name + ' </option>';
});
}
});
provinces.empty().append(pro);
}
});
Select2 don't wrap the provinces contain after append from JS
provinces.empty().append(pro);
Change your selectors to select the elements relative to your cloned tbody
var provinces = $(this).closest('tbody').find('.provinces');
var countryId = parseInt($(this).closest('tbody').find(".country").select2("data").element[0].dataset['id'])
When you clone the elements destroy the select2 before you clone them and then reinitialize it after the clone
to add elements use the select2 syntax
$("#select2").select2('data', {});
You need to find provinces of current td on whose select the onchange is triggerd.
var provinces = $(this).closest('tbody.mbody').find('.provinces');
Also the country should be fetched for current tbody.
var countryId = parseInt($(this).closest('tbody.mbody').find(".country").select2("data").element[0].dataset['id']);

Find the input box that is made hidden using hide() in jQuery

How can I find the input box that is made hidden using hide() in jQquery?
$("#tab1").on('click', 'td button.save', function() {
var $thisParent = $(this).parent().parent().find("td:eq(1)").find("input").val();
$(this).parent().parent().find("td:eq(1)").find("input").hide().end().html('<span>' + $thisParent + '</span>');
});
// Here, this portion is not working:
$("#tab1").on('click', 'td span.edit', function() {
$(this).parent().parent().find("td:eq(1)").find("input").show();
alert($(this).parent().parent().find("td:eq(1)").find("input").prop("tagName"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table id="tab1" width="80%">
<tr>
<td></td>
<td>
<input class="fillcolumn" type="text" />
</td>
<td>          <span class="edit">✎</span>  <span class="remove">✘</span>
</td>
<td>
Weightage:     
<select>
<option value="High">High</option>
<option value="Medium">Medium</option>
<option value="Low">Low</option>
</select>
</td>
<td>
<button class="save">Save</button>
</td>
</tr>
</table>
The above code is not working, I mean, it is not turn the input box on with its value. Any help?
Few things need to be changed,
The appended span does not have edit class, so the click won't fire.
Use append() instead of html() as html() deletes the <input> tag.
Instead of .parent().parent() use .closest()
$(this).closest('tr')
.find("td:eq(1)")
.find("input").hide().end()
.append('<span class="edit">' + $thisParent + '</span>');
Demo
$("#tab1").on('click', 'td button.save', function() {
var $thisParent = $(this).closest('tr').find("td:eq(1)").find("input").val();
$(this).closest('tr').find("td:eq(1)").find("input").hide().end().append('<span class="edit">' + $thisParent + '</span>');
});
// Here, this portion is not working
$("#tab1").on('click', 'td span.edit', function() {
$(this).closest('tr').find("td:eq(1)").find("input").show();
alert($(this).parent().parent().find("td:eq(1)").find("input").prop("tagName"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table id="tab1" width="80%">
<tr>
<td></td>
<td>
<input class="fillcolumn" type="text" />
</td>
<td>          <span class="edit">✎</span>  <span class="remove">✘</span>
</td>
<td>Weightage:     
<select>
<option value="High">High</option>
<option value="Medium">Medium</option>
<option value="Low">Low</option>
</select>
</td>
<td>
<button class="save">Save</button>
</td>
</tr>
</table>
Further improved use of selectors. Refer Fiddle
instead of html() use append()
$("#tab1").on('click', 'td button.save', function(){
var $thisParent = $(this).parent().parent().find("td:eq(1)").find("input").val();
$(this).parent().parent().find("td:eq(1)").find("input").hide().end().append('<span>' + $thisParent + '</span>');
});
When you call save the input is removed from the page.
I guess what you want to do is hide the input when save is clicked and add in a new span with the value from the input?
this should help you move on:
http://jsbin.com/pufiroxolo/1/edit?html,js,output
but like #Shaunack D says lots of optimisations can be done with this! I've just used what was provided so not to confuse things!
When you call JQuery hide() on a DOM element, JQuery adds the style attribute for the dom as display:none.
You can do a find() using jquery for all text boxes and then check if each textbox has the style display: none.
Something like this
var listOfHidden = []
$($.find("input")).each(function()
{
if ($(this).css("display") == 'none'){listOfHidden.push(this)}
});
//variable listOfHidden will have the list of all hidden text

Jquery clone event handling not working

I am trying to retrieve the index of the row when the user has clicked on the check box. It works for the codes that I have written for the first two rows when the check box are ticked. However when I tried to insert more rows, the index that I retrieve after the check box is tick gave me a false result, i.e -1.
Can anyone help me with this? I have research for a long time and I still can't get it to work. I tried setting the clone argument to true but it still failed.
//Insert a new row after the last row in the table
$("#add").click(function() {
clickCount++;
var numRows = $('#getnumRows').val();
var index = $('#mytable tbody>tr:last td:nth-child(2)').text();
var i=Number(index);
var intNumRow=Number(numRows)+i;
for (; i < intNumRow; i++)
{
$('#mytable tbody>tr:last').clone(true,true).insertAfter('#mytable tbody>tr:last');
//$("#mytable tbody>tr>td:last td:nth-child(1)").children('input').addClass('chkbox');
$('#mytable tbody>tr:last td:nth-child(2)').text(i+1);
var input= $('#mytable tbody>tr:last').find('td').children('input');
input.val('');
input.attr("checked", false);
}
});//end click tag
var chkBox=$("#mytable tbody>tr>td ").children('.chkbox');
chkBox.on('click',null,function ()
{
var isChecked=$('.chkbox');
if (isChecked.is(':checked')) {
var index=chkBox.index(this);
alert(index); //added alert to intentional check the index retrieve from the checked checkbox of the row![enter image description here][1]
var insertNewRow=ajaxNewRowInfo(partNo,serviceName);
insertNewRow.success(function(data)
{
var row=$('#mytable tbody>tr').eq(index);
for(i=2;i<data.length;i++)
{
$(row.children(' td:nth-child('+(i+3)+')')).children('input').val(data[i]);
}
});//insertNewRow end tag
}//if end tag
else{
alert('You Un-Checked it');
}
});//chckbox end tag
<!--Add rows -->
<div class="form-group">
<label class="col-sm-1 control-label" style='margin-top:0.6%;'>Rows</label>
<input class="form-control" style='width:100px;' type='text' id='getnumRows' placeholder='No.of Rows'>
<button type="submit" id="add" class="btn btn-success" style="margin-left:200px; margin-top:-35px; ">Add rows</button>
</div>
<!------------->
<tbody>
<tr id='tableRow1'>
<td><input type="checkbox" class='chkbox'/></td>
<td> 1</td>
<td>
<select class="form-control" class="serviceDropdown">
<option></option>
<option value='1'>Oil Change Service</option>
<option value='2'> Tyre Service</option>
<option value='3'>Vehicle Service</option>
<option value='4'>Battery Service</option>
<option value='5'>Clutch Brake Service</option>
<option value='6'>Suspension Service</option>
<option value='7'>Brake Service</option>
<option value='8'>Tuning and Diagnostic Service</option>
</select>
</td>
</tbody>
[The first image shows the alert box which the index of the check box row is able to retrieved. The second image shows when new rows are added through cloning, the index of the alert box shows -1.]
http://postimg.org/image/913o3lyuv/
http://postimg.org/image/fg2p0a5kn/
Consider Element Indexing w/ jQuery Index()
Ex. http://codepen.io/anon/pen/XJRJEg
If .index() is called on a collection of elements and a DOM element or
jQuery object is passed in, .index() returns an integer indicating the
position of the passed element relative to the original collection.
HTML
<table id="hi">
<thead>
<tr>
<th>Heading</th>
<th>Heading 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
jQuery
$( "table#hi tbody tr" ).click(function() {
var index = $( "table#hi tbody tr" ).index( this );
alert(index);
});
DOCUMENTATION

jQuery get value of unknown element within table cell

A table cell may contain an INPUT element, or a SELECT element, or some other element. I must get both the value and the class attributes from the element, in order to route code appropriately.
There will only be one element within the table cell (but the element type may change).
Problem: test1 and test2 are not returning desired values (classname and value for element in table cell).
jsFiddle Demo
HTML:
<table id="tbl">
<tr>
<td class="pid">12345</td>
<td class="tbl_vendor"><input class="vi" value="Ikea" /></td>
<td>Stove</td>
<td><input class="qty_in" value="1" /></td>
<td class="del">del</td>
</tr>
<tr>
<td class="pid">38674</td>
<td class="tbl_vendor">
<select class="vendSEL">
<option value="1">C.P.O.</option>
<option value="2">Knightin</option>
<option value="3">CanDine</option>
</select>
</td>
<td id="selTD"></td>
<td><input class="qty_in" value="1" /></td>
<td class="del">del</td>
</tr>
</table>
jQuery/javascript:
var $this, qty, thisRowNdx, thisTR, vendorTD;
$(document).on('keyup', '.qty_in', function() {
$this = $(this);
qty = this.value;
thisTR = $this.closest('tr')[0];
vendorTD = $this.closest('tr').find('.tbl_vendor');
var currVendorTagname = vendorTD.children()[0].tagName;
var test1 = vendorTD.children()[0].getAttribute['class'];
var test2 = vendorTD.children()[0].nodeValue;
alert('currVendorTagname: ' + currVendorTagname);
alert('test1: ' + test1);
alert('test2: ' + test2);
});
It's all a matter of finding the right reference. Or, this is even easier to read: the Mozilla Developer Network page.
Thanks to answers given for this question: JavaScript getting an elements class without any libraries
Solution:
var test1 = vendorTD.children()[0].className;
var test2 = vendorTD.children()[0].value;
Updated jsFiddle
Note that this should have worked, but didn't:
var test1 = vendorTD.children()[0].getAttribute['className'];

Categories