Demo
I want to select multiple rows using Windows Shift and Ctrl keys, like multiple folder selection in Windows.
From table of selected rows I have to get the first column (student id) and pass to server side C# and delete those records from database.
I have written a code in javascript but the classname is not being applied to <tr> on Shift or Ctrl+ left click.
HTML
<table id="tableStudent" border="1">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Class</th>
</tr>
</thead>
<tbody>
<tr onmousedown="RowClick(this,false);">
<td>1</td>
<td>John</td>
<td>4th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>2</td>
<td>Jack</td>
<td>5th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>3</td>
<td>Michel</td>
<td>6th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>4</td>
<td>Mike</td>
<td>7th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>5</td>
<td>Yke</td>
<td>8th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>6</td>
<td>4ke</td>
<td>9th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>7</td>
<td>7ke</td>
<td>10th</td>
</tr>
</tbody>
</table>
JavaScript
var selectedrow;
function RowClick(currenttr, lock) {
var trs =tableStudent.tBodies[0].getElementsByTagName("tr");
var cnt;
if(window.event.button==2)
{
if(currenttr.className=='selected')
return false;
}
alert(trs.length);
if (((window.event.shiftKey) && (window.event.ctrlKey) ) ||(window.event.shiftKey))
{
for(var j=0; j<trs.length; j++)
{
if (trs[j].className!='normallock')
{
trs[j].className='normal';
}
}
var mark=false;
if (typeof(selectedrow)=="undefined")
{
selectedrow=currenttr;
selectedrow.className='selected'
return false;
}
for(var j=0; j<trs.length; j++)
{
if ((trs[j].id ==selectedrow.id) || (trs[j].id ==currenttr.id) )
{
if (trs[j].className!='normallock')
{
trs[j].className='selected'
mark = !(mark);
}
}
else
{
if(mark==true)
{
if (trs[j].className!='normallock')
trs[j].className='selected'
}
}
}
}
else if(window.event.ctrlKey)
{
//if ctrl key is seelcted while selecting the patients
// select the patient with currently clicked row plus
// maintain the previous seelcted status
cnt=0;
for(var j=0; j<trs.length; j++)
{
if(trs[j].id == currenttr.id)
{
if(trs[j].className=='selected')
{
trs[j].className='normal';
}else
{
trs[j].className='selected';
}
}
if(trs[j].className=='selected')
{
cnt++;
}
}
if(cnt==0)
{
selectedrow=undefined;
return false;
}
}
else
{
for(var j=0; j<trs.length; j++)
{
if(trs[j].id == currenttr.id)
{
trs[j].className='selected'
}
else
{
if (trs[j].className!='normallock')
trs[j].className='normal';
}
}
}
selectedrow=currenttr;
}
It's probably not all of the functionality you want, since the question is a bit vague, but he's an attempt at adding Ctrl or Shift+ left mouse button to select or deselect multiple table rows - see demo and code below. Disclaimer: Only tested in Chrome and code can almost certainly be optimised.
JavaScript
var lastSelectedRow;
var trs = document.getElementById('tableStudent').tBodies[0].getElementsByTagName('tr');
// disable text selection
document.onselectstart = function() {
return false;
}
function RowClick(currenttr, lock) {
if (window.event.ctrlKey) {
toggleRow(currenttr);
}
if (window.event.button === 0) {
if (!window.event.ctrlKey && !window.event.shiftKey) {
clearAll();
toggleRow(currenttr);
}
if (window.event.shiftKey) {
selectRowsBetweenIndexes([lastSelectedRow.rowIndex, currenttr.rowIndex])
}
}
}
function toggleRow(row) {
row.className = row.className == 'selected' ? '' : 'selected';
lastSelectedRow = row;
}
function selectRowsBetweenIndexes(indexes) {
indexes.sort(function(a, b) {
return a - b;
});
for (var i = indexes[0]; i <= indexes[1]; i++) {
trs[i-1].className = 'selected';
}
}
function clearAll() {
for (var i = 0; i < trs.length; i++) {
trs[i].className = '';
}
}
HTML
<table id="tableStudent" border="1">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Class</th>
</tr>
</thead>
<tbody>
<tr onmousedown="RowClick(this,false);">
<td>1</td>
<td>John</td>
<td>4th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>2</td>
<td>Jack</td>
<td>5th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>3</td>
<td>Michel</td>
<td>6th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>4</td>
<td>Mike</td>
<td>7th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>5</td>
<td>Yke</td>
<td>8th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>6</td>
<td>4ke</td>
<td>9th</td>
</tr>
<tr onmousedown="RowClick(this,false);">
<td>7</td>
<td>7ke</td>
<td>10th</td>
</tr>
</tbody>
</table>
CSS
.selected {
background: lightBlue
}
I would also look at addEventListener vs onclick and move the event handler binding out of the HTML and into JavaScript. This is known as Unobtrusive Javascript.
Resources you might want to read:
Retrieve Table Row Index of Current Row
disable text selection while pressing 'shift'
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
I made it work with all the Windows 7 explorer behaviors and jquery mouse events.
http://jsfiddle.net/ubershmekel/nUV23/6/
Note that:
When you just click, you set a pivot for the next shift-click
Use Ctrl-Shift to expand your current selection and not pivot like Shift-alone does.
Use Ctrl-click to add a pivot, you can use Ctrl-Shift to then expand that selection around the new pivot.
The js:
var selectionPivot;
// 1 for left button, 2 for middle, and 3 for right.
var LEFT_MOUSE_BUTTON = 1;
var trs = document.getElementById('tableStudent').tBodies[0].getElementsByTagName('tr');
var idTds = $('td:first-child');
idTds.each(function(idx, val) {
// onselectstart because IE doesn't respect the css `user-select: none;`
val.onselectstart = function() { return false; };
$(val).mousedown(function(event) {
if(event.which != LEFT_MOUSE_BUTTON) {
return;
}
var row = trs[idx];
if (!event.ctrlKey && !event.shiftKey) {
clearAll();
toggleRow(row);
selectionPivot = row;
return;
}
if (event.ctrlKey && event.shiftKey) {
selectRowsBetweenIndexes(selectionPivot.rowIndex, row.rowIndex);
return;
}
if (event.ctrlKey) {
toggleRow(row);
selectionPivot = row;
}
if (event.shiftKey) {
clearAll();
selectRowsBetweenIndexes(selectionPivot.rowIndex, row.rowIndex);
}
});
});
function toggleRow(row) {
row.className = row.className == 'selected' ? '' : 'selected';
}
function selectRowsBetweenIndexes(ia, ib) {
var bot = Math.min(ia, ib);
var top = Math.max(ia, ib);
for (var i = bot; i <= top; i++) {
trs[i-1].className = 'selected';
}
}
function clearAll() {
for (var i = 0; i < trs.length; i++) {
trs[i].className = '';
}
}
And the CSS:
.selected {
background: #bdf;
}
td:first-child {
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
}
td,th {
padding: 3px;
border: 2px solid #aaa;
}
table {
border-collapse: collapse;
}
Here's a jQuery plugin I wrote recently for a project. Thought sharing...
Works exactly like you're used to, +
it's extremely fast cause it operates over an Array without the need to check for attributes, classes etc, and the add/removeClass triggers only on the selected elements:
// Use like:
// $("table").selekt();
//
// Available options:
$("table").selekt({
children: "tr", // Elements to target (default: "tbody tr")
className: "selected", // Desired CSS class (default: "selected")
onSelect: function(sel) { // Useful callback
$("span").text(sel.length + ' in ' + this.id);
}
});
.selected { background: #0bf; }
table {border: 1px solid #555;display: inline-block; vertical-align: top;}
<p>Seleceted: <span id="info">0</span></p>
<table id="table_1">
<tr><td>1 SELECT ME</td></tr>
<tr><td>2 SELECT ME</td></tr>
<tr><td>3 SELECT ME</td></tr>
<tr><td>4 SELECT ME</td></tr>
<tr><td>5 SELECT ME</td></tr>
<tr><td>6 SELECT ME</td></tr>
</table>
<table id="table_2">
<tr><td>1 SELECT ME</td></tr>
<tr><td>2 SELECT ME</td></tr>
<tr><td>3 SELECT ME</td></tr>
<tr><td>4 SELECT ME</td></tr>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
;(function($) {
// selekt jQuery plugin // http://stackoverflow.com/a/35813513/383904
$.fn.selekt = function() {
var settings = $.extend({
children: "tbody tr",
className: "selected",
onSelect: function() {}
}, arguments[0] || {});
return this.each(function(_, that) {
var $ch = $(this).find(settings.children),
sel = [],
last;
$ch.on("mousedown", function(ev) {
var isCtrl = (ev.ctrlKey || ev.metaKey),
isShift = ev.shiftKey,
ti = $ch.index(this),
li = $ch.index(last),
ai = $.inArray(this, sel);
if (isShift || isCtrl) ev.preventDefault();
$(sel).removeClass(settings.className);
if (isCtrl) {
if (ai > -1) sel.splice(ai, 1);
else sel.push(this);
} else if (isShift && sel.length > 0) {
if (ti > li) ti = [li, li = ti][0];
sel = $ch.slice(ti, li + 1);
} else {
sel = ai < 0 || sel.length > 1 ? [this] : [];
}
last = this;
$(sel).addClass(settings.className);
settings.onSelect.call(that, sel);
});
});
};
}(jQuery));
</script>
Check this example:
JSFiddle: Highlight list with shift and ctrl
Part of the code:
switch(e.type) {
case "keydown" :
console.log('k_down');
keysPressed.push(e.keyCode);
break;
case "keyup" :
console.log('k_up');
var idx = keysPressed.indexOf(e.keyCode);
if (idx >= 0)
keysPressed.splice(idx, 1);
break;
}
Sources could be found here:
Source files github
I know this question is already answered and it's pretty old, but I found the answer by andyb to be super helpful. Perhaps it was because andyb's answer might be outdated now, but I ended up having to change his solution a bit to work with my project, so I figured I'd share my updated version. Here is what I ended up with, using a sprinkling of jQuery.
$(document).ready(function(){
//put all the table rows in a variable after page load to pass in to RowClick
var trs = $('#tableStudent tr')
//bind the click handler to all the table rows
$('tr').on('click', function(){
//call the RowClick function on click event
RowClick($(this),false,trs)
})
})
//declare variable to store the most recently clicked row
var lastSelectedRow;
// disable text selection
document.onselectstart = function() {
return false;
}
function RowClick(currentrow, lock, rows) {
//if control is held down, toggle the row
if (window.event.ctrlKey) {
toggleRow(currentrow);
}
//if there are no buttons held down...
if (window.event.button === 0) {
//if neither control or shift are held down...
if (!window.event.ctrlKey && !window.event.shiftKey) {
//clear selection
clearAll(rows);
//toggle clicked row
toggleRow(currentrow);
}
//if shift is held down...
if (window.event.shiftKey) {
//pass the indexes of the last selected row and currently selected row along with all rows
selectRowsBetweenIndexes([lastSelectedRow.index(), currentrow.index()], rows)
}
}
}
function toggleRow(row) {
//if the row is not the header row...
if (!row.hasClass('header-row')){
//if the row is selected...
if (row.hasClass('selected')){
//deselect it
row.removeClass('selected')
}
else{
//otherwise, select it
row.addClass('selected')
}
//reassign the most recently selected row
lastSelectedRow = row;
}
}
function selectRowsBetweenIndexes(indexes,rows) {
//sort the indexes in ascending order
indexes.sort(function(a, b) {
return a - b;
});
//for every row starting at the first index, until the second index...
for (var i = indexes[0]; i <= indexes[1]; i++) {
//select the row
$(rows[i+1]).addClass('selected');
}
}
function clearAll(rows) {
//for all rows...
for (var i = 0; i < rows.length; i++) {
//deselect each row
$(rows[i]).removeClass("selected");
}
}
Following code is modification from Robo C Buljan, since i wanted to multiselect using checkboxes and shift key
<includeScript value="/jquery-3.2.0.min.js" />
<script>
;(function($) {
// selekt jQuery plugin // http://stackoverflow.com/a/35813513/383904
$.fn.selekt = function() {
var settings = $.extend({
children: "td input[type='checkbox'][name='ids']",
onSelect: function(){
}
}, arguments[0] || {});
return this.each(function(_, that){
var $ch = $(this).find(settings.children),
sel = [],
last;
$ch.on("mouseup", function(ev) {
/* Note 1: Remember this code is run when a checkbox is clicked and is run before checbox's state changes because of click
i.e. to say if the checkbox was checked and we clicked it to uncheck, then this event handler (mouse up)code is called before the unchecing happens */
if(ev.shiftKey || ev.ctrlKey){
ev.preventDefault();
ev.stopPropagation();
}
var self = this;
var ti = $ch.index(this), // index of current element in the matching elements
li = $ch.index(last), // index of last element in the matching elements
ai = $.inArray(this, sel); // index of this in the sel array
if(ev.ctrlKey) {
if(ai > -1) sel.splice(ai, 1);
else sel.push(this);
}
else if(ev.shiftKey && sel.length > 0) {
if(ti > li) ti = [li, li=ti][0];
sel = $ch.slice(ti, li+1);
}
else {
sel = ai < 0 || sel.length > 1 ? [this] : [];
}
last = this;
/* purpose 2
code to check checkboxes inside the array*/
$(sel).each(function(index, checkbox){
/* see/search Note 1 in comments, if the checkbox is already checked/unchecked then uncheck/check all the elements straight from the last element correspondingly */
if(self.checked) {
if( checkbox != self){
checkbox.checked = false;
}
} else {
if( checkbox != self){
checkbox.checked = true;
}
}
})
/*end of purpose 2*/
// settings.onSelect.call(that, sel); // this is defined just in case we want to call some function after the select/deselect operation
});
});
};
}(jQuery));
setTimeout(function(){
$("table.list").selekt();
},500)
</script>
Related
In My project I have a table with button to add new row. In each row a select box is there when I pick an option it should be disabled in all other select boxes including the new ones. When I tried this code in here enter link description here
it works. But in Asp.net core it doesn't work entirely it only works for the first select box option.
This is my code in Asp.net Core, I modified it to work but still not all select box selected option updated and disabled
Why does the same code works outside visual studio and on visual studio it doesn't work the same way>
<table id="empData">
<thead>
<tr>
<th>Location</th>
<th>Role</th>
<th>Action</th>
</tr>
</thead>
<tbody id="UserLocation">
<tr>
<td>
<select id="select1" asp-for="#Model.Location" asp-
items="Html.GetEnumSelectList<Location>()" class="stockCode form-control"
name="locations">
</select>
</td>
<td>
<select id="select2" asp-for="#Model.roles" asp-items="ViewBag.Rolelist"
class="form-control" name="role">
</select>
</td>
<td><Button onClick='deleteRow(this)' class="kx-repeatable" /></td>
</tr>
</tbody>
</table>
<button onClick="addNewRow()" id="AddNew">Add New Row</button>
Jquery Code
$(document).ready(function () {
addNewRow = function () {
var newRow = $("#empData tbody tr").first().clone()
$("#UserLocation").append(newRow);
}
deleteRow = function (element) {
$(element).parent().parent().remove();
}
});
$(document).ready(function () {
var masterList = [];
var selectedList = [];
Array.prototype.equals = function (array) {
// if the other array is a falsy value, return
if (!array)
return false;
// compare lengths - can save a lot of time
if (this.length != array.length)
return false;
for (var i = 0, l = this.length; i < l; i++) {
// Check if we have nested arrays
if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].equals(array[i]))
return false;
}
else if (this[i] != array[i]) {
// Warning - two different object instances will never be equal: {x:20} !=
{x:20}
return false;
}
}
return true;
}
function createMasterList() {
masterList = [];
$('#select1\\(1\\)').children('#select1 option').each(function () {
masterList.push($(this).val());
});
masterList.shift(); //remove blank value
}
createMasterList(); //used to check if all dropdown values have been selected
function updateSelectedList() {
selectedList = [];
var selectedValue;
$('#empData #select1').each(function () {
selectedValue = $(this).find('#select1 option:selected').val();
if (selectedValue != "" && $.inArray(selectedValue, selectedList) == "-1") {
selectedList.push(selectedValue);
}
});
}
//disable the dropdown items that have already been selected
function disableAlreadySelected() {
$('#select1 > option:selected').each(function () {
if ($.inArray(this.value, selectedList) != "-1") {
$(this).attr("disabled", "disabled");
} else {
$(this).attr("disabled", "");
}
});
}
//If all values have been selected, don't let the user add more rows
function hideAddButtonIfDone() {
masterList.sort();
selectedList.sort();
if (masterList.equals(selectedList)) {
console.log("lists equal, hiding add button");
$('#empData #AddNew').hide();
}
else {
console.log("lists not equal, showing add button");
$('#empData #AddNew').show();
}
}
$('#empData').on('change', '.stockCode', function () {
setTimeout(function () {
updateSelectedList();
disableAlreadySelected();
hideAddButtonIfDone();
}, 0.1);
});
//when a new table row is added, disable the dropdown options that have already been
selected
$('#empData #AddNew').on('click', disableAlreadySelected);
//when a table row is removed, update all dropdowns (the removed row's dropdown option
will be re-enabled
//in remaining dropdowns
$('#empData').on('DOMNodeRemoved', '.kx-repeatable > tr', function () {
updateSelectedList();
disableAlreadySelected();
hideAddButtonIfDone();
});
});
I think it is because id is not unique,when add a new row,it will create selects with the same ids,so the element cannot be found and used correctly by id.Here is a working demo:
<table id="empData">
<thead>
<tr>
<th>Location</th>
<th>Role</th>
<th>Action</th>
</tr>
</thead>
<tbody id="UserLocation">
<tr>
<td>
<select asp-for="#Model.Location" asp-
items="Html.GetEnumSelectList<Location>()" class="stockCode form-control"
name="locations">
</select>
</td>
<td>
<select asp-for="#Model.roles" asp-items="ViewBag.Rolelist"
class="form-control" name="role">
</select>
</td>
<td><Button onClick='deleteRow(this)' class="kx-repeatable" /></td>
</tr>
</tbody>
</table>
<button onClick="addNewRow()" id="AddNew">Add New Row</button>
js:
$(document).ready(function () {
addNewRow = function () {
var newRow = $("#empData tbody tr").first().clone()
$("#UserLocation").append(newRow);
disableAlreadySelected();
}
deleteRow = function (element) {
$(element).parent().parent().remove();
}
var masterList = [];
var selectedList = [];
Array.prototype.equals = function (array) {
// if the other array is a falsy value, return
if (!array)
return false;
// compare lengths - can save a lot of time
if (this.length != array.length)
return false;
for (var i = 0, l = this.length; i < l; i++) {
// Check if we have nested arrays
if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].equals(array[i]))
return false;
}
else if (this[i] != array[i]) {
// Warning - two different object instances will never be equal: {x:20} !=
{ x: 20 }
return false;
}
}
return true;
}
function createMasterList() {
masterList = [];
$('#select1\\(1\\)').children('#select1 option').each(function () {
masterList.push($(this).val());
});
masterList.shift(); //remove blank value
}
createMasterList(); //used to check if all dropdown values have been selected
function updateSelectedList() {
selectedList = [];
var selectedValue;
$('#empData .stockCode').each(function (index,element) {
selectedValue = $(element).find('option:selected').val();
if (selectedValue != "" && $.inArray(selectedValue, selectedList) == "-1") {
selectedList.push(selectedValue);
}
});
}
//disable the dropdown items that have already been selected
function disableAlreadySelected() {
$('.stockCode > option').each(function (index,element) {
if ($.inArray(element.value, selectedList) != "-1") {
$(element).attr("disabled", "disabled");
} else {
$(element).removeAttr("disabled");
}
});
}
//If all values have been selected, don't let the user add more rows
function hideAddButtonIfDone() {
masterList.sort();
selectedList.sort();
if (masterList.equals(selectedList)) {
console.log("lists equal, hiding add button");
$('#empData #AddNew').hide();
}
else {
console.log("lists not equal, showing add button");
$('#empData #AddNew').show();
}
}
$('#empData').on('change', '.stockCode', function () {
setTimeout(function () {
updateSelectedList();
disableAlreadySelected();
hideAddButtonIfDone();
}, 0.1);
});
//when a new table row is added, disable the dropdown options that have already been selected
//$('#empData #AddNew').on('click', disableAlreadySelected);
//when a table row is removed, update all dropdowns (the removed row's dropdown option
//will be re - enabled
//in remaining dropdowns
$('#empData').on('DOMNodeRemoved', '.kx-repeatable > tr', function () {
updateSelectedList();
disableAlreadySelected();
hideAddButtonIfDone();
});
});
result:
I'm wondering if there is a way for this search bar that I'm using to display multiple elements. As it is right now if I search for "123" in a pool with "321" "1234" "123" "12345" The only displayed value would be the first one: "1234". I'd like for all values that match my search to be displayed, therefore this would be the correct search result: "1234" "123" "12345".
Any answer is appreciated.
Here's the current code that I have:
var cells = document.querySelectorAll("#myTable td");
var search = document.getElementById("myInput");
search.addEventListener("keyup", function() {
if (search.value.length > 0 && search.value != '') {
for (var i = 0; i < cells.length; ++i) {
if (cells[i].textContent.toLowerCase().indexOf(search.value.toLowerCase()) === 0) {
cells.forEach(function(element) {
element.style.display = "none";
});
cells[i].style.display = "table-cell";
break;
} else {
cells.forEach(function(element) {
if (cells[i] !== element) {
element.style.display = "table-cell";
}
});
}
}
} else {
cells.forEach(function(element) {
if (cells[i] !== element) {
element.style.display = "table-cell";
}
});
}
});
<input id="myInput">
<table id="myTable">
<tr>
<td>321</td>
<td>123</td>
</tr>
<tr>
<td>1234</td>
<td>abc</td>
</tr>
<tr>
<td>12345</td>
<td>abcde</td>
</tr>
</table>
Your cells selector returns a nodelist this is an arrayish object. That doesn't have the forEach function.
However we can borrow from the Array object:
Array.prototype.forEach
What I did to solve the other problem is create an indexArray as a lookup array. that keeps track of the indices that contained the search string. Then when we loop all the cells we can turn the ones of that don't show up in the lookup array
var cells = document.querySelectorAll("#myTable td");
var search = document.getElementById("myInput");
search.addEventListener("keyup", function() {
var indexArray = []; //look up array
for (var i = 0; i < cells.length; ++i) {
//restore the cells:
cells[i].style.display = "table-cell";
//if search value is found the value will be 0 if it starts a the beginning
if (cells[i].textContent.toLowerCase().indexOf(search.value.toLowerCase()) === 0) {
indexArray.push(i); //push index into lookup
}
}
//loop over all cells
Array.prototype.forEach.call(cells, function(element, index) {
if (indexArray.indexOf(index) === -1) //if index is not present in look up, set display to none
element.style.display = "none";
});
});
<input id="myInput">
<table id="myTable">
<tr>
<td>321</td>
<td>123</td>
</tr>
<tr>
<td>1234</td>
<td>abc</td>
</tr>
<tr>
<td>12345</td>
<td>abcde</td>
</tr>
</table>
below code is enough if you want to show which cell has contain that search; also you can test on jsfiddle https://jsfiddle.net/bzcdomjs/
var cells = document.querySelectorAll("#myTable td");
var search = document.getElementById("myInput");
search.addEventListener("keyup", function() {
for (var i = 0; i < cells.length; ++i) {
cells[i].style.display = "table-cell";
if (search.value.length > 0 && search.value != '') {
if(cells[i].textContent.toLowerCase().indexOf(search.value.toLowerCase()) === -1) {
cells[i].style.display = "none";
}
}
});
How do I go about either modifying the existing Javascript code or add some code to be able to have the option to delete the highlighted (selected row) from my HTML table at the click of a button?
The use of jQuery is framework also fine.
<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
<script type="text/javascript">
window.onload = function() {
test()
}
function test() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow, nextrow,
rownum = document.getElementById('rownum'),
addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false); //modern browsers
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, function(e){f.apply(el, [e]);}); //IE 8 and less
}:function(){return;}; //a very old browser (IE 4 or less, or Mozilla, others, before Netscape 6), so let's skip those
})();
rownum.value = rownum.defaultValue; //reset for browsers that remember input values on reload
while (--t > -1) {
trow = trows[t];
trow.className = 'normal';
addEvent(trow, 'click', highlightRow);
}//end while
function highlightRow(gethighlight) { //now dual use - either set or get the highlighted row
gethighlight = gethighlight === true;
var t = trows.length;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight){
if(trow !== this) { trow.className = 'normal'; }
else if(this.className === 'normal') { rownum.value = t; }
else { rownum.value = rownum.defaultValue; }
}
}//end while
return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function
function movehighlight(way, e){
e.preventDefault && e.preventDefault();
e.returnValue = false;
var idx = highlightRow(true); //gets current index or null if none highlighted
if(typeof idx === 'number'){//there was a highlighted row
idx += way; //increment\decrement the index value
if(idx && (nextrow = trows[idx])){ return highlightRow.apply(nextrow); } //index is > 0 and a row exists at that index
else if(idx){ return highlightRow.apply(trows[1]); } //index is out of range high, go to first row
return highlightRow.apply(trows[trows.length - 1]); //index is out of range low, go to last row
}
return highlightRow.apply(trows[way > 0? 1 : trows.length - 1]); //none was highlighted - go to 1st if down arrow, last if up arrow
}//end function
function processkey(e){
switch(e.keyCode){
case 38: {//up arrow
return movehighlight(-1, e)
}
case 40: {//down arrow
return movehighlight(1, e);
}
default: {
return true;
}
}
}//end function
addEvent(document, 'keydown', processkey);
addEvent(window, 'unload', function(){}); //optional, resets the page for browsers that remember the script state on back and forward buttons
}//end function
</script>
</head>
<body>
<div>
Current Row: <input type="text" id="rownum" value="None" readonly>
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>
</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>
<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>
<br><br>
<input type="button" value="delete this row" onclick="delete_row()"/>
</body>
</html>
this seems to work, once the row number seems to accounted for.
function delete_row() {
var r = document.getElementById("rownum").value
document.getElementById("mstrTable").deleteRow(r);
}
Use this (if you know the row number)
function delete_row() {
var r = document.getElementById("rownum").value
document.getElementById("mstrTable").deleteRow(r);
}
This only deletes a row that is selected. No need to pass in the row number.
function delete_row() {
document.querySelector(".highlighted").remove();
}
You can see it working here: http://jsbin.com/gubuduli/3/edit?html,output
How do you write this so it runs faster. It looks like because I'm using an each() it is slowing it down.
Can I use filter()?
$("#X tr").each(function () {
if ($(this).find("table td:eq(1)").text() == "a") {
$(this).css("background":"red");
}
});
<table id = "X">
<tr >
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
<tr >
<td></td>
<td></td>
<td></td>
</tr>
...
<tr >
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
</table>
thanks
I'd suggest:
$('td:contains("a")').closest('tr').css('background-color','red');
JS Fiddle demo.
Or, in to affect all ancestor tr elements:
$('td:contains("a")').parents('tr').css('background-color','red');
JS Fiddle demo.
Or to affect all tr elements with descendent (however deeply nested):
$('tr').filter(
function(){
return $(this).find('td:contains("a")').length;
}).css('background-color','red');
JS Fiddle demo.
Added a function, lookAt() that might be used instead:
function lookAt(haystack, needle) {
if (!haystack) {
return false;
}
else {
needle = needle ? needle : 'a';
for (var i = 0, len = haystack.childNodes.length; i < len; i++) {
var cur = haystack.childNodes[i];
if (cur.nodeType == 3 && cur.nodeValue.indexOf(needle) > -1){
return true;
}
else if (i == (len-1)) {
return false;
}
}
}
}
$('#table td').filter(
function() {
return lookAt(this);
}).css('background-color', 'red');
JS Fiddle demo
JS Perf test examining the lookAt() function approach against the return $(this).is(':contains("a")') Sizzle-based approach.
For reference, for a closer comparison the JS Perf jQuery test was the following:
$('#table td').filter(
function() {
return $(this).is(':contains("a")')
}).css('background-color', 'red');
JS Fiddle demo.
You can use the :contains selector: http://jsfiddle.net/Af6Nz/1/.
$("#X tr:contains('a')").css("background-color", "red");
Using contains and parent (to go back to the tr that we want to colorize) :
$(this).find('td:eq(0):contains("a")').parent().css("background","red");
or using has :
$(this).find('tr:has(td:eq(0):contains("a"))').css("background","red");
If you don't need the eq condition, use
$(this).find('td:contains("a")').parent().css("background","red");
Keep in mind that eq is 0-based (as your test case didn't involve a matching element with 1 instead of 0).
Demonstration : http://jsfiddle.net/KRqQN/
If you're concerned about performance, the following might help.
var getText = (function() {
var div = document.createElement('div');
if (typeof div.textContent == 'string') {
return function (el) {
return el.textContent;
};
} else if (typeof div.innerText == 'string') {
return function (el) {
return el.innerText;
};
}
}());
function foo(table) {
var row, rows = table.rows;
var i = rows.length;
var re = /a/;
while (i--) {
row = rows[i];
if (re.test(getText(row))) {
row.style.backgroundColor = 'red';
}
}
}
Using jQuery, how can I find the column index of an arbitrary table cell in the example table below, such that cells spanning multiple columns have multiple indexes?
HTML
<table>
<tbody>
<tr>
<td>One</td>
<td>Two</td>
<td id="example1">Three</td>
<td>Four</td>
<td>Five</td>
<td>Six</td>
</tr>
<tr>
<td colspan="2">One</td>
<td colspan="2">Two</td>
<td colspan="2" id="example2">Three</td>
</tr>
<tr>
<td>One</td>
<td>Two</td>
<td>Three</td>
<td>Four</td>
<td>Five</td>
<td>Six</td>
</tr>
</tbody>
</table>
jQuery
var cell = $("#example1");
var example1ColIndex = cell.parent("tr").children().index(cell);
// == 2. This is fine.
cell = $("#example2");
var example2ColumnIndex = cell.parent("tr").children().index(cell);
// == 2. It should be 4 (or 5, but I only need the lowest). How can I do this?
Here's a plugin which can calculate the 'noncolspan' index.
$(document).ready(
function()
{
console.log($('#example2').getNonColSpanIndex()); //logs 4
console.log($('#example1').getNonColSpanIndex()); //logs 2
}
);
$.fn.getNonColSpanIndex = function() {
if(! $(this).is('td') && ! $(this).is('th'))
return -1;
var allCells = this.parent('tr').children();
var normalIndex = allCells.index(this);
var nonColSpanIndex = 0;
allCells.each(
function(i, item)
{
if(i == normalIndex)
return false;
var colspan = $(this).attr('colspan');
colspan = colspan ? parseInt(colspan) : 1;
nonColSpanIndex += colspan;
}
);
return nonColSpanIndex;
};
Mine is quite similar to SolutionYogi's, minus the creation of a plugin. It took me a bit longer... but I'm still proud of it so here it is :)
cell = $("#example2");
var example2ColumnIndex2 = 0;
cell.parent("tr").children().each(function () {
if(cell.get(0) != this){
var colIncrementor = $(this).attr("colspan");
colIncrementor = colIncrementor ? colIncrementor : 1;
example2ColumnIndex2 += parseInt(colIncrementor);
}
});
console.log(example2ColumnIndex2);
There is a more concise answer here: Get Index of a td considering the colspan using jquery
In short:
var index = 0;
$("#example2").prevAll("td").each(function() {
index += this.colSpan;
});
console.log(index);
You could do something like this:
var index = 0;
cell.parent('tr').children().each(
function(idx,node) {
if ($(node).attr('colspan')) {
index+=parseInt($(node).attr('colspan'),10);
} else {
index++;
}
return !(node === cell[0]);
}
);
console.log(index);
It'd probably make sense to do it as a plugin or via extend.
Slightly modified version is here: http://jsfiddle.net/Lijo/uGKHB/13/
//INDEX
alert ( GetNonColSpanIndex ('Type'));
function GetNonColSpanIndex(referenceHeaderCellValue) {
var selectedCell = $("th").filter(function (i) {
return ($.trim($(this).html() )) == referenceHeaderCellValue;
});
alert(selectedCell.html());
var allCells = $(selectedCell).parent('tr').children();
var normalIndex = allCells.index($(selectedCell));
var nonColSpanIndex = 0;
allCells.each(
function (i, item) {
if (i == normalIndex)
return false;
var colspan = $(selectedCell).attr('colspan');
colspan = colspan ? parseInt(colspan) : 1;
nonColSpanIndex += colspan;
}
);
return nonColSpanIndex;
};