OnClicks links to wrong button - javascript

I'm trying to link the button across every row to delete that row when clicked. However, every delete button is linked to the onclick delete of the last created row.
For example:
TABLE
Record 1 | deleteButton1
Record 2 | deleteButton2
Record 3 | deleteButton3
Actions:
clicks deleteButton1 ---> deletes the row with "Record 3"
clicks deleteButton1 ---> tries to delete the row with "Record 3" (a.k.a. nothing happens b/c row not found)
clicks deleteButton2 ---> tries to delete the row with "Record 3" (a.k.a. nothing happens b/c row not found)
HTML:
<table id="Table"></table>
JavaScript:
//Code snippet
for (var x = 0; x < itemArray.length; x++)
{
selectedItem = itemArray[x];
table = document.getElementById("Table");
row = table.insertRow(table.rows.length);
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell1.innerHTML = selectedItem;
cell2.innerHTML = "<button>—</button>"; //Delete button across every row.
cell2.onclick = function () { removeRow(selectedItem); };
}
function removeRow(content, where)
{
var table;
table = document.getElementById("Table");
var iter;
for (var i = 0; i < table.rows.length; i++)
{
iter = table.rows[i].cells[0].innerHTML;
if (iter == content)
{
table.deleteRow(i);
}
}
}

Each onclick function references the variable selectedItem. After your for loop, that variable is set to the last item in the array. So, every button will reference that last item. Here is a demonstration.
I suggest using Javascript's parentNode and rowIndex to allow a button to reference its own parent row.
In my example below, rowIndex returns the index number of the tr that is the parentNode for the clicked cell (td). This index number can be used to remove a table row directly.
cell2.onclick = function () { removeRow(this.parentNode.rowIndex); };
function removeRow(x) {
document.getElementById("Table").deleteRow(x);
}
Working Example (jsFiddle)

You may need something like this :
http://www.codingforums.com/javascript-programming/170869-dynamically-add-delete-reorder-rows-table.html
Here :
for (var i= startingIndex; i< tbl.tBodies[0].rows.length; i++) {
// CONFIG: next line is affected by myRowObject settings
tbl.tBodies[0].rows[i].myRow.one.data = count; // text
// CONFIG: next line is affected by myRowObject settings
tbl.tBodies[0].rows[i].myRow.two.name = INPUT_NAME_FS; // input text
tbl.tBodies[0].rows[i].myRow.two.id = INPUT_NAME_FS + count;
tbl.tBodies[0].rows[i].myRow.three.name = INPUT_NAME_FS_DESIGN; // input text
tbl.tBodies[0].rows[i].myRow.three.id = INPUT_NAME_FS_DESIGN + count;
// CONFIG: next line is affected by myRowObj settings
// CONFIG: requires class named classy0 and classy1
tbl.tBodies[0].rows[i].className = 'classy' + (count % 2);
count++;
}

Related

How to get checked rows' values from html table on a sidebar using GAS?

I have a table whose rows consist of 3 columns. 1º is a checkbox, 2º contains the colors and the 3º contains the hex.
As the user selects the colors desired by ticking the checkboxes, i imagine the colors being pushed into an arrat, that will be written to a cell as the user clicks on the save button.
I've borrowed this snippet from Mark, but it doesn't seem to run in my context:
var checkboxes = document.getElementsByTagName("input");
var selectedRows = [];
for (var i = 0; i < checkboxes.length; i++) {
var checkbox = checkboxes[i];
checkbox.onclick = function() {
var currentRow = this.parentNode.parentNode;
var secondColumn = currentRow.getElementsByTagName("td")[1];
selectedRows.push(secondColumn);
};
console.log(selectedRows)
}
This is the javascript part running to load and populate the table and I'm not sure where the above snippet woud go into:
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
/**
* Run initializations on sidebar load.
*/
$(function() {
// Assign handler functions to sidebar elements here, if needed.
// Call the server here to retrieve any information needed to build
// the dialog, if necessary.
google.script.run
.withSuccessHandler(function (record) { //<-- with this
showRecord(record);
})
.withFailureHandler(
function(msg, element) {
showStatus(msg, $('#button-bar'));
element.disabled = false;
})
.getRecord();
});
/**
* Callback function to display a "record", or row of the spreadsheet.
*
* #param {object[]} Array of field headings & cell values
*/
function showRecord(record) {
if (record.length) {
for (var i = 0; i < record.length-1; i++) {
// Adds a header to the table
if(i==0){
$('#sidebar-record-block').append($($.parseHTML('<div class="div-table-row"><div class="div-table-header">Sel</div><div class="div-table-header">Color</div><div class="div-table-header">Hex</div></div>')));
}
// build field name on the fly, formatted field-1234
var str = '' + i;
var fieldId = 'field-' + ('0000' + str).substring(str.length)
// If this field # doesn't already exist on the page, create it
if (!$('#'+fieldId).length) {
var newField = $($.parseHTML('<div id="'+fieldId+'"></div>'));
$('#sidebar-record-block').append(newField);
}
// Replace content of the field div with new record
$('#'+fieldId).replaceWith('<div id="'+fieldId+'" class="div-table-row"></div>');
$('#'+fieldId).append('<input type="checkbox" class="div-table-td" id=CB"'+fieldId+'"name="checkBox" </input>')
.append($('<div class="div-table-td">' + record[i].heading + '</div>'))
.append('<div class="div-table-td">' + record[i].cellval + '</div>')
}
}
}
</script>
Sample of how to get the checked tickboxes an button click
Assuming all your checkboxes are tied to a row, you can loop through all checkboxes with a query selector,
access their checked status
and save the indices of those checkboxes.
Those indices will be the same as when looping through the corresponding table rows.
Sample implementing a button click event:
var saveButton = document.getElementById("myButtonId");
saveButton.onclick = function(){
var checkedRowIndices = [];
$('input[type=checkbox]').each(function( index ) {
if($(this)[0].checked{
checkedRowIndices.push(index);
}
});
};
//now get the rows with those indeices and do something with them

I can't access nested JavaScript function in index.jsp

I have a function that is supposed to perform pagination on a table. Within that function is another function that needs to be executed when I click on the numbers in the navigation bar. The code works fine in VSCode. When I put the code in index.jsp in eclipse, the function gives the error: Uncaught ReferenceError: sort is not defined at HTMLButtonElement.onclick.
// get the table element
var table = document.getElementById("disposalTable"),
// number of rows per page
n = 5,
// number of rows of the table
rowCount = table.rows.length,
// get the first cell's tag name (in the first row)
firstRow = table.rows[0].firstElementChild.tagName,
// boolean var to check if table has a head row
hasHead = (firstRow === "TH"),
// an array to hold each row
tr = [],
// loop counters, to start count from rows[1] (2nd row) if the first row has a head tag
i,ii,j = (hasHead)?1:0,
// holds the first row if it has a (<TH>) & nothing if (<TD>)
th = (hasHead?table.rows[(0)].outerHTML:"");
// count the number of pages
var pageCount = Math.ceil(rowCount / n);
// if we had one page only, then we have nothing to do ..
if (pageCount > 1) {
// assign each row outHTML (tag name & innerHTML) to the array
for (i = j,ii = 0; i < rowCount; i++, ii++)
tr[ii] = table.rows[i].outerHTML;
// create a div block to hold the buttons
table.insertAdjacentHTML("afterend","<div id='buttons'></div");
// the first sort, default page is the first one
sort(1);
}
// ($p) is the selected page number. it will be generated when a user clicks a button
function sort(p) {
/* create ($rows) a variable to hold the group of rows
** to be displayed on the selected page,
** ($s) the start point .. the first row in each page, Do The Math
*/
var rows = th,s = ((n * p)-n);
for (i = s; i < (s+n) && i < tr.length; i++)
rows += tr[i];
// now the table has a processed group of rows ..
table.innerHTML = rows;
// create the pagination buttons
document.getElementById("buttons").innerHTML = pageButtons(pageCount,p);
// CSS Stuff
document.getElementById("id"+p).setAttribute("class","active");
}
// ($pCount) : number of pages,($cur) : current page, the selected one ..
function pageButtons(pCount,cur) {
/* this variables will disable the "Prev" button on 1st page
and "next" button on the last one */
var prevDis = (cur == 1)?"disabled":"",
nextDis = (cur == pCount)?"disabled":"",
/* this ($buttons) will hold every single button needed
** it will creates each button and sets the onclick attribute
** to the "sort" function with a special ($p) number..
*/
buttons = "<input type='button' value='<< Prev' onclick='sort("+(cur - 1)+")' "+prevDis+">";
for (i=1; i<=pCount;i++)
buttons += "<input type='button' id='id"+i+"'value='"+i+"' onclick='sort("+i+")'>";
buttons += "<input type='button' value='Next >>' onclick='sort("+(cur + 1)+")' "+nextDis+">";
return buttons;
}
I figured it out. Instead of trying to access the nested function. Put the pager code into a function. Then create an instance of the function as a variable. And call that variable every time.
For instance:
let pager = new Pager();
Then the onclick method will call pager.sort(1) or pager.sort(2) everytime.

javascript highlight multiple rows

I have looked all over but can't find a good answer.
So what I'm wanting to do is highlight multiple rows on a table
Then if you click on a highlighted row it gets un-highlighted.
All of this works for me. The problem I'm having is when I un-highlight a row for some reason it won't highlight again.
function highlight_row() {
var table = document.getElementById("display-table");
var cells = table.getElementsByTagName('td');
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
cell.onclick = function () {
var rowId = this.parentNode.rowIndex;
var rowSelected = table.getElementsByTagName('tr')[rowId];
rowSelected.className += "selected";
$(cell).toggleClass('selected');
}
}
}
I have changed out $(cell) with $(this) and that works but only re highlighting the cell I click on and not the whole row.
I'm at a lose here.
Thanks
If you want to highlight the whole row, you need to get parent tr
cell.onclick = function () {
$(this).parent('tr').toggleClass('selected');
}

HTML table cell event listeners don't seem to work?

I'm working on a HTML / Javascript project to create a simple game of Minesweeper. In order to create a clickable grid of cells, I adopted code that I found in another thread. That code works perfectly on its own (see this JSBin for more details):
var lastClicked;
var grid = clickableGrid(10,10,onClick);
document.body.appendChild(grid);
// This is the clickableGrid object constructor. It takes in the number of rows and columns
// for the grid, and a callback function that will be executed when a cell is clicked
function clickableGrid( rows, cols, callback ){
// 'i' is the variable that will store the number in each cell. A 10x10
// grid, for example, will see i range from 1 (top left cell) to 100 (bottom right cell)
var i=0;
// Create the table element and assign it a class name so that CSS formatting
// may be applied
var grid = document.createElement('table');
grid.className = 'grid';
// Build the grid row by row
for (var r=0;r<rows;++r){
// Create a table row element and append it to the table element ('grid')
var tr = grid.appendChild(document.createElement('tr'));
tr.row = r;
// Build the row cell by cell
for (var c=0;c<cols;++c){
// Create the cell element and append it to the row element ('tr')
var cell = tr.appendChild(document.createElement('td'));
// Input the number to the cell's innerHTML
cell.innerHTML = ++i;
// Add an event listener that will execute the callback function
// when the cell is clicked, using the cell's element and information
cell.addEventListener('click',(function(el, r, c, i){
return function() {
callback(el, r, c, i);
}
})(cell, r, c, i),false);
}
}
return grid;
}
// This function contains the actions we want to be executed when the click occurs
function onClick(el, row, col, i) {
// Log to the console the details of the cell that was clicked
console.log("You clicked on element:",el);
console.log("You clicked on row:",row);
console.log("You clicked on col:",col);
console.log("You clicked on item #:",i);
// Record in the element that it was clicked
el.className='clicked';
// If the element is not the same as
if (lastClicked) lastClicked.className='';
lastClicked = el;
}
However, I can't seem to make it work properly in my Minesweeper game. The "mined" grid gets built and appended to the DOM, but the innerHTML and listeners are not applied. This other JSBin contains all the game code I have so far. The current process is:
1) Run init to initialize the page and create all elements. Part of this includes adding an event listener to the "New Game" button.
2) When the "New Game" button is clicked, create a clickable grid that will be "mined". At the moment, no mines get placed, but the code tries to place an "X" inside each cell. Furthermore, each cell should have an event listener attached to it.
The relevant code section in the game is:
function startGame() {
var gameDifficulty = document.getElementsByTagName("select")[0].value;
var currGrid = document.querySelector('.grid');
var newGrid = new minedGrid(gameDifficulty, onClick);
currGrid.parentNode.replaceChild(newGrid, currGrid);
}
// minedGrid object constructor: creates and returns a fully-mined and
// prepared Minesweeper grid
function minedGrid(difficulty, callback){
var rows, cols, mines;
var newGrid = document.createElement('table');
newGrid.className = 'grid';
switch (difficulty) {
case 0:
rows = 10;
cols = 10;
mines = 10;
break;
case 1:
rows = 16;
cols = 16;
mines = 40;
break;
case 2:
rows = 16;
cols = 30;
mines = 99;
break;
default:
rows = 10;
cols = 10;
mines = 10;
break;
}
for (var r = 0; r < rows; ++r) {
var tr = newGrid.appendChild(document.createElement('tr'));
for (var c = 0; c < cols; ++c) {
var cell = tr.appendChild(document.createElement('td'));
cell.innerHTML = "X";
cell.addEventListener('click',(function(el, r, c){
return function() {
callback(el, r, c);
}
})(cell, r, c),false);
}
}
return grid;
}
// This function contains the actions we want to be executed when the click occurs
function onClick(el, row, col) {
// Log to the console the details of the cell that was clicked
console.log("You clicked on element:",el);
console.log("You clicked on row:",row);
console.log("You clicked on col:",col);
// Record in the element that it was clicked
el.className='clicked';
// If the element is not the same as
if (lastClicked) lastClicked.className='';
lastClicked = el;
}
Solution by OP.
Chris G, who commented on the question, was absolutely correct when noting that the grid is "never appended to the document." The issue is that the minedGrid function has return grid; at the bottom, when it should do return newGrid; instead. If you would like to see a revised version of this code, please refer to this link.
I want to again specifically highlight Chris G for his help, as well as his version of the minedGrid code: Chris G's JSBin.

Hide table column ondblclick

I have a table and I want to hide a column when I double click a column.
Code for hiding a column is practically all around Stack Overflow. All I need is a hint on how/where to add the ondblclick event so I can retrieve the identity of a <td> within a <table>.
Here are two solutions that should work. One done with jQuery and one with only standard Javascript.
http://jsfiddle.net/GNFN2/2/
// Iterate over each table, row and cell, and bind a click handler
// to each one, keeping track of which column each table cell was in.
var tables = document.getElementsByTagName('table');
for (var i = 0; i < tables.length; i++) {
var rows = tables[i].getElementsByTagName('tr');
for (var j = 0; j < rows.length; j++) {
var cells = rows[j].getElementsByTagName('td');
for (var k = 0; k < cells.length; k++) {
// Bind our handler, capturing the list of rows and colum.
cells[k].ondblclick = column_hide_handler(rows, k);
}
}
}
// Get a click handler function, keeping track of all rows and
// the column that this function should hide.
function column_hide_handler(rows, col) {
return function(e) {
// When the handler is triggered, hide the given column
// in each of the rows that were found previously.
for (var i = 0; i < rows.length; i++) {
var cells = rows[i].getElementsByTagName('td');
if (cells[col]) {
cells[col].style.display = 'none';
}
}
}
}
With jQuery it is much cleaner. This method also uses event bubbling, so you don't need to bind an event handler to each table cell individually.
http://jsfiddle.net/YCKZv/4/
// Bind a general click handler to the table that will trigger
// for all table cells that are clicked on.
$('table').on('dblclick', 'td', function() {
// Find the row that was clicked.
var col = $(this).closest('tr').children('td').index(this);
if (col !== -1) {
// Go through each row of the table and hide the clicked column.
$(this).closest('table').find('tr').each(function() {
$(this).find('td').eq(col).hide();
});
}
});
You can do this way:
<td ondblclick="this.style.display = 'none';">Some Stuff</td>
Here this refers to current td clicked.
Working Example
To go unobtrusive, you can do that easily using jQuery if you want:
$('#tableID td').dblclick(function(){
$(this).hide();
});
Due to lack of answears I came up with a workaround, which is a big ugly, but it works fine.
On the window load event I decided to iterate the table and set each 's onclick event to call my show_hide_column function with the column parameter set from the iteration.
window.onload = function () {
var headers = document.getElementsByTagName('th');
for (index in headers) {
headers[index].onclick = function (e) {
show_hide_column(index, false)
}
}
}
show_hide_column is a function that can be easily googled and the code is here:
function show_hide_column(col_no, do_show) {
var stl;
if (do_show) stl = 'table-cell'
else stl = 'none';
var tbl = document.getElementById('table_id');
var rows = tbl.getElementsByTagName('tr');
var headers = tbl.getElementsByTagName('th');
headers[col_no].style.display=stl;
for (var row=1; row<rows.length; row++) {
var cels = rows[row].getElementsByTagName('td')
cels[col_no].style.display=stl;
}
}
Note: my html only had one table so the code also assumes this. If you have more table you should tinker with it a little. Also it assumes the table has table headers ();
Also I noted this to be an ugly approach as I was expecting to be able to extract the index of a table cell from the table without having to iterate it on load.

Categories

Resources