jQuery - Detect TD ID on click - javascript

I'm trying to get a TD ID when I'm clicking on a table's row.
I've searched for ways to realize this, and found a way. But everytime I'm clicking, an alert pops up but it's an empty text. Using the console I saw that's the error code is "undefined".
Here's my code :
function chooseCell() {
let square = 0;
let squareNumber = 0;
$("td").click((e) => {
let data = $(this).attr('id');
alert (data);
for (square in squarePositions) {
squareNumber += 1;
if (square[1] <= e.pageX <= square[3] && square[0] <= e.pageY <= square[2]) {
alert(squareNumber);
alert("Square Number : " + squareNumber);
}
}
}
)}
If I replace the alert(data) by :
alert($('td').attr('id'));
The alert pops up the first table's TD. Whenever I click on a different TD, the first ID is displayed
Does someone know how to display the current clicked id ? There were no answers for my problem on Google and SOF
Thank you very much, best regards.

You are using an arrow function for your event handler.
An arrow function does not newly define its own this when it's being
executed in the global context; instead, the this value of the
enclosing execution context is used, equivalent to treating this as
closure value.
$("td").click((e) => {
let data = $(this).attr('id');
alert (data);
// ...
});
Hence in your code this doesn't refer to the td as you expect it to.
You can use the event.target to access the td with the following code
let data = $(e.target).attr('id');
Or you can also use a regular function instead of the arrow function and now this would refer td
$("td").click(function(e){
let data = $(this).attr('id');
alert (data);
// ...
});

Related

Error trying to overlay and remove elements with removeChild

i have a problem in the following code snippet.
for (var i=0;i<data.parlist.length;i++){
var inp = document.createElement("input")
var label = document.createElement("label")
var labelValue = document.createElement("label")
var subDiv = document.createElement("div")
var br = document.createElement("br")
try{
var dBtn = document.getElementById(data.parlist[i].id);
var dLabel = document.getElementById(data.parlist[i].id + " label")
var dDiv = document.getElementById(data.parlist[i].id +" div");
var inprad = document.getElementById(data.parlist[i].id+" inp_rad");
var dLabelRad = document.getElementById(data.parlist[i].id + " label_rad")
var dSubDiv = document.getElementById(data.parlist[i].id +" div_rad");
dSubDiv.replaceChild(inprad);
dSubDiv.removeChild(dLabelRad);
dDiv.removeChild(dSubDiv);
dDiv.removeChild(dBtn);
dDiv.removeChild(dLabel);
myDiv.removeChild(dDiv);
}catch{
console.log("no")
}
This for loop is inside a function that when clicking on a button of a station shows the parameters.in this way:
What you see in the images works, but the problem that I have come to try to clarify is that when I press the button for example as station 1 appears in the image and then I press the button for example of station 2 the try that is supposed to you must remove the previous parameters with removeChild does not work, the parameters of station 1 remain in the div and the parameters of station 2 are added below these instead of being removed
Within the try there is a problem but I do not know what it is, I say this because when I check the page and open the console I get the message that I left in the catch a "no"
Thanks for reading my problem and any suggestions are welcome as I am desperate to find a solution.
You need to pass 2 inputs to the replaceChild function.
parentNode.replaceChild(newChild, oldChild);
For more info refer Mozilla docs here.
Here is some additional advice
When you log for debugging, use some meaningful messages. In your case you could do
try {
...
} catch (err) {
console.log(err);
}
From the questions nothing is clear about what is there in data.parlist and whether that is implemented properly.

JavaScript global array undefined although it shows in alert

I have written a JQuery script in SharePoint to truncate a multiple lines of text column. Below is the script:
<script>
window.$divs = [];
window.$i = 0;
window.textFull = new Array();
$(document).ready(function(){
window.setInterval(function(){
/// call your function here
$divs = $("[class^=ExternalClass]");
for($i=0;$i<$divs.length;$i++)
{
textFull[$i] = $($divs[$i]).html();
if(typeof textFull[$i] != 'undefined' && textFull[$i].length > 50)
{
//alert($textFull[$i]); this alert show the correct text
$($divs[$i]).html(textFull[$i].substring(0,49)+"<a href='javascript:alert(textFull[$i]);'>...more</a>");
}
}
}, 500);
});
</script>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
In the above code "javascript:alert(textFull[$i])" shows 'undefined' in alert. But the alert above it shows correct text. Also I when I use a variable instead of an array it works fine in the alert inside anchor tag. I have also declared the array as global. So what am I missing?
You are running into the classic problem using for loop without using a closure to keep track of the index with
No need to create that array if all it is used for is to modify the html
Can do that much simpler using html(fn) and a jQuery event handler
$("[class^=ExternalClass]").html(function(index, oldhtml){
if(oldhtml.length >=50){
// store the full html in element data
$(this).data('html', oldhtml)
return oldhtml.substring(0,49)+"<a class="more-btn">...more</a>"
} else{
return oldhtml
}
}).find('.more-btn').click(function(){
var $div = $(this).parent();
$div.html( $div.data('html'));
});

Using this within functions called with onclick event in Javascript

I'm currently building a small Todo list application using vanilla Javascript but I'm having some issues creating a delete button that onClick removes it's parent element.
From what I have read, when an onClick is called in Javascript the this keyword can be used to refer to the element that called the function. With this in mind I have the following code:
window.onload = initialiseTodo;
function addRecord(){
var title = document.getElementById('issueTitle');
var issueContent = document.getElementById('issueContent');
var contentArea = document.getElementById('contentArea');
if(title.value.length > 0 && issueContent.value.length > 0){
var newItem = document.createElement('div');
newItem.id = 'task' + count++;
newItem.className = 'task';
newItem.innerHTML = '<div class="taskbody"><h1>' + title.value + '</h1>'+ issueContent.value + '</div><div class="deleteContainer">'
+ '<a class="delete">DELETE</a></div>';
contentArea.appendChild(newItem);
assignDeleteOnclick();
}
}
function deleteRecord(){
this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
}
function assignDeleteOnclick(){
var deleteArray = document.getElementsByClassName('delete');
for(var i=0;i<deleteArray.length;i++){
deleteArray[i].onclick= deleteRecord();
}
}
function initialiseTodo(){
var btn_addRecord = document.getElementById('addRecord');
btn_addRecord.onclick = addRecord;
}
Basically I have a form that has two fields. When these fields are filled and the addRecord button is clicked a new div is added at the bottom of the page. This div contains a delete button. After the creation of this I assign an onclick event to the delete button which assigns the deleteRecord function when the delete button is clicked. My issue is with the deleteRecord function. I have used this to refer to the calling element (the delete button) and wish to remove the task div that is the outermost container however I current get a message that says: 'Cannot read property 'parentNode' of undefined ' which suggests to me the this keyword is not working correctly.
Any help would be greatly appreciated.
I've added the full code to a fiddle.
http://jsfiddle.net/jezzipin/Bd8AR/
J
You need to provide the element itself as a parameter. I did so by changing the html to include onclick="deleteRecord(this)" to make it a little easier to deal with. This means you can remove the assignDeleteOnclick() function
function deleteRecord(elem){
elem.parentNode.parentNode.remove();
}
Demo
You might style the .content to be hidden better if there are no elements to prevent that extra white space
Edit
Since you don't want an inline onclick, you can do it with js the same:
function deleteRecord(elem){
elem.parentNode.parentNode.remove();
}
function assignDeleteOnclick(){
var deleteArray = document.getElementsByClassName('delete');
for(var i=0;i<deleteArray.length;i++){
// Has to be enveloped in a function() { } or else context is lost
deleteArray[i].onclick=function() { deleteRecord(this); }
}
}
Demo

Adding a custom attribute in ASP.NET. accessing it in JQuery

I have a table that is created in ASP.NET C# code behind. The table has several levels of groupings, and when I create the rows for the outer most grouping, I add an custom attribute as follows:
foreach (Table2Row row in Table2Data)
{
// skipping a bunch of irrelevent stuff
...
tr_group.Attributes.Add("RowsToToggle", String.Format(".InnerRowGroupId_{0}", row.GroupHeaderId));
...
}
The attribute is the CSS class name of the inner level rows that I would like to toggle. When the user clicks on the outer level row, I would like to call JQuery Toggle function for all inner level rows that match the custom attribute.
To achieve that effect, I have attached an onclick event to the header rows with the following script in the aspx file:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
}
});
function ToggleOnRowClick(row) {
var r = $('#' + row.id);
var innerRows = r.attr('RowsToToggle');
$(innerRows ).toggle();
}
So, clicking anywhere on the header row should call the function ToggleOnRowClick, which should then toggle the set of rows below it via the custom attribute RowsToToggle.
When I set a (FireBug) break point in the ToggleOnRow function, the variable r appears to be pointing to the correct object. However, innerRows is not getting set but instead remains null. So am I setting the custom attribute incorrectly in ASP.NET or reading in incorrectly in JQuery?
You did not post the code to generate inner level rows, I am assuming you sat proper classes to them.
There are few issues with the jquery you posted. This line wouldn't work:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
You don't have any groupRows property defined for table object.
We don't care about table row anymore, we care about groupRows[i] and want to pass it to ToggleOnRowClick function.
This line in next function is also wrong:var r = $('#' + row.id);
Solution: Change your script to this:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
groupRows[i].onclick = function () { ToggleOnRowClick(this); }
}
});
function ToggleOnRowClick(row) {
//var r = $('#' + row.id);
var innerRows = $(row).attr('RowsToToggle');
$("." + innerRows).toggle();
}
I have tested the code with dummy data. So if you have any issue, PM me.
This line is your culprit:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i])
By the time the event handler runs, table.rows might still exist, but i will be set to groupRows.length+1, which is out of bounds for the array. The handler will get called with an argument of undefined.
Remember, Javascript is an interpreted language! The expression "table.rows[i]" will get interpeted when the handler runs. It will use the last value of i (which will still be set to the value that caused your for loop to end, groupRows.length+1).
Just use
table.groupRows[i].onclick = function () { ToggleOnRowClick(this) }
So, First you shouldn't use custom attributes... they are a sin!
Please use data attributes instead, so that is what I'm going to use in the code, should be an easy fix regardless.
If this doesn't work then I'd be very very interested in seeing a dumbed down HTML snippet of the actual output.
$(document).ready(function () {
$('#MYTABLE').on('click', '.Table2GroupHeader', function() {
var attr_if_you_insist_on_sinning = $(this).attr("RowsToToggle");
var data_if_you_like_not_sinning = $(this).data("RowsToToggle");
//if the row is like <tr data-RowsToToggle=".BLAH" or th etc
//asumming you set the attribute to .BLAH then:
var rows_to_toggle = $(data_if_you_like_not_sinning);
rows_to_toggle.toggle();
//assuming you set it to BLAH then:
var rows_to_toggle = $("."+ data_if_you_like_not_sinning);
rows_to_toggle.toggle();
});
});
$(document).ready(function () {
$('#<%= Table2MainTable.ClientID %> .Table2GroupHeader').each(function(){
$(this).click(function(){
$(this).toggle();
});
});
});

Javascript - Dynamically assign onclick event in the loop

I have very simple html page with js code:
<html>
<head>
<title></title>
</head>
<body>
<div id="divButtons">
</div>
<script type="text/javascript">
var arrOptions = new Array();
for (var i = 0; i < 10; i++) {
arrOptions[i] = "option" + i;
}
for (var i = 0; i < arrOptions.length; i++) {
var btnShow = document.createElement("input");
btnShow.setAttribute("type", "button");
btnShow.value = "Show Me Option";
var optionPar = arrOptions[i];
btnShow.onclick = function() {
showParam(optionPar);
}
document.getElementById('divButtons').appendChild(btnShow);
}
function showParam(value) {
alert(value);
}
</script>
</body>
</html>
That page binds 10 buttons, but when you click on any button it always shows alert "option9". How is it possible assign onclick event to show correspondent option !?
Thanks!
You'll have to do something like this:
btnShow.onclick = (function(opt) {
return function() {
showParam(opt);
};
})(arrOptions[i]);
Consider the fact that when the onclick() function is executed, all it has is:
showParam(optionPar);
, verbatim. The optionPar will be resolve at the time the click event is executed, and at this point it most likely be the latest value you assigned to it. You should generally avoid passing variables in such a way.
The problem you are trying to solve is best solved by re-writing the piece such as:
btnShow.value = "Show Me Option";
var optionPar = arrOptions[i];
btnShow.optionPar = optionPar;
btnShow.onclick = function(e) {
// if I'm not mistaking on how to reference the source of the event.
// and if it would work in all the browsers. But that's the idea.
showParam(e.source.optionPar);
}
The accepted answer seems to work, but seems to be confusing and a somewhat cumbersome way to do it. A better way perhaps might be to use the data attribute for the element you're looking to assign the event listener for. It's simple, easy to understand, and way less code. Here's an example:
btnShow.data = arrOptions[i];
btnShow.onclick = function() {
showParam(this.data);
}
I attach an event handler:
window.onload = function() {
var folderElement;
tagFolders = document.getElementById("folders");
for (i = 0; i < folders.length; i++) {
folderElement = folderButtons[i];
folderElement = document.createElement("button");
folderElement.setAttribute("id", folders[i]);
folderElement.setAttribute("type", "button");
folderElement.innerHTML = folders[i];
if (typeof window.addEventListener !== "undefined") {
folderElement.addEventListener("click", getFolderElement, false);
} else {
folderElement.attachEvent("onclick", getFolderElement);
}
tagFolders.appendChild(folderElement);
}
which can retrieve anything from the element that triggered the event:
// This function is the event handler for the folder buttons.
function getFolderElement(event) {
var eventElement = event.currentTarget;
updateFolderContent(eventElement.id);
}
in which case you have to embed the option inside the element / tag. In my case I use the id.
For jquery, check out the adding event data section from the API:
...
for (var i = 0; i < arrOptions.length; i++) {
$('<input id="btn" type="button" value="Show Me Option"><input>').appendTo("#divButtons")
$('#btn').bind("click", {
iCount: i},
function(event) {
showParam(arrOptions[iCount]);
});
}
The accepted answer is correct but I feel that no real explanation was done.
Let me try to explain, the issue here is classical missing closure.
The variable 'i' is getting increased by 1 per loop iteration,
and the on-click event actually is not being executed, whether only applied to the a element, it getting summarize up to the length of arrOptions which is 10.
So, the loop continues up until 'i' is 10,
Then, whenever the on-click event is being triggered, it takes the value of i which is 10.
now, for the solution,
in the solution we are using a closure, so that when we apply the value of 'i' to the on-click event of the a element, it actually gets the exact value of i at in time.
The inner function of the onclick event create a closure where it references the parameter (arrOptions[i]), meaning what the actual i variable is at the right time.
The function eventually closes with that value safely,
and can then return its corresponding value when the on-click event is being executed.
You pass just the reference of the variable to the function, not it's value. So every time the loop is iterated, it assigns a reference to your anonymous function and all of them point to the same value in memory. But since you use the same variable name in the loop, you overwrite the value of the variable. You can concatenate the variable to a string to preserve it's value. For example like that:
btnShow.onclick = new Function("", "showParam(" + arrOptions[i] + ");");
The first parameter is the name of the function but afaik it is optional (it can be left blank or omitted at all).
pp();
function pp()
{
for(j=0;j<=11;j++)
{
if(j%4==0)
{
html+= "<br>";
}
html += "<span class='remote' onclick='setLift(this)' >"+ j+"</span>";
}
document.getElementById('el').innerHTML = html;
}
function setLift(x)
{
alert(x.innerHTML);
}

Categories