SOLVED: jQuery $(this) not recognizing checkbox elements in tr











up vote
0
down vote

favorite












SOLVED: the problem was with my jQuery, but it wasn't a problem with the "this" keywords - it was a problem with how I set up the selectors.



jQuery's native browser event handlers (.change(), .click(), .focus(), and .blur()) will only get attached to elements that exist at the time the jQuery function runs - but not elements which are added after the initial render (at least, not with how I had the selectors set up). Since the table, rows, cells, and checkboxes are all dynamically created via my JS file, I needed to attach an .on() method to the static div (#table_goes_here) wherein my table was dynamically added, and THEN pass the "change" event handler and ":checkbox" selector as method arguments. SO I fixed the problem by changing the jQuery script file to the code below. If you're someone who'd like to learn more about jQuery event handling, this jQuery documentation page is exactly what you need.



<script>
$(document).ready(function() {
$("#table_goes_here").on("change", ":checkbox", function() {
var noticeCountHTML = document.getElementById("noticeCount");
var noticeCount = $("#table_goes_here").find("tr").length;
noticeCountHTML.innerHTML = noticeCount;
if ($(this).is(":checked")) {
noticeCount -= 1;
$(this).closest(".account_data").css("background-color", "rgba(64, 64, 64, 0.7)");
} else {
noticeCount += 1;
$(this).closest(".account_data").css("background-color", "rgba(255, 255, 255, 1)");
}
noticeCountHTML.innerHTML = noticeCount;
})
});
</script>


// --------------------------vvv INITIAL POST vvv--------------------------



I'm trying to use JQuery to highlight dynamically-created rows in a table when a checkbox in that row is unchecked, as well as update a counter element showing how many rows are checked. I'm using Google Apps Scripts, specifically the project is an HTML template output (html, js, and css files). Everything works EXCEPT the row highlighting upon unchecking the box and updating the checked-row-counter (>_<) I've looked everywhere for a solution, but have thus far come up empty. The only thing I can think of is that the $(this) variable in my jquery script file isn't getting set to the checkbox, but I can't use Chrome Dev Tools to watch "this" (unless someone knows a way to do this within GAS...?). Any help that can be offered will be greatly appreciated.



Here's my code.gs...



function openLateAccountsNoticesWindow() {
var htmlTemp = HtmlService.createTemplateFromFile('send_notices/HTML').evaluate();
var html = HtmlService.createHtmlOutput(htmlTemp);
SpreadsheetApp.getUi().showModalDialog(html, 'Send Notices');
};

// INCLUDE creates an import so files can be added inside the main index.
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
};

// The getAccountsWithOpenBal function creates an array of accounts with
// an outstanding balance > $0.

function getAccountsWithOpenBal() {
// Code to get the array of accounts from my spreadsheet goes here,
// but I'll provide a stand-in array below for debugging purposes.
var accounts = [
{Unit: "123 Abc Street", Name: "John Doe", Balance: 500.10},
{Unit: "456 Maple Street", Name: "Mary Jane", Balance: 250.05},
{Unit: "765 Stone Road", Name: "Mark Isaguy", Balance: 1300.45},
{Unit: "999 Nine Avenue", Name: "Lauren Lady", Balance: 45.23}];

var lateAccountsArray = ;
for (var i=0; i < accounts.length; i++) {
if (parseFloat(accounts[i]['Balance']) > 0) {
var balToNum = parseFloat(accounts[i]['Balance']);
var bal2Decimals = balToNum.toFixed(2);
var balWithCommas = bal2Decimals.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
accounts[i]['Balance'] = balWithCommas;
lateAccountsArray.push(accounts[i]);
}
}
return lateAccountsArray;
};


My html...



<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<?!= include('send_notices/CSS') ?>
</head>
<body>
<h4 id="header">Accounts with Current Balance Owed:</h4>
<div id="table_goes_here">
</div>
<br>
<h4>Number of Notices to Submit: <span id="noticeCount"></span></h4>
<br>
<button class="action" id="submitButton" onclick="form_data()">Submit</button> <button class="cancel" onclick="google.script.host.close()">Cancel</button>
<br>
</body>
<?!= include('send_notices/JS') ?>
</html>


Here's the script from my js file that generates the table...



<script>
window.onload = function() {
google.script.run.withSuccessHandler(addAccountsData).getAccountsWithOpenBal();
}

function addAccountsData(lateAccountsArray) {

var div = document.getElementById("table_goes_here");
var table = document.createElement("TABLE");
table.setAttribute("id", "debtorList");
var tableBody = document.createElement('TBODY');
table.appendChild(tableBody);

// TABLE HEADERS
// Create header row, and append to table body
var headerRow = document.createElement('TR');
tableBody.appendChild(headerRow);

// Next, create each header cell
// Unit Column Header ("unit" = "address")
var unitTH = document.createElement('TH');
unitTH.setAttribute("style", "width: 25%");
unitTH.appendChild(document.createTextNode("Address"));

// Name Column Header (name of account holder)
var nameTH = document.createElement('TH');
nameTH.setAttribute("style", "width: 22%");
nameTH.appendChild(document.createTextNode("Name"));

// Currency Column Header
var currencyTH = document.createElement('TH');
currencyTH.setAttribute("style", "width: 5%");
currencyTH.appendChild(document.createTextNode(""));

// Balance Column Header
var balanceTH = document.createElement('TH');
balanceTH.setAttribute("style", "width: 5%; text-align: right");
balanceTH.appendChild(document.createTextNode("Balance"));

// Checkbox Column Header
var includeTH = document.createElement('TH');
includeTH.setAttribute("style", "width: 10%; text-align: center");
includeTH.appendChild(document.createTextNode("Include"));

// Append all headers to header row
headerRow.appendChild(unitTH);
headerRow.appendChild(nameTH);
headerRow.appendChild(currencyTH);
headerRow.appendChild(balanceTH);
headerRow.appendChild(includeTH);

// I use getRowCount when filling in the table
// rows in order to attach a unique id attr to
// each row and checkbox.
var rowCount = 0;
function getRowCount() {
rowCount += 1;
return rowCount;
}

// Loop through each account, creating a row for each one.

for (var i=0; i < lateAccountsArray.length; i++) {
var tr = document.createElement("TR");
rowCount = getRowCount();
tr.classList.add("account_data");
tr.setAttribute("id", "row" + rowCount);

// td cell for unit/address
var unitTD = document.createElement("TD");
unitTD.classList.add("account_unit");
unitTD.setAttribute("value", lateAccountsArray[i]["Unit"]);
unitTD.appendChild(document.createTextNode(lateAccountsArray[i]["Address"]));

// td cell for account-holder name
var nameTD = document.createElement("TD");
nameTD.classList.add("name");
nameTD.setAttribute("value", lateAccountsArray[i]["Name"]);
nameTD.appendChild(document.createTextNode(lateAccountsArray[i]["Name"]));

// td cell for $ (to keep them aligned, regardless of the
// number of digits in their balance.
var currencyTD = document.createElement("TD");
currencyTD.classList.add("currency");
currencyTD.appendChild(document.createTextNode("$"));

// td cell for balance amount
var balanceTD = document.createElement("TD");
balanceTD.classList.add("balance");
balanceTD.setAttribute("value", lateAccountsArray[i]["Balance"]);
balanceTD.appendChild(document.createTextNode(lateAccountsArray[i]["Balance"]));

// td cell for checkbox
var checkboxTD = document.createElement("TD");
checkboxTD.classList.add("checkboxTD");
var checkbox = document.createElement("INPUT");
checkbox.classList.add("checkbox");
checkbox.setAttribute("id", "checkbox" + rowCount);
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("checked", true);
checkboxTD.appendChild(checkbox);

// Attach all td cells to tr
tr.appendChild(unitTD);
tr.appendChild(nameTD);
tr.appendChild(currencyTD);
tr.appendChild(balanceTD);
tr.appendChild(checkboxTD);

// Attach tr to tableBody
tableBody.appendChild(tr);

// Set the initial count for the number of notices.
if (i == lateAccountsArray.length - 1) {
var noticeCount = document.getElementById("noticeCount");
noticeCount.innerHTML = i;
}
}
div.appendChild(table)
};
</script>


And here's the script from my js file that is SUPPOSED to highlight the closest tr and update #noticeCount when :checkbox is checked...



<script>
$(document).ready(function() {
$(":checkbox").change(function() {
var noticeCountEle = document.getElementById("noticeCount");
var noticeCount = parseFloat(noticeCountEle.text());
if ($(this).is(":checked")) {
noticeCount += 1;
$(this).closest("tr").css("background-color", "rgba(255, 255, 255, 1)");
} else {
noticeCount -= 1;
$(this).closest("tr").css("background-color", "rgba(64, 64, 64, 0.7)");
}
noticeCountEle.innerHTML = noticeCount;
})
});
</script>


I've tried .closest("tr"), .closest(".account_data"), and I've tried getting the ID of the row and passing that, but none of them seem to work. My hunch is that the (this) keyword isn't right, but I'm not sure how to fix it/get around it.










share|improve this question
























  • noticeCountEle.text() isn't valid and is probably throwing error. Look in browser dev tools console
    – charlietfl
    Nov 12 at 20:26












  • you can change the scope of the dev tools console and stacktrace to be your GAS hosted webapp. This will work for any iframe or nested function call.
    – Jonathon
    Nov 12 at 20:30










  • I tried using dev tools, but with GAS, the source file isn't available (or if it is, I haven't found a way to access it). I first tried noticeCountEle.val() but that didn't work.
    – Trevor
    Nov 12 at 20:30










  • Thanks @Jonathon, I'll give that a try.
    – Trevor
    Nov 12 at 20:31










  • In Dev Tools, I can only see my code in the Elements tab, not Sources (I think this has something to do with Google's caja sanitization), so unfortunately I still can't see what "this" is getting set to. I don't get why it wouldn't get set to the checkbox given the context, but considering any code I use that involves "this" isn't working, I'm increasingly thinking that's the issue =/
    – Trevor
    Nov 13 at 15:32















up vote
0
down vote

favorite












SOLVED: the problem was with my jQuery, but it wasn't a problem with the "this" keywords - it was a problem with how I set up the selectors.



jQuery's native browser event handlers (.change(), .click(), .focus(), and .blur()) will only get attached to elements that exist at the time the jQuery function runs - but not elements which are added after the initial render (at least, not with how I had the selectors set up). Since the table, rows, cells, and checkboxes are all dynamically created via my JS file, I needed to attach an .on() method to the static div (#table_goes_here) wherein my table was dynamically added, and THEN pass the "change" event handler and ":checkbox" selector as method arguments. SO I fixed the problem by changing the jQuery script file to the code below. If you're someone who'd like to learn more about jQuery event handling, this jQuery documentation page is exactly what you need.



<script>
$(document).ready(function() {
$("#table_goes_here").on("change", ":checkbox", function() {
var noticeCountHTML = document.getElementById("noticeCount");
var noticeCount = $("#table_goes_here").find("tr").length;
noticeCountHTML.innerHTML = noticeCount;
if ($(this).is(":checked")) {
noticeCount -= 1;
$(this).closest(".account_data").css("background-color", "rgba(64, 64, 64, 0.7)");
} else {
noticeCount += 1;
$(this).closest(".account_data").css("background-color", "rgba(255, 255, 255, 1)");
}
noticeCountHTML.innerHTML = noticeCount;
})
});
</script>


// --------------------------vvv INITIAL POST vvv--------------------------



I'm trying to use JQuery to highlight dynamically-created rows in a table when a checkbox in that row is unchecked, as well as update a counter element showing how many rows are checked. I'm using Google Apps Scripts, specifically the project is an HTML template output (html, js, and css files). Everything works EXCEPT the row highlighting upon unchecking the box and updating the checked-row-counter (>_<) I've looked everywhere for a solution, but have thus far come up empty. The only thing I can think of is that the $(this) variable in my jquery script file isn't getting set to the checkbox, but I can't use Chrome Dev Tools to watch "this" (unless someone knows a way to do this within GAS...?). Any help that can be offered will be greatly appreciated.



Here's my code.gs...



function openLateAccountsNoticesWindow() {
var htmlTemp = HtmlService.createTemplateFromFile('send_notices/HTML').evaluate();
var html = HtmlService.createHtmlOutput(htmlTemp);
SpreadsheetApp.getUi().showModalDialog(html, 'Send Notices');
};

// INCLUDE creates an import so files can be added inside the main index.
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
};

// The getAccountsWithOpenBal function creates an array of accounts with
// an outstanding balance > $0.

function getAccountsWithOpenBal() {
// Code to get the array of accounts from my spreadsheet goes here,
// but I'll provide a stand-in array below for debugging purposes.
var accounts = [
{Unit: "123 Abc Street", Name: "John Doe", Balance: 500.10},
{Unit: "456 Maple Street", Name: "Mary Jane", Balance: 250.05},
{Unit: "765 Stone Road", Name: "Mark Isaguy", Balance: 1300.45},
{Unit: "999 Nine Avenue", Name: "Lauren Lady", Balance: 45.23}];

var lateAccountsArray = ;
for (var i=0; i < accounts.length; i++) {
if (parseFloat(accounts[i]['Balance']) > 0) {
var balToNum = parseFloat(accounts[i]['Balance']);
var bal2Decimals = balToNum.toFixed(2);
var balWithCommas = bal2Decimals.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
accounts[i]['Balance'] = balWithCommas;
lateAccountsArray.push(accounts[i]);
}
}
return lateAccountsArray;
};


My html...



<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<?!= include('send_notices/CSS') ?>
</head>
<body>
<h4 id="header">Accounts with Current Balance Owed:</h4>
<div id="table_goes_here">
</div>
<br>
<h4>Number of Notices to Submit: <span id="noticeCount"></span></h4>
<br>
<button class="action" id="submitButton" onclick="form_data()">Submit</button> <button class="cancel" onclick="google.script.host.close()">Cancel</button>
<br>
</body>
<?!= include('send_notices/JS') ?>
</html>


Here's the script from my js file that generates the table...



<script>
window.onload = function() {
google.script.run.withSuccessHandler(addAccountsData).getAccountsWithOpenBal();
}

function addAccountsData(lateAccountsArray) {

var div = document.getElementById("table_goes_here");
var table = document.createElement("TABLE");
table.setAttribute("id", "debtorList");
var tableBody = document.createElement('TBODY');
table.appendChild(tableBody);

// TABLE HEADERS
// Create header row, and append to table body
var headerRow = document.createElement('TR');
tableBody.appendChild(headerRow);

// Next, create each header cell
// Unit Column Header ("unit" = "address")
var unitTH = document.createElement('TH');
unitTH.setAttribute("style", "width: 25%");
unitTH.appendChild(document.createTextNode("Address"));

// Name Column Header (name of account holder)
var nameTH = document.createElement('TH');
nameTH.setAttribute("style", "width: 22%");
nameTH.appendChild(document.createTextNode("Name"));

// Currency Column Header
var currencyTH = document.createElement('TH');
currencyTH.setAttribute("style", "width: 5%");
currencyTH.appendChild(document.createTextNode(""));

// Balance Column Header
var balanceTH = document.createElement('TH');
balanceTH.setAttribute("style", "width: 5%; text-align: right");
balanceTH.appendChild(document.createTextNode("Balance"));

// Checkbox Column Header
var includeTH = document.createElement('TH');
includeTH.setAttribute("style", "width: 10%; text-align: center");
includeTH.appendChild(document.createTextNode("Include"));

// Append all headers to header row
headerRow.appendChild(unitTH);
headerRow.appendChild(nameTH);
headerRow.appendChild(currencyTH);
headerRow.appendChild(balanceTH);
headerRow.appendChild(includeTH);

// I use getRowCount when filling in the table
// rows in order to attach a unique id attr to
// each row and checkbox.
var rowCount = 0;
function getRowCount() {
rowCount += 1;
return rowCount;
}

// Loop through each account, creating a row for each one.

for (var i=0; i < lateAccountsArray.length; i++) {
var tr = document.createElement("TR");
rowCount = getRowCount();
tr.classList.add("account_data");
tr.setAttribute("id", "row" + rowCount);

// td cell for unit/address
var unitTD = document.createElement("TD");
unitTD.classList.add("account_unit");
unitTD.setAttribute("value", lateAccountsArray[i]["Unit"]);
unitTD.appendChild(document.createTextNode(lateAccountsArray[i]["Address"]));

// td cell for account-holder name
var nameTD = document.createElement("TD");
nameTD.classList.add("name");
nameTD.setAttribute("value", lateAccountsArray[i]["Name"]);
nameTD.appendChild(document.createTextNode(lateAccountsArray[i]["Name"]));

// td cell for $ (to keep them aligned, regardless of the
// number of digits in their balance.
var currencyTD = document.createElement("TD");
currencyTD.classList.add("currency");
currencyTD.appendChild(document.createTextNode("$"));

// td cell for balance amount
var balanceTD = document.createElement("TD");
balanceTD.classList.add("balance");
balanceTD.setAttribute("value", lateAccountsArray[i]["Balance"]);
balanceTD.appendChild(document.createTextNode(lateAccountsArray[i]["Balance"]));

// td cell for checkbox
var checkboxTD = document.createElement("TD");
checkboxTD.classList.add("checkboxTD");
var checkbox = document.createElement("INPUT");
checkbox.classList.add("checkbox");
checkbox.setAttribute("id", "checkbox" + rowCount);
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("checked", true);
checkboxTD.appendChild(checkbox);

// Attach all td cells to tr
tr.appendChild(unitTD);
tr.appendChild(nameTD);
tr.appendChild(currencyTD);
tr.appendChild(balanceTD);
tr.appendChild(checkboxTD);

// Attach tr to tableBody
tableBody.appendChild(tr);

// Set the initial count for the number of notices.
if (i == lateAccountsArray.length - 1) {
var noticeCount = document.getElementById("noticeCount");
noticeCount.innerHTML = i;
}
}
div.appendChild(table)
};
</script>


And here's the script from my js file that is SUPPOSED to highlight the closest tr and update #noticeCount when :checkbox is checked...



<script>
$(document).ready(function() {
$(":checkbox").change(function() {
var noticeCountEle = document.getElementById("noticeCount");
var noticeCount = parseFloat(noticeCountEle.text());
if ($(this).is(":checked")) {
noticeCount += 1;
$(this).closest("tr").css("background-color", "rgba(255, 255, 255, 1)");
} else {
noticeCount -= 1;
$(this).closest("tr").css("background-color", "rgba(64, 64, 64, 0.7)");
}
noticeCountEle.innerHTML = noticeCount;
})
});
</script>


I've tried .closest("tr"), .closest(".account_data"), and I've tried getting the ID of the row and passing that, but none of them seem to work. My hunch is that the (this) keyword isn't right, but I'm not sure how to fix it/get around it.










share|improve this question
























  • noticeCountEle.text() isn't valid and is probably throwing error. Look in browser dev tools console
    – charlietfl
    Nov 12 at 20:26












  • you can change the scope of the dev tools console and stacktrace to be your GAS hosted webapp. This will work for any iframe or nested function call.
    – Jonathon
    Nov 12 at 20:30










  • I tried using dev tools, but with GAS, the source file isn't available (or if it is, I haven't found a way to access it). I first tried noticeCountEle.val() but that didn't work.
    – Trevor
    Nov 12 at 20:30










  • Thanks @Jonathon, I'll give that a try.
    – Trevor
    Nov 12 at 20:31










  • In Dev Tools, I can only see my code in the Elements tab, not Sources (I think this has something to do with Google's caja sanitization), so unfortunately I still can't see what "this" is getting set to. I don't get why it wouldn't get set to the checkbox given the context, but considering any code I use that involves "this" isn't working, I'm increasingly thinking that's the issue =/
    – Trevor
    Nov 13 at 15:32













up vote
0
down vote

favorite









up vote
0
down vote

favorite











SOLVED: the problem was with my jQuery, but it wasn't a problem with the "this" keywords - it was a problem with how I set up the selectors.



jQuery's native browser event handlers (.change(), .click(), .focus(), and .blur()) will only get attached to elements that exist at the time the jQuery function runs - but not elements which are added after the initial render (at least, not with how I had the selectors set up). Since the table, rows, cells, and checkboxes are all dynamically created via my JS file, I needed to attach an .on() method to the static div (#table_goes_here) wherein my table was dynamically added, and THEN pass the "change" event handler and ":checkbox" selector as method arguments. SO I fixed the problem by changing the jQuery script file to the code below. If you're someone who'd like to learn more about jQuery event handling, this jQuery documentation page is exactly what you need.



<script>
$(document).ready(function() {
$("#table_goes_here").on("change", ":checkbox", function() {
var noticeCountHTML = document.getElementById("noticeCount");
var noticeCount = $("#table_goes_here").find("tr").length;
noticeCountHTML.innerHTML = noticeCount;
if ($(this).is(":checked")) {
noticeCount -= 1;
$(this).closest(".account_data").css("background-color", "rgba(64, 64, 64, 0.7)");
} else {
noticeCount += 1;
$(this).closest(".account_data").css("background-color", "rgba(255, 255, 255, 1)");
}
noticeCountHTML.innerHTML = noticeCount;
})
});
</script>


// --------------------------vvv INITIAL POST vvv--------------------------



I'm trying to use JQuery to highlight dynamically-created rows in a table when a checkbox in that row is unchecked, as well as update a counter element showing how many rows are checked. I'm using Google Apps Scripts, specifically the project is an HTML template output (html, js, and css files). Everything works EXCEPT the row highlighting upon unchecking the box and updating the checked-row-counter (>_<) I've looked everywhere for a solution, but have thus far come up empty. The only thing I can think of is that the $(this) variable in my jquery script file isn't getting set to the checkbox, but I can't use Chrome Dev Tools to watch "this" (unless someone knows a way to do this within GAS...?). Any help that can be offered will be greatly appreciated.



Here's my code.gs...



function openLateAccountsNoticesWindow() {
var htmlTemp = HtmlService.createTemplateFromFile('send_notices/HTML').evaluate();
var html = HtmlService.createHtmlOutput(htmlTemp);
SpreadsheetApp.getUi().showModalDialog(html, 'Send Notices');
};

// INCLUDE creates an import so files can be added inside the main index.
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
};

// The getAccountsWithOpenBal function creates an array of accounts with
// an outstanding balance > $0.

function getAccountsWithOpenBal() {
// Code to get the array of accounts from my spreadsheet goes here,
// but I'll provide a stand-in array below for debugging purposes.
var accounts = [
{Unit: "123 Abc Street", Name: "John Doe", Balance: 500.10},
{Unit: "456 Maple Street", Name: "Mary Jane", Balance: 250.05},
{Unit: "765 Stone Road", Name: "Mark Isaguy", Balance: 1300.45},
{Unit: "999 Nine Avenue", Name: "Lauren Lady", Balance: 45.23}];

var lateAccountsArray = ;
for (var i=0; i < accounts.length; i++) {
if (parseFloat(accounts[i]['Balance']) > 0) {
var balToNum = parseFloat(accounts[i]['Balance']);
var bal2Decimals = balToNum.toFixed(2);
var balWithCommas = bal2Decimals.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
accounts[i]['Balance'] = balWithCommas;
lateAccountsArray.push(accounts[i]);
}
}
return lateAccountsArray;
};


My html...



<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<?!= include('send_notices/CSS') ?>
</head>
<body>
<h4 id="header">Accounts with Current Balance Owed:</h4>
<div id="table_goes_here">
</div>
<br>
<h4>Number of Notices to Submit: <span id="noticeCount"></span></h4>
<br>
<button class="action" id="submitButton" onclick="form_data()">Submit</button> <button class="cancel" onclick="google.script.host.close()">Cancel</button>
<br>
</body>
<?!= include('send_notices/JS') ?>
</html>


Here's the script from my js file that generates the table...



<script>
window.onload = function() {
google.script.run.withSuccessHandler(addAccountsData).getAccountsWithOpenBal();
}

function addAccountsData(lateAccountsArray) {

var div = document.getElementById("table_goes_here");
var table = document.createElement("TABLE");
table.setAttribute("id", "debtorList");
var tableBody = document.createElement('TBODY');
table.appendChild(tableBody);

// TABLE HEADERS
// Create header row, and append to table body
var headerRow = document.createElement('TR');
tableBody.appendChild(headerRow);

// Next, create each header cell
// Unit Column Header ("unit" = "address")
var unitTH = document.createElement('TH');
unitTH.setAttribute("style", "width: 25%");
unitTH.appendChild(document.createTextNode("Address"));

// Name Column Header (name of account holder)
var nameTH = document.createElement('TH');
nameTH.setAttribute("style", "width: 22%");
nameTH.appendChild(document.createTextNode("Name"));

// Currency Column Header
var currencyTH = document.createElement('TH');
currencyTH.setAttribute("style", "width: 5%");
currencyTH.appendChild(document.createTextNode(""));

// Balance Column Header
var balanceTH = document.createElement('TH');
balanceTH.setAttribute("style", "width: 5%; text-align: right");
balanceTH.appendChild(document.createTextNode("Balance"));

// Checkbox Column Header
var includeTH = document.createElement('TH');
includeTH.setAttribute("style", "width: 10%; text-align: center");
includeTH.appendChild(document.createTextNode("Include"));

// Append all headers to header row
headerRow.appendChild(unitTH);
headerRow.appendChild(nameTH);
headerRow.appendChild(currencyTH);
headerRow.appendChild(balanceTH);
headerRow.appendChild(includeTH);

// I use getRowCount when filling in the table
// rows in order to attach a unique id attr to
// each row and checkbox.
var rowCount = 0;
function getRowCount() {
rowCount += 1;
return rowCount;
}

// Loop through each account, creating a row for each one.

for (var i=0; i < lateAccountsArray.length; i++) {
var tr = document.createElement("TR");
rowCount = getRowCount();
tr.classList.add("account_data");
tr.setAttribute("id", "row" + rowCount);

// td cell for unit/address
var unitTD = document.createElement("TD");
unitTD.classList.add("account_unit");
unitTD.setAttribute("value", lateAccountsArray[i]["Unit"]);
unitTD.appendChild(document.createTextNode(lateAccountsArray[i]["Address"]));

// td cell for account-holder name
var nameTD = document.createElement("TD");
nameTD.classList.add("name");
nameTD.setAttribute("value", lateAccountsArray[i]["Name"]);
nameTD.appendChild(document.createTextNode(lateAccountsArray[i]["Name"]));

// td cell for $ (to keep them aligned, regardless of the
// number of digits in their balance.
var currencyTD = document.createElement("TD");
currencyTD.classList.add("currency");
currencyTD.appendChild(document.createTextNode("$"));

// td cell for balance amount
var balanceTD = document.createElement("TD");
balanceTD.classList.add("balance");
balanceTD.setAttribute("value", lateAccountsArray[i]["Balance"]);
balanceTD.appendChild(document.createTextNode(lateAccountsArray[i]["Balance"]));

// td cell for checkbox
var checkboxTD = document.createElement("TD");
checkboxTD.classList.add("checkboxTD");
var checkbox = document.createElement("INPUT");
checkbox.classList.add("checkbox");
checkbox.setAttribute("id", "checkbox" + rowCount);
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("checked", true);
checkboxTD.appendChild(checkbox);

// Attach all td cells to tr
tr.appendChild(unitTD);
tr.appendChild(nameTD);
tr.appendChild(currencyTD);
tr.appendChild(balanceTD);
tr.appendChild(checkboxTD);

// Attach tr to tableBody
tableBody.appendChild(tr);

// Set the initial count for the number of notices.
if (i == lateAccountsArray.length - 1) {
var noticeCount = document.getElementById("noticeCount");
noticeCount.innerHTML = i;
}
}
div.appendChild(table)
};
</script>


And here's the script from my js file that is SUPPOSED to highlight the closest tr and update #noticeCount when :checkbox is checked...



<script>
$(document).ready(function() {
$(":checkbox").change(function() {
var noticeCountEle = document.getElementById("noticeCount");
var noticeCount = parseFloat(noticeCountEle.text());
if ($(this).is(":checked")) {
noticeCount += 1;
$(this).closest("tr").css("background-color", "rgba(255, 255, 255, 1)");
} else {
noticeCount -= 1;
$(this).closest("tr").css("background-color", "rgba(64, 64, 64, 0.7)");
}
noticeCountEle.innerHTML = noticeCount;
})
});
</script>


I've tried .closest("tr"), .closest(".account_data"), and I've tried getting the ID of the row and passing that, but none of them seem to work. My hunch is that the (this) keyword isn't right, but I'm not sure how to fix it/get around it.










share|improve this question















SOLVED: the problem was with my jQuery, but it wasn't a problem with the "this" keywords - it was a problem with how I set up the selectors.



jQuery's native browser event handlers (.change(), .click(), .focus(), and .blur()) will only get attached to elements that exist at the time the jQuery function runs - but not elements which are added after the initial render (at least, not with how I had the selectors set up). Since the table, rows, cells, and checkboxes are all dynamically created via my JS file, I needed to attach an .on() method to the static div (#table_goes_here) wherein my table was dynamically added, and THEN pass the "change" event handler and ":checkbox" selector as method arguments. SO I fixed the problem by changing the jQuery script file to the code below. If you're someone who'd like to learn more about jQuery event handling, this jQuery documentation page is exactly what you need.



<script>
$(document).ready(function() {
$("#table_goes_here").on("change", ":checkbox", function() {
var noticeCountHTML = document.getElementById("noticeCount");
var noticeCount = $("#table_goes_here").find("tr").length;
noticeCountHTML.innerHTML = noticeCount;
if ($(this).is(":checked")) {
noticeCount -= 1;
$(this).closest(".account_data").css("background-color", "rgba(64, 64, 64, 0.7)");
} else {
noticeCount += 1;
$(this).closest(".account_data").css("background-color", "rgba(255, 255, 255, 1)");
}
noticeCountHTML.innerHTML = noticeCount;
})
});
</script>


// --------------------------vvv INITIAL POST vvv--------------------------



I'm trying to use JQuery to highlight dynamically-created rows in a table when a checkbox in that row is unchecked, as well as update a counter element showing how many rows are checked. I'm using Google Apps Scripts, specifically the project is an HTML template output (html, js, and css files). Everything works EXCEPT the row highlighting upon unchecking the box and updating the checked-row-counter (>_<) I've looked everywhere for a solution, but have thus far come up empty. The only thing I can think of is that the $(this) variable in my jquery script file isn't getting set to the checkbox, but I can't use Chrome Dev Tools to watch "this" (unless someone knows a way to do this within GAS...?). Any help that can be offered will be greatly appreciated.



Here's my code.gs...



function openLateAccountsNoticesWindow() {
var htmlTemp = HtmlService.createTemplateFromFile('send_notices/HTML').evaluate();
var html = HtmlService.createHtmlOutput(htmlTemp);
SpreadsheetApp.getUi().showModalDialog(html, 'Send Notices');
};

// INCLUDE creates an import so files can be added inside the main index.
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
};

// The getAccountsWithOpenBal function creates an array of accounts with
// an outstanding balance > $0.

function getAccountsWithOpenBal() {
// Code to get the array of accounts from my spreadsheet goes here,
// but I'll provide a stand-in array below for debugging purposes.
var accounts = [
{Unit: "123 Abc Street", Name: "John Doe", Balance: 500.10},
{Unit: "456 Maple Street", Name: "Mary Jane", Balance: 250.05},
{Unit: "765 Stone Road", Name: "Mark Isaguy", Balance: 1300.45},
{Unit: "999 Nine Avenue", Name: "Lauren Lady", Balance: 45.23}];

var lateAccountsArray = ;
for (var i=0; i < accounts.length; i++) {
if (parseFloat(accounts[i]['Balance']) > 0) {
var balToNum = parseFloat(accounts[i]['Balance']);
var bal2Decimals = balToNum.toFixed(2);
var balWithCommas = bal2Decimals.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
accounts[i]['Balance'] = balWithCommas;
lateAccountsArray.push(accounts[i]);
}
}
return lateAccountsArray;
};


My html...



<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<?!= include('send_notices/CSS') ?>
</head>
<body>
<h4 id="header">Accounts with Current Balance Owed:</h4>
<div id="table_goes_here">
</div>
<br>
<h4>Number of Notices to Submit: <span id="noticeCount"></span></h4>
<br>
<button class="action" id="submitButton" onclick="form_data()">Submit</button> <button class="cancel" onclick="google.script.host.close()">Cancel</button>
<br>
</body>
<?!= include('send_notices/JS') ?>
</html>


Here's the script from my js file that generates the table...



<script>
window.onload = function() {
google.script.run.withSuccessHandler(addAccountsData).getAccountsWithOpenBal();
}

function addAccountsData(lateAccountsArray) {

var div = document.getElementById("table_goes_here");
var table = document.createElement("TABLE");
table.setAttribute("id", "debtorList");
var tableBody = document.createElement('TBODY');
table.appendChild(tableBody);

// TABLE HEADERS
// Create header row, and append to table body
var headerRow = document.createElement('TR');
tableBody.appendChild(headerRow);

// Next, create each header cell
// Unit Column Header ("unit" = "address")
var unitTH = document.createElement('TH');
unitTH.setAttribute("style", "width: 25%");
unitTH.appendChild(document.createTextNode("Address"));

// Name Column Header (name of account holder)
var nameTH = document.createElement('TH');
nameTH.setAttribute("style", "width: 22%");
nameTH.appendChild(document.createTextNode("Name"));

// Currency Column Header
var currencyTH = document.createElement('TH');
currencyTH.setAttribute("style", "width: 5%");
currencyTH.appendChild(document.createTextNode(""));

// Balance Column Header
var balanceTH = document.createElement('TH');
balanceTH.setAttribute("style", "width: 5%; text-align: right");
balanceTH.appendChild(document.createTextNode("Balance"));

// Checkbox Column Header
var includeTH = document.createElement('TH');
includeTH.setAttribute("style", "width: 10%; text-align: center");
includeTH.appendChild(document.createTextNode("Include"));

// Append all headers to header row
headerRow.appendChild(unitTH);
headerRow.appendChild(nameTH);
headerRow.appendChild(currencyTH);
headerRow.appendChild(balanceTH);
headerRow.appendChild(includeTH);

// I use getRowCount when filling in the table
// rows in order to attach a unique id attr to
// each row and checkbox.
var rowCount = 0;
function getRowCount() {
rowCount += 1;
return rowCount;
}

// Loop through each account, creating a row for each one.

for (var i=0; i < lateAccountsArray.length; i++) {
var tr = document.createElement("TR");
rowCount = getRowCount();
tr.classList.add("account_data");
tr.setAttribute("id", "row" + rowCount);

// td cell for unit/address
var unitTD = document.createElement("TD");
unitTD.classList.add("account_unit");
unitTD.setAttribute("value", lateAccountsArray[i]["Unit"]);
unitTD.appendChild(document.createTextNode(lateAccountsArray[i]["Address"]));

// td cell for account-holder name
var nameTD = document.createElement("TD");
nameTD.classList.add("name");
nameTD.setAttribute("value", lateAccountsArray[i]["Name"]);
nameTD.appendChild(document.createTextNode(lateAccountsArray[i]["Name"]));

// td cell for $ (to keep them aligned, regardless of the
// number of digits in their balance.
var currencyTD = document.createElement("TD");
currencyTD.classList.add("currency");
currencyTD.appendChild(document.createTextNode("$"));

// td cell for balance amount
var balanceTD = document.createElement("TD");
balanceTD.classList.add("balance");
balanceTD.setAttribute("value", lateAccountsArray[i]["Balance"]);
balanceTD.appendChild(document.createTextNode(lateAccountsArray[i]["Balance"]));

// td cell for checkbox
var checkboxTD = document.createElement("TD");
checkboxTD.classList.add("checkboxTD");
var checkbox = document.createElement("INPUT");
checkbox.classList.add("checkbox");
checkbox.setAttribute("id", "checkbox" + rowCount);
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("checked", true);
checkboxTD.appendChild(checkbox);

// Attach all td cells to tr
tr.appendChild(unitTD);
tr.appendChild(nameTD);
tr.appendChild(currencyTD);
tr.appendChild(balanceTD);
tr.appendChild(checkboxTD);

// Attach tr to tableBody
tableBody.appendChild(tr);

// Set the initial count for the number of notices.
if (i == lateAccountsArray.length - 1) {
var noticeCount = document.getElementById("noticeCount");
noticeCount.innerHTML = i;
}
}
div.appendChild(table)
};
</script>


And here's the script from my js file that is SUPPOSED to highlight the closest tr and update #noticeCount when :checkbox is checked...



<script>
$(document).ready(function() {
$(":checkbox").change(function() {
var noticeCountEle = document.getElementById("noticeCount");
var noticeCount = parseFloat(noticeCountEle.text());
if ($(this).is(":checked")) {
noticeCount += 1;
$(this).closest("tr").css("background-color", "rgba(255, 255, 255, 1)");
} else {
noticeCount -= 1;
$(this).closest("tr").css("background-color", "rgba(64, 64, 64, 0.7)");
}
noticeCountEle.innerHTML = noticeCount;
})
});
</script>


I've tried .closest("tr"), .closest(".account_data"), and I've tried getting the ID of the row and passing that, but none of them seem to work. My hunch is that the (this) keyword isn't right, but I'm not sure how to fix it/get around it.







javascript jquery html google-apps-script this






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 at 15:54

























asked Nov 12 at 19:52









Trevor

13




13












  • noticeCountEle.text() isn't valid and is probably throwing error. Look in browser dev tools console
    – charlietfl
    Nov 12 at 20:26












  • you can change the scope of the dev tools console and stacktrace to be your GAS hosted webapp. This will work for any iframe or nested function call.
    – Jonathon
    Nov 12 at 20:30










  • I tried using dev tools, but with GAS, the source file isn't available (or if it is, I haven't found a way to access it). I first tried noticeCountEle.val() but that didn't work.
    – Trevor
    Nov 12 at 20:30










  • Thanks @Jonathon, I'll give that a try.
    – Trevor
    Nov 12 at 20:31










  • In Dev Tools, I can only see my code in the Elements tab, not Sources (I think this has something to do with Google's caja sanitization), so unfortunately I still can't see what "this" is getting set to. I don't get why it wouldn't get set to the checkbox given the context, but considering any code I use that involves "this" isn't working, I'm increasingly thinking that's the issue =/
    – Trevor
    Nov 13 at 15:32


















  • noticeCountEle.text() isn't valid and is probably throwing error. Look in browser dev tools console
    – charlietfl
    Nov 12 at 20:26












  • you can change the scope of the dev tools console and stacktrace to be your GAS hosted webapp. This will work for any iframe or nested function call.
    – Jonathon
    Nov 12 at 20:30










  • I tried using dev tools, but with GAS, the source file isn't available (or if it is, I haven't found a way to access it). I first tried noticeCountEle.val() but that didn't work.
    – Trevor
    Nov 12 at 20:30










  • Thanks @Jonathon, I'll give that a try.
    – Trevor
    Nov 12 at 20:31










  • In Dev Tools, I can only see my code in the Elements tab, not Sources (I think this has something to do with Google's caja sanitization), so unfortunately I still can't see what "this" is getting set to. I don't get why it wouldn't get set to the checkbox given the context, but considering any code I use that involves "this" isn't working, I'm increasingly thinking that's the issue =/
    – Trevor
    Nov 13 at 15:32
















noticeCountEle.text() isn't valid and is probably throwing error. Look in browser dev tools console
– charlietfl
Nov 12 at 20:26






noticeCountEle.text() isn't valid and is probably throwing error. Look in browser dev tools console
– charlietfl
Nov 12 at 20:26














you can change the scope of the dev tools console and stacktrace to be your GAS hosted webapp. This will work for any iframe or nested function call.
– Jonathon
Nov 12 at 20:30




you can change the scope of the dev tools console and stacktrace to be your GAS hosted webapp. This will work for any iframe or nested function call.
– Jonathon
Nov 12 at 20:30












I tried using dev tools, but with GAS, the source file isn't available (or if it is, I haven't found a way to access it). I first tried noticeCountEle.val() but that didn't work.
– Trevor
Nov 12 at 20:30




I tried using dev tools, but with GAS, the source file isn't available (or if it is, I haven't found a way to access it). I first tried noticeCountEle.val() but that didn't work.
– Trevor
Nov 12 at 20:30












Thanks @Jonathon, I'll give that a try.
– Trevor
Nov 12 at 20:31




Thanks @Jonathon, I'll give that a try.
– Trevor
Nov 12 at 20:31












In Dev Tools, I can only see my code in the Elements tab, not Sources (I think this has something to do with Google's caja sanitization), so unfortunately I still can't see what "this" is getting set to. I don't get why it wouldn't get set to the checkbox given the context, but considering any code I use that involves "this" isn't working, I'm increasingly thinking that's the issue =/
– Trevor
Nov 13 at 15:32




In Dev Tools, I can only see my code in the Elements tab, not Sources (I think this has something to do with Google's caja sanitization), so unfortunately I still can't see what "this" is getting set to. I don't get why it wouldn't get set to the checkbox given the context, but considering any code I use that involves "this" isn't working, I'm increasingly thinking that's the issue =/
– Trevor
Nov 13 at 15:32

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269166%2fsolved-jquery-this-not-recognizing-checkbox-elements-in-tr%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269166%2fsolved-jquery-this-not-recognizing-checkbox-elements-in-tr%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to change which sound is reproduced for terminal bell?

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

Can I use Tabulator js library in my java Spring + Thymeleaf project?