I've made a drag and droppable table for sorting products.
My table looks like this:
<table class="table table-sortable" id="mytab">
<tbody>
[{foreach from=$mylist item=listitem}]
[{assign var="_cnt1" value=$_cnt1+1}]
<tr draggable="true" id="test_variant.[{$_cnt1}]">
<td class="idcount">[{$_cnt1}]</td>
<td class="[{$listclass}]">Productname</td>
<input id="sortcount[{$_cnt1}]" class="sortcount" type="hidden" value="[{$_cnt1}]"/>
</tr>
[{/foreach}]
</tbody>
</table>
My jQuery looks like this:
$(function() {
$('.table-sortable tbody').sortable({
handle: 'span'
});
$('.table-sortable tbody').sortable().bind('sortupdate', function(e, ui) {
function updateTable(){
var table = document.getElementById("mytab");
for (var i = 0, row; row = table.rows[i]; i++) {
$( row ).attr("id","test_variant."+i);
$( row ).find(".idcount").text(i);
$( row ).find(".sortcount").val(i+10);
}
}
setTimeout(updateTable, 100);
});
});
The problem is, after I drag and drop my items the dom or something doesn't exist anymore.
Like my system won't save the dragged and dropped entries (But the others which are updated but not dragged).
And what leads me here because I don't understand it is when i dragged an item and try to access it like this
document.getElementById("sortcount1").value = "200";
it just says
Uncaught TypeError: Cannot set property 'value' of null like it's not existing
I've no problem accessing the other items.
When I open the dom with clicking on elements in chrome devtools, then back to console and try it again its working again like it needs to initialize or something.
Hope someone can give me a hint.
Thank you!
You might consider the following example.
$(function() {
function updateTable(e, ui) {
var t = $(e.target).closest("table");
$("tbody tr", t).each(function(i, el) {
$(el).attr("id", "test_variant." + i);
$(".idcount", el).html(i);
$(".sortcount", el).val(i + 10);
});
}
$('.table-sortable tbody').sortable({
handle: 'span',
update: updateTable
});
});
This will reset the items in the table after the Sort has updated.
Update
$(function() {
function updateTable(e, ui) {
var t = $(e.target).closest("table");
$("tbody tr", t).each(function(i, el) {
var c = i + 1;
$(el).attr("id", "test_variant." + c);
$(".idcount", el).html(c);
$(".sortcount", el).val(c + 10);
});
}
$('.table-sortable tbody').sortable({
handle: 'span',
items: "> tr",
update: updateTable
});
});
table {
width: 340px;
}
table tr {
margin: 0 3px 3px 3px;
padding: 0.4em;
padding-left: 1.5em;
font-size: 1.4em;
height: 18px;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<table class="table-sortable">
<thead>
<tr>
<td> </td>
<td>ID</td>
<td>Product Name</td>
</tr>
</thead>
<tbody>
<tr id="test_variant.1">
<td><span class="ui-icon ui-icon-arrowthick-2-n-s"></span></td>
<td class="idcount">1</td>
<td class="products">Item Name 1
<input id="sortcount-1" class="sortcount" type="hidden" value="11" />
</td>
</tr>
<tr id="test_variant.2">
<td><span class="ui-icon ui-icon-arrowthick-2-n-s"></span></td>
<td class="idcount">2</td>
<td class="products">Item Name 2
<input id="sortcount-2" class="sortcount" type="hidden" value="12" />
</td>
</tr>
<tr id="test_variant.3">
<td><span class="ui-icon ui-icon-arrowthick-2-n-s"></span></td>
<td class="idcount">3</td>
<td class="products">Item Name 3
<input id="sortcount-3" class="sortcount" type="hidden" value="13" />
</td>
</tr>
<tr id="test_variant.4">
<td><span class="ui-icon ui-icon-arrowthick-2-n-s"></span></td>
<td class="idcount">4</td>
<td class="products">Item Name 4
<input id="sortcount-4" class="sortcount" type="hidden" value="14" />
</td>
</tr>
<tr id="test_variant.5">
<td><span class="ui-icon ui-icon-arrowthick-2-n-s"></span></td>
<td class="idcount">5</td>
<td class="products">Item Name 5
<input id="sortcount-5" class="sortcount" type="hidden" value="15" />
</td>
</tr>
</tbody>
</table>
Tested the code and it appears to work properly.
Related
I have the following html table:
<table border="1" cellpadding="5" class="test">
<tr>
<td class="talent-cell"><div class="btn7" data-value="0">aaa</div></td>
<td class="talent-cell"><div class="btn8" data-value="1">bbb</div></td>
<td class="talent-cell"><div class="btn9" data-value="2">ccc</div></td>
</tr>
<tr>
<td class="talent-cell"><div class="btn7" data-value="0">ddd</div></td>
<td class="talent-cell"><div class="btn8" data-value="1">eee</div></td>
<td class="talent-cell"><div class="btn9" data-value="2">fff</div></td>
</tr>
<tr>
<td class="talent-cell"><div class="btn7" data-value="0">ggg</div></td>
<td class="talent-cell"><div class="btn8" data-value="1">hhh</div></td>
<td class="talent-cell"><div class="btn9" data-value="2">iii</div></td>
</tr>
</table>
If you click on a "div attribute" inside a table cell I need to get the "data-value" of the clicked div attribute. After that I build a query string to use it with "URLSearchParams". This works so far.
Now I need a certain condition. It should be only allowed to select one div-attribute per table row and column. But I don't know how to implement this condition in my code.
This is the Fiddle and the code:
var btn7;
var btn8;
var btn9;
$('.btn7').click(function () {
if ($(this).attr('data-selected') === 'true') {
$(this).attr('data-selected', 'false');
$(this).removeClass('selected');
} else {
$(this).closest('tr').find('.btn7').not(this)
.removeClass('selected').attr('data-selected', 'false');
$(this).attr('data-selected', 'true');
$(this).addClass('selected');
params.set('var7', $(this).data("value"));
window.history.replaceState({}, '', `?${params}`);
}
});
$('.btn8').click(function () {
if ($(this).attr('data-selected') === 'true') {
$(this).attr('data-selected', 'false');
$(this).removeClass('selected');
} else {
$(this).closest('tr').find('.btn8').not(this)
.removeClass('selected').attr('data-selected', 'false');
$(this).attr('data-selected', 'true');
$(this).addClass('selected');
params.set('var8', $(this).data("value"));
window.history.replaceState({}, '', `?${params}`);
}
});
$('.btn9').click(function () {
if ($(this).attr('data-selected') === 'true') {
$(this).attr('data-selected', 'false');
$(this).removeClass('selected');
} else {
$(this).closest('tr').find('.btn9').not(this)
.removeClass('selected').attr('data-selected', 'false');
$(this).attr('data-selected', 'true');
$(this).addClass('selected');
params.set('var9', $(this).data("value"));
window.history.replaceState({}, '', `?${params}`);
}
});
const params = new URLSearchParams({
var7: btn7,
var8: btn8,
var9: btn9,
});
Idea
Mark each table cell with a data- attribute indicating its respective row and column, and maintain 2 arrays that hold the currently selected element (if any) for each of the columns and row.
Implementation
The following code implements the selection logic. Based on the arrays holding the currently active selections you can visit all relevant elements and assemble the parameters when you send a request to the server.
The specs of single cell/row selection implies that there will usually be rows and columns that do not carry a selection.
Note that the case of expressly deselecting a cell is not handled.
The code does not resort to jquery.
<!DOCTYPE html>
<html>
<head>
<title>SO _: 1-in-a-row, 1-in-a-col selection</title>
<style type="text/css">
.selected {
background: #333;
color: #fff;
}
</style>
<script type="text/javascript">
let a_colSelection = new Array(3)
, a_rowSelection = new Array(3)
;
document.addEventListener ( 'DOMContentLoaded', () => {
Array.from(document.querySelectorAll('div[data-row][data-col]')).forEach ( el => {
el.addEventListener ( 'click', eve => {
let c = parseInt(eve.target.getAttribute('data-col'))
, r = parseInt(eve.target.getAttribute('data-row'))
;
if (a_colSelection[c] !== undefined) {
document.querySelector(`div[data-col="${a_colSelection[c][1]}"][data-row="${a_colSelection[c][0]}"]`).classList.remove("selected");
}
if (a_rowSelection[r] !== undefined) {
document.querySelector(`div[data-col="${a_rowSelection[r][1]}"][data-row="${a_rowSelection[r][0]}"]`).classList.remove("selected");
}
a_colSelection[c] = [r, c];
a_rowSelection[r] = [r, c];
document.querySelector(`div[data-col="${a_colSelection[c][1]}"][data-row="${a_rowSelection[r][0]}"]`).classList.add("selected");
});
});
});
</script>
</head>
<body>
<table border="1" cellpadding="5" class="test">
<tr>
<td class="talent-cell"><div data-value="0" data-col="0" data-row="0">aaa</div></td>
<td class="talent-cell"><div data-value="1" data-col="1" data-row="0">bbb</div></td>
<td class="talent-cell"><div data-value="2" data-col="2" data-row="0">ccc</div></td>
</tr>
<tr>
<td class="talent-cell"><div data-value="0" data-col="0" data-row="1">ddd</div></td>
<td class="talent-cell"><div data-value="1" data-col="1" data-row="1">eee</div></td>
<td class="talent-cell"><div data-value="2" data-col="2" data-row="1">fff</div></td>
</tr>
<tr>
<td class="talent-cell"><div data-value="0" data-col="0" data-row="2">ggg</div></td>
<td class="talent-cell"><div data-value="1" data-col="1" data-row="2">hhh</div></td>
<td class="talent-cell"><div data-value="2" data-col="2" data-row="2">iii</div></td>
</tr>
</table>
</body>
</html>
Consider the following.
Fiddle: https://jsfiddle.net/Twisty/dzng31f5/39/
HTML
<table border="1" cellpadding="5" class="test">
<tr class="var7">
<td class="talent-cell">
<div class="btn" data-value="0">aaa</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="1">bbb</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="2">ccc</div>
</td>
</tr>
<tr class="var8">
<td class="talent-cell">
<div class="btn" data-value="0">ddd</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="1">eee</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="2">fff</div>
</td>
</tr>
<tr class="var9">
<td class="talent-cell">
<div class="btn" data-value="0">ggg</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="1">hhh</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="2">iii</div>
</td>
</tr>
</table>
I adjusted the HTML Structure, such that each Row has a Class that represents the Index name that will be used in the Object.
jQuery
$(function() {
function checkCol(colIndex, table) {
var result = true;
console.log("Col Index:" + colIndex)
$("tbody tr", table).each(function(i, el) {
result = result && !$("td:eq(" + colIndex + ") div.btn", el).hasClass("selected");
});
return !result;
}
function checkRow(target, row) {
var isInCol = checkCol($(target).parent().index(), $(row).closest("table"));
if (!isInCol) {
if ($(".selected", row).length) {
$(".selected", row).removeClass("selected");
$(target).addClass("selected");
} else {
$(target).addClass("selected");
}
}
}
var selected = {};
$('.btn').click(function(event) {
var row = $(this).closest("tr");
checkRow(this, row);
$(".test tbody tr").each(function(i, el) {
selected[$(el).attr("class")] = $(".selected", el).length ? $(".selected", el).data("value") : "";
});
console.log(selected);
var params = new URLSearchParams(selected);
console.log(params.toString());
});
});
You can now use selected as your Data in a POST or GET call.
Updated
I had missed that each Row and Column needed to be unique. Code is updated to use Functions to check both conditions.
"Now I need a certain condition. It should be only allowed to select one div-attribute per table row and column."
The versatility of jQuery is leveraged by the use of this because it narrows down from many objects (all <td> in <table>) to a single object (<td> the user clicked). The behavior needed is common with radio button groups called "mutual exclusive selection", using .not(this) makes it simple.
In HTML,
assign a common class to each <div> (ex. '.col', see Figure I)
assign a class to each <div> that corresponds to the value of it's [data-value] (ex. '.c0', see Figure I)
Figure I
<div class='col c0' data-value='0'>
I did not include the params part in OP since it's beyond the scope of the question (see beginning of this answer). The values are stored in object C and is easily accessible (ex. C.c0).
BTW, I hope that the logic is different with your real code. For example, there is no difference between .c0 2nd row and .c0 1st row.
Details are commented in example below
// Declare object to store [data-value]
let C = {};
// Any click on a .col calls the event handler
$('.col').on('click', function() {
// Flip .selected on this .col
$(this).toggleClass('selected');
// If this .col is flipped to be .selected...
if ($(this).is('.selected')) {
//... get this .col [data-value] (0, 1, or 2)...
let idx = $(this).data('value');
/*
... find all .c0, .c1, or .c2 BUT NOT this .col and
remove .selected from them...
*/
$('.c' + idx).not(this).removeClass('selected');
/*
... then find the closest <tr>, then find all .col of
<tr> BUT NOT this .col and remove .selected from them
*/
$(this).closest('tr').find('.col')
.not(this).removeClass('selected');
// set key 'c0', 'c1', or 'c2' of C to this .col [data-value]
C['c'+idx] = $(this).data('value');
}
console.log(C);
});
<table border="1" cellpadding="5" class="test">
<tr>
<td><div class="col c0" data-value="0">aaa</div></td>
<td><div class="col c1" data-value="1">bbb</div></td>
<td><div class="col c2" data-value="2">ccc</div></td>
</tr>
<tr>
<td><div class="col c0" data-value="0">aaa</div></td>
<td><div class="col c1" data-value="1">bbb</div></td>
<td><div class="col c2" data-value="2">ccc</div></td>
</tr>
<tr>
<td><div class="col c0" data-value="0">aaa</div></td>
<td><div class="col c1" data-value="1">bbb</div></td>
<td><div class="col c2" data-value="2">ccc</div></td>
</tr>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I am trying to change the color of the selected row from a table on a onmousedown event and reset all others (or keep them the same) . Only one row can be red at a time while all others are green.
What I have tried:
function HighLight(id) {
var rows = $('#tbl > tbody > tr').each(function(elem) {
elem.style.background = 'green';
})
var tr = document.getElementById(id);
tr.style.background = 'red';
}
<table id="tbl">
<tr id="tr1" style="background-color:aquamarine" onmousedown="Highlight(e)">
<td>
v1
</td>
</tr>
<tr id="tr2" style="background-color:aquamarine" onmousedown="Highlight(e)">
<td>
v2
</td>
</tr>
<tr id="tr3" style="background-color:aquamarine" onmousedown="Highlight(e)">
<td>
v3
</td>
</tr>
</table>
Ideally I would like to store the old selected row so that I won't reset all others at each new selection, but in case I can't reset all would do it.
P.S I need to make due with the id that i am provided.I am using interop so the id is coming from the exterior. All my tr have that method injected in them.
The function name is wrong its Highlight not HighLight
To pass the id of the element on function call you cannot just pass any variable(e in your case). Use this.getAttribute('id') to get the id.
In the each() the argument elem represented the index of the element and not the element itself. Introduce another argument for index.
function Highlight(id) {
var rows = $('#tbl > tbody > tr').each(function(i,elem) {
elem.style.background = 'green';
})
var tr = document.getElementById(id);
tr.style.background = 'red';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl">
<tr id="tr1" style="background-color:aquamarine" onmousedown="Highlight(this.getAttribute('id'))">
<td>
v1
</td>
</tr>
<tr id="tr2" style="background-color:aquamarine" onmousedown="Highlight(this.getAttribute('id'))">
<td>
v2
</td>
</tr>
<tr id="tr3" style="background-color:aquamarine" onmousedown="Highlight(this.getAttribute('id'))">
<td>
v3
</td>
</tr>
</table>
Here is a quick example on how can you do that.
$("table tr").on('click', function(){
$(".highlighted").removeClass("highlighted");
$(this).addClass("highlighted");
});
table tr {
background: green;
}
table tr.highlighted {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl">
<tr id="tr1">
<td>
v1
</td>
</tr>
<tr id="tr2">
<td>
v2
</td>
</tr>
<tr id="tr3">
<td>
v3
</td>
</tr>
</table>
Here is how it works:
It binds a click event to every row in the table (tr),
Every time you click on a row, all elements that has a class called highlighted loose it and the row that you clicked gets the class highlighted,
In css you can change the default background color for all rows and the color after highlighting.
If you don't want to use a css, here is similar function but instead of adding and removing class it does the same with the inline css property.
$("table tr").on('click', function(){
$("table tr").css("background", "green");
$(this).css("background", "red");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl">
<tr id="tr1" style="background: green;">
<td>
v1
</td>
</tr>
<tr id="tr2" style="background: green;">
<td>
v2
</td>
</tr>
<tr id="tr3" style="background: green;">
<td>
v3
</td>
</tr>
</table>
But I do not recommend the second solution.
You can have two css classes; one for selected row and other for remaining rows.
On click of the row, you can add the "selected" class to that row.
$("#tbl tr").click(function(){
var $this = $(this);
//remove the previous row selection, if any
$("#tbl tr.selected").removeClass("selected");
//add selected class to the current row
$this.addClass("selected");
});
#tbl tr{
background-color: aquamarine;
}
#tbl tr.selected{
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl">
<tr id="tr1">
<td>
v1
</td>
</tr>
<tr id="tr2" >
<td>
v2
</td>
</tr>
<tr id="tr3" >
<td>
v3
</td>
</tr>
</table>
You can do like this.by using class you can carry out other operations
$("#tbl").on("click", "tr", function() {
$(' tr').removeClass("Red")
$(this).addClass("Red")
});
.Red {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl">
<tr id="tr1">
<td>
v1
</td>
</tr>
<tr id="tr2">
<td>
v2
</td>
</tr>
<tr id="tr3">
<td>
v3
</td>
</tr>
</table>
Several issues:
JS is case sensitive, so Highlight and HighLight (capital L) is not the same. I renamed the HighLight function to Highlight (lowercase l)
Use parameter this on function call in event handler attribute. This hands over the HTML element of the event handler attribute over to the event handler function (Highlight in your case)
Callback function of jQuery's each method has the index as a first parameter and the element as second
This makes your code work
function Highlight(tr) {
var rows = $('#tbl > tbody > tr').each(function(index, elem) {
elem.style.backgroundColor = 'green';
})
tr.style.background = 'red';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl">
<tr id="tr1" style="background-color:aquamarine" onmousedown="Highlight(this)">
<td>
v1
</td>
<td>
v1
</td>
<td>
v1
</td>
</tr>
<tr id="tr2" style="background-color:aquamarine" onmousedown="Highlight(this)">
<td>
v2
</td>
<td>
v2
</td>
<td>
v2
</td>
</tr>
<tr id="tr3" style="background-color:aquamarine" onmousedown="Highlight(this)">
<td>
v3
</td>
<td>
v3
</td>
<td>
v3
</td>
</tr>
</table>
There are some more things you can do to enhance your code
Don't use style in your JS code, but set classes for CSS
Don't use HTML onmousedown attributes, but JS addEventListeners
Replace jQuery code with VanillaJS
console.clear()
const rows = document.querySelectorAll('#tbl > tbody > tr');
for (row of rows) {
row.addEventListener('mousedown', Highlight)
}
function Highlight(e) {
e.preventDefault()
const tr = this
const rows = document.querySelectorAll('#tbl > tbody > tr');
for (row of rows) {
row.classList.remove('highlight')
row.classList.add('highlight-siblings')
}
tr.classList.remove('highlight-siblings')
tr.classList.add('highlight')
}
/* 1. */
tr {
background-color: aquamarine;
}
tr.highlight-siblings{
background-color: green;
}
tr.highlight{
background-color: red;
}
<table id="tbl">
<tr>
<td>
v1
</td>
<td>
v1
</td>
<td>
v1
</td>
</tr>
<tr>
<td>
v2
</td>
<td>
v2
</td>
<td>
v2
</td>
</tr>
<tr>
<td>
v3
</td>
<td>
v3
</td>
<td>
v3
</td>
</tr>
</table>
I have a simple table as following which has checkboxes in the first and last columns of each row.
<table style="width:100%">
<tr>
<td><input type="checkbox" /></td>
<td>Smith</td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td><input type="checkbox" /></td>
<td>Jackson</td>
<td><input type="checkbox" /></td>
</tr>
</table>
Problem:
When I check/uncheck the last column's checkbox in the first row, the first column's checkbox in the same row should be checked/unchecked. Similarly, if I check/uncheck the first column's checkbox, the corresponding last column checkbox should be checked/unchecked.
How can I achieve this in javascript? Any help or pointers would be really appreciated.
Here is the fiddle which I have created: Fiddle
Thank you.
Use :checkbox selector to select input type checkbox elements.
Try this:
$(':checkbox').on('change', function() {
$(this).closest('tr').find(':checkbox').prop('checked', this.checked);
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table style="width:100%">
<tr>
<td>
<input type="checkbox" />
</td>
<td>Smith</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Jackson</td>
<td>
<input type="checkbox" />
</td>
</tr>
</table>
Using JavaScript:
Use querySelectorAll('[type="checkbox"]') to find checkbox elements.
Try this:
var checkboxes = document.querySelectorAll('[type="checkbox"]');
[].forEach.call(checkboxes, function(checkbox) {
checkbox.onchange = function() {
var currentRow = this.parentNode.parentNode;
var cbElems = currentRow.querySelectorAll('[type="checkbox"]');
[].forEach.call(cbElems, function(cb) {
cb.checked = this.checked;
}.bind(this))
};
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<table style="width:100%">
<tr>
<td>
<input type="checkbox" />
</td>
<td>Smith</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Jackson</td>
<td>
<input type="checkbox" />
</td>
</tr>
</table>
One possible Javascript solution to toggle Checkboxes on Table Row click is shown below:
HTML
<table id = "Table1">
<tr>
<td><input type="checkbox" /></td>
<td>John Smith</td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td><input type="checkbox" /></td>
<td>Anna Warner</td>
<td><input type="checkbox" /></td>
</tr>
</table>
CSS
table, th, td{
border: 1px solid #c0c0c0;
border-collapse: collapse;
}
table{width:100%;}
Javascript
// row click will toggle checkboxes
row_OnClick("Table1")
function row_OnClick(tblId) {
try {
var rows = document.getElementById(tblId).rows;
for (i = 0; i < rows.length; i++) {
var _row = rows[i];
_row.onclick = null;
_row.onclick = function () {
return function () {selectRow(this);};
}(_row);
}
}
catch (err) { }
}
function selectRow(row) {
row.cells[0].firstChild.checked = !row.cells[0].firstChild.checked;
row.cells[2].firstChild.checked = row.cells[0].firstChild.checked;
}
Working jsfiddle demo at: https://jsfiddle.net/t6nsxgnz/
Practical implementation at: http://busny.net
You can further customize this solution pertinent to your task by modifying the selectRow(row) function:
function selectRow(row) {
row.cells[0].firstChild.checked = // add your code for the 1st CheckBox
row.cells[2].firstChild.checked = // add your code for the 2nd CheckBox
}
Another variation of this functionality coded in jQuery can be found in online pop-quiz engine (http://webinfocentral.com), implemented via the follwoing code snippet:
// toggle Checkboxes on row click
$(Table1 tr').click(function (event) {
// find the checkbox in the row
var _chk = $(this).find('input:checkbox');
if (!($(event.target).is("checkbox"))) {
$(_chk).prop('checked', !$(_chk).prop('checked'));
}
});
In this case, Row Click (at any place of the Row) or CheckBox Click events will toggle the state of that particular CheckBox. The state of other CheckBoxes can be synchronized with this one (by using "siblings" property, for example).
Hope this may help.
As the title suggests, I have created a table which I am populating with a list, and I also have a checkbox next to each element of that table. Finally I have a button labelled Delete. I want to attach that button with the actual delete operation.
Code of the button (it is inside another table):
<tr id="deleteproject" >
<td width="180" align="center" background="ButtonBackground.png"
onclick = "deleteRow('plist')">
<style="text-decoration:none; display:block; width:100%;
height:100%">
<font size="0.5px"><br/></font>
<font id="DeleteProject" face="verdana" color="white">
DELETE</font>
</a>
</td>
</tr>
The table:
<table ID="plist" border="0" cellpadding="0" cellspacing="0" datasrc="#clicklist"
style="WIDTH: 380px">
<tr>
<td id="projline" width="100%" align="left" valign="middle"
style="margin-left: 16px;">
<input type="checkbox" name="AAA"/>
<font size="3" face="Arial">
<a id="proj" href="urn:a">
<span datafld="Name"
style="margin-left: 20px; line-height: 26px;"></span>
</a>
</font>
</td>
</tr>
</table>
rowDelete function in JS:
function deleteRow(tableID) {
try {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
for(var i=0; i<rowCount; i++) {
var row = table.rows[i];
var chkbox = row.cells[0].childNodes[0];
if(null != chkbox && true == chkbox.checked)
{
table.deleteRow(i);
rowCount--;
i--;
}
}
}catch(e)
{
alert(e);
}
}
When I select a checkbox from a row and push the delete button, I get an object error, which I think means something is null or not understood in the JS code.
You must create a proper table first. The table is invalid in HTML5 and in HTML4, the button needs to be inside a table. Please read this article.
When I select a checkbox from a row and push the delete button, I get an object error, which I think means something is null or not understood in the JS code.
I don't know where to start ... looking at the JS, you are trying to target rows by referencing them by the TableRow Object? or ChildNode? Either way, the vague error message you are receiving is because you must reference the elements in the DOM as an object. There are several ways to do so in your situation, for example:
The tr needs to be referenced by what they are: <tr> the tag name.
var All_TR_Tags = document.getElementsByTagName('tr');
Now All_TR_Tags is an array-like object
Please review the demo and ask questions because I can't make a list of what is wrong and what issues that need to be addressed because it would take hours. The demo's styling is not part of the topic, I just used it because it's a default style I use for tables. The structure of the table is important as much as the JS though. The source itself has been extensively annotated. Please do not hesitate to ask if you have any further questions.
Snippet
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>delRows</title>
<style>
.x th {
color: #FFF;
background: #2C7EDB;
padding: 10px;
text-align: center;
vertical-align: middle;
}
.x tr:nth-child(odd) {
background-color: #333;
color: #FFF;
}
.x tr:nth-child(even) {
background-color: #D3E9FF;
color: #333;
}
.x td {
border-style: solid;
border-width: 1px;
border-color: #264D73;
padding: 5px;
text-align: left;
vertical-align: top;
position: relative;
}
.x thead th:first-child {
border-top-left-radius: 6px;
}
.x thead th:last-child {
border-top-right-radius: 6px;
}
.x tbody tr:last-child th:first-child {
border-bottom-left-radius: 6px;
}
.x tbody tr:last-child td:last-child {
border-bottom-right-radius: 6px;
}
th {
width: 30%;
}
th:first-of-type {
width: 10%;
}
table {
width: 80%;
}
</style>
</head>
<body>
<table id="T1" class="x">
<thead>
<tr>
<th>
<input id="btn1" type="button" value="DelRows" onclick="delRows('T1')" )/>
</th>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr id="row1">
<td>
<input id="chx1" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row2">
<td>
<input id="chx2" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row3">
<td>
<input id="chx3" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row4">
<td>
<input id="chx4" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row5">
<td>
<input id="chx5" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row6">
<td>
<input id="chx6" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row7">
<td>
<input id="chx7" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row8">
<td>
<input id="chx8" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row9">
<td>
<input id="chx9" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row10">
<td>
<input id="chx10" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
<script>
function delRows(tableID) {
//1| Take the function's argument and reference it as an id.
var table = document.getElementById(tableID);
//2| getElementsByTagName()[0]¹ will find the first† element with the <tbody> tag.
/* †You can use [0] to specify the first tag, [1] for the second tag, etc. <tbody> is the direct parent of all <tr>, so that's why we want a reference to it */
var tb = table.getElementsByTagName('tbody')[0];
//3| Collect all checkboxes that are checked into a NodeList² named 'checked'.
/* querySelectorAll³ is like getElementBy* on steroids. It accepts a selector as a target to reference, the syntax is like CSS or inside a jQuery object $(selector). Notice the ":checked"⁴ pseudoselector */
var checked = document.querySelectorAll('input[type="checkbox"]:checked');
//4| Collect all <tr> in <tbody> into a NodeList named 'rows'.
/* Remember we referenced the <tbody> as var tb on step 2? */
var rows = tb.querySelectorAll('tr');
//5| Iterate through the checked NodeList from step 3.
/* When dealing with arrays and array-like objects, you'll need to use a 'for loop' to iterate (or loop)⁵ 90% of the time. */
for (var i = 0; i < checked.length; i++) {
//6| For every checked checkbox find it's parent's parent and name it 'row'.
/* In the checked NodeList, there are all of the checked checkboxes so on each loop we are finding that particular checkbox's "grandmother". Example:
i = 4 means we are on the 3rd iteration (loop).
checked[4] is the third checked checkbox.
.parentNode⁶ is the parent element of the third checked checkbox--a <td>
The second .parentNode is the parent of the <td> which is a <tr> */
var row = checked[i].parentNode.parentNode;
//7| Remove 'row' from <tbody>
/* removeChild⁷ needs the parent of the element (or node) that you intend to remove. Thinking ahead, we have the parent of all <tr>: tb (a.k.a. <tbody>) from step 2. */
tb.removeChild(row);
//8| At this point, i is i+1 we go back to step 5 as long as "i < checked.length".
/* var i = one loop of steps 6, 7, and 8. It started initially as 0 which by design coincides with the 0 count index of arrays and array-like objects like the NodeList checked. i is then incremented by 1 (i++) thereby completing the loop. As long as i is less than the total amount of checked checkboxes, it will continue looping. */
}
//9| At this point, i is greater than the total amount of checked checkboxes and stops looping thru steps 6, 7, and 8.
/* This is the end of the function. Sometimes you'll see "return false;", but we didn't need it because the click event that starts this function is just a button. If we kept the original markup, that used an anchor, then "return false" would be necessary because an anchor by default will jump to a location which is undesirable if you are using the anchor as a button instead. */
}
</script>
</body>
</html>
I want to use casperJS to automatically select a checkbox
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="1" data-crdid="0005442" data-numcrd="3" value="">
</td>
<td>Data Structures and Algorithms</td>
<td>INT2203></td>
</tr>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="2" data-crdid="0005682" data-numcrd="3" value="">
</td>
<td>Machine Learning</td>
<td>INT2204></td>
</tr>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="3" data-crdid="003643" data-numcrd="3" value="">
</td>
<td>Artificial Intelligence</td>
<td>INT2205></td>
</tr>
The first column is the checkbox to select.
The second one is the name of the subject and the last one is the ID of the subject.
Now I just know the ID of the subject: INT2204 and I want to use casperjs to select the box of this subject. However, the only thing to distinguish is data-crdid which I have no clue.
Are there anyway to select the checkbox of the subject with ID 'INT2204' by casperjs?
You can use jQuery to filter on the element and get the siblings. This can be evaluated inside the page by CasperJS if you inject jQuery (if it isn't already).
Inject jQuery:
casper = require('casper').create();
casper.start();
casper.open('some url');
casper.then(function doSomething() {
this.page.injectJs('relative/local/path/to/jquery.js');
this.evaluate(function (courseId) {
$('td').filter(function() {
return $(this).text() === courseId;
}).siblings().find('input').prop('checked', true);
}, 'INT2203>');
});
Example in Browser:
var courseId = 'INT2203>';
$('td').filter(function() {
return $(this).text() === courseId;
}).siblings().find('input').prop('checked', true);
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<title>Checkbox test</title>
</head>
<body>
<table>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="1" data-crdid="0005442" data-numcrd="3" value="">
</td>
<td>Data Structures and Algorithms</td>
<td>INT2203></td>
</tr>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="2" data-crdid="0005682" data-numcrd="3" value="">
</td>
<td>Machine Learning</td>
<td>INT2204></td>
</tr>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="3" data-crdid="003643" data-numcrd="3" value="">
</td>
<td>Artificial Intelligence</td>
<td>INT2205></td>
</tr>
</table>
</body>
</html>
I finally found a way to solve my problem without using jQuery.
Here is the HTML code which I copied from #Evers answer:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<title>Checkbox test</title>
</head>
<body>
<table>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="1" data-crdid="0005442" data-numcrd="3" value="">
</td>
<td>Data Structures and Algorithms</td>
<td>INT2203</td>
</tr>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="2" data-crdid="0005682" data-numcrd="3" value="">
</td>
<td>Machine Learning</td>
<td>INT2204</td>
</tr>
<tr>
<td style=" text-align:center;">
<input type="checkbox" data-rowindex="3" data-crdid="003643" data-numcrd="3" value="">
</td>
<td>Artificial Intelligence</td>
<td>INT2205</td>
</tr>
</table>
</body>
</html>
I will use method getElementsInfo and getElementsAttribute of CasperJS:
First, I need to collect all the data which related to the subjects. Since the only things I know is the ID and the name of the subjects, I need to know their data-crdid in order to select the checkbox.
casper.then(function () {
// Select all the subject IDs in the table
id = this.getElementsInfo('table tr td:nth-child(3)')
.map(function (value, index, array) {
return array[index].text();
});
// Select all the data-crdid in the table
data = this.getElementsInfo('table tr td input', 'data-crdid');
});
After that, everything is simple. I just need to pick my subject by its ID and the data-crdid will have the same index in array data.
casper.then(function () {
selected = data[id.indexOf(subject)];
});
casper.thenEvaluate(function (selected) {
document.querySelector('input[data-crdid="' + selected + '"]').click();
}, selected);
Here is the full code:
var casper = require('casper').create();
var subject = 'INT2204';
casper.start();
casper.thenOpen('/{{ URL }}');
casper.then(function () {
// Select all the subject IDs in the table
var id = this.getElementsInfo('table tr td:nth-child(3)')
.map(function (value, index, array) {
return array[index].text();
});
// Select all the data-crdid in the table
var data = this.getElementsInfo('table tr td input', 'data-crdid');
var selected = data[id.indexOf(subject)];
this.thenEvaluate(function (selected) {
document.querySelector('input[data-crdid="' + selected + '"]').click();
}, selected);
});
casper.run();