I can't figure out why after I search for something and then delete that search query to search something else the table doesn't display anything but is still searching for the right answer.
So in the jsfiddle if you type 001 then delete that to try to look for 002 the table that was displayed doesn't show up anymore. Any help would be greatly appreciated!
let rows = document.querySelector("#Test").rows;// or much precise query if needed
function check(event) {
let caps = event.target.value.toUpperCase();
let hyphen = caps.replace(/[-]/g, ""); // Edit : caps + hyphen will work
// Browse all rows to check if input matching and hide/show
// Fortunately row.textContent yields all texts values :)
for(let i = 1; i < rows.length; i++) {
let row = rows[i];
// test caps length to allow revert to all hidden when no text to match
if(caps.length && (row.textContent.indexOf(caps) >= 0 || row.textContent.indexOf(hyphen) >= 0)) { row.style.display = "";} // process next row
else{
row.style.display = 'none'; // Hide row (avoid an else)
}
}}
document.getElementById('myInput').addEventListener('keyup', check, true);
https://jsfiddle.net/jx8vw64L/9/
Get rid of the
caps.length &&
in your if
if((row.textContent.indexOf(caps) >= 0 || row.textContent.indexOf(hyphen) >= 0))
{
row.style.display = "";
} // process next row
else
{
row.style.display = 'none'; // Hide row (avoid an else)
}
Do you html markup like this
function textChange() {
//DO SOME CODE
}
<input type="text" name="foo" onKeyUp="return textChange()" />
OR WITH JQUERY
$('.target').change(function() {
//DO SOME CODE
});
Related
On my website, users can click on some text to open up a Modal. This Modal allows users to choose a bunch of toppings to add to their Pizza.
Through Javascript, I add each selected topping to an array and change the text display to match their selected toppings. This more or less works, but the problem is for some reason, whenever they add a topping, it is added to ALL arrays, not just the item it's selected for. Can someone help me find why this is happening?
// Open Toppings Modal
$(document).ready(function() {
var count = -1
var tplist = []
$(".order").each(function(){
count += 1
tplist.push([])
var listeners = 0
setModal(count, tplist, listeners)
});
function setModal(count, tplist, listeners) {
$("#openModal" + count).click(function(){
console.log("clicked")
$("#toppingModal" + count).modal()
if (listeners == 0) {
listeners += 1
$("input[type='checkbox']").change(function() {
// TODO: Fix Bug
// Adding to all javascript lists
if (this.checked) {
tplist[count].push($(this).val());
console.log(tplist)
}
else {
ele = $(this).val();
pos = $.inArray(ele, tplist[count])
if ( ~pos ) tplist[count].splice(pos, 1);
}
// Change text to list
if (tplist[count].length > 0) {
$("#openModal" + count).text(tplist[count])
}
else {
$("#openModal" + count).text("Select Toppings")
}
})
}
});
};
});
I am suspecting your $("input[type='checkbox']").change(function() {} is called for every model. Try setting count number somewhere when you click select topping and compare inside $("input[type='checkbox']").change(function() {} to prevent adding of toppings in all arrays
By inefficient I mean, activating the code makes the page hang for 20+ seconds.
To set the scene, I currently have an HTML table that looks like the following. It can be fairly big, easily 1,000-1,500 rows and 40 columns wide. It is generated from Python/Flask as a static HTML table and then javascript takes over to allow the users to filter out and sort rows. I do use the jquery tablesorter widget to allow users to sort rows by whatever column they wish.
The table itself has a structure like:
<table id="myTablePlayers" class="tablesorter table table-striped table-bordered table-hover" style="overflow: visible">
<thead>
<tr>
<th>...</th>
<th>...</th>
<th>...</th>
<th>...</th>
...
<th>...</th>
</tr>
</thead>
<tbody>
<tr class="playerData">
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
...
<td>...</td>
</tr>
...
</tbody>
</table>
The filters that users are given are as follows:
minimum GP - input field that removes all rows less than the user's input in a specific column
teams - select field (text) that removes all rows that does not match in a specific column
position - select field (text) that removes all rows that does not match in a specific column
age - input field that removes all rows less than the user's input in a specific column (e.g. if enters 20, it will keep all rows with the age in the range [20.0, 21.0)
The javascript/jquery I have written and is likely the culprit is as follows:
function autoRank() {
// auto number
rank = 0;
$("#myTablePlayers .playerData").each(function() {
if ($(this).css("display") != "none") {
rank++;
$(this).find('td').eq(colRank).text(rank);
}
});
}
function filterTable() {
// Need some error checking on input not number
minGP = $("#mingp").val()
teams = $("#teamFilter").val()
position = $("#position").val()
age = $("#age").val()
$("#myTablePlayers .playerData").show();
$("#myTablePlayers .playerData").each(function() {
toHide = false;
if (teams != "") {
if ( !$(this).find('td').eq(colTeam).text().toUpperCase().includes(teams.toUpperCase())) {
toHide = true;
}
}
if ( Number($(this).find('td').eq(colGP).text()) < minGP ) {
toHide = true;
}
if (position != "") {
if (position == "D") {
if ($(this).find('td').eq(colPos).text().indexOf("D") == -1) {
toHide = true;
}
} else if (position == "F") {
if ($(this).find('td').eq(colPos).text().indexOf("D") != -1) {
toHide = true;
}
} else if ( $(this).find('td').eq(colPos).text() != position) {
toHide = true;
}
}
if (age != "") {
column = Number($(this).find('td').eq(colAge).text())
age = Number(age)
if ( column < age || column >= age+1 ) {
toHide = true;
}
}
if (toHide == true) {
$(this).hide();
}
});
autoRank();
}
$("#teamFilter").on('change', filterTable);
$("#mingp").on('change', filterTable);
$("#position").on('change', filterTable);
$("#age").on('change', filterTable);
What is the inefficiency in this code that makes the browser hang? What should I be changing to make it efficient?
I looked at Google but jquery table filter plug ins do not give me the ability to filter rows based on specific columns based on specific inputs as outlined above (e.g. https://www.sitepoint.com/12-amazing-jquery-tables/).
Currently your code works like this:
iterate all rows
then for each row:
successively for each not-empty filter, look for all its child columns
then isolate the involved column and get its value
Only regarding the above exposed mechanism and using some numbers you cited it means that, with a unique simple filter like "teams" you actually touch 40000 columns (1000 rows * 1 filter * 40 columns).
But if 2 filters are not-empty it immediately grows to 80000 columns touched, and so on.
This is obviously a first realm where to find a way to work faster, with a pretty simple change like this:
iterate all rows
then for each row:
look for all its child columns
successively for each not-empty filter, then isolate the involved column and get its value
The involved part of code becomes:
$("#myTablePlayers .playerData").each(function() {
var toHide = false,
columns = $(this).find('td');
if (teams != "") {
if ( !columns.eq(colTeam).text().toUpperCase().includes(teams.toUpperCase())) {
toHide = true;
}
}
// ...same for next filters
This way, we already get rid of multiplying the column touches by the number of not-empty filters.
But we can go further...
In the current situation, each execution actually touches all the cells of the table, while at most 4 columns are involved (for the 4 filters). So we might try to find a way to reduce the total number of touched columns from 40000 to 4000!
This can be achieved by affecting a distinguishing class (say the filter-name) to these involved columns, so we might change the code like this:
$("#myTablePlayers .playerData").each(function() {
var toHide = false,
classTeam = '.colTeam',
classGP = `.colGP`,
classPos = `.colPos`,
classAge = `.colAge`;
if (teams != "") {
if ( !$(classTeam, this).text().toUpperCase().includes(teams.toUpperCase())) {
toHide = true;
}
}
// ...same for next filters
Maybe there is an issue with this:
It is generated from Python/Flask as a static HTML table
which means you don't have hand on the generated table.
If so, you can merely add the following to affect the class names just after the page load:
$(document).ready(function() {
$("#myTablePlayers .playerData").each(function() {
$('td', this).eq(colTeam).addClass(classTeam);
$('td', this).eq(colGP).addClass(classGP);
// ...
}
}
But actually it might be improved another way (then the previous suggestion becomes useless), using a totally different method.
Since the table is static, we can act just after the page load (so only once) to prepare the needed data for a more direct access when filtering happens.
We can pre-register all the involved columns for each filter:
$(document).ready(function() {
var teamCols = $(),
GPCols = $(),
posCols = $(),
ageCols = $();
$("#myTablePlayers .playerData").each(function() {
var columns = $(this).find('td');
teamCols.add(columns.eq(colTeam));
GPCols.add(columns.eq(colGP));
posCols.add(columns.eq(colPos));
ageCols.add(columns.eq(colAge));
}
}
Then the filter can process directly addressing the involved columns. BTW we can also immediately hide their parent (this was already possible in the original version):
if (teams) {
teamCols.each(function() {
if (!this.innerHTML.toUpperCase().includes(teams.toUpperCase())) {
$(this).parent().hide();
}
}
}
This is written a bit quickly, so it might contain some flaws, and also might be yet improved...
You can improve your code by caching your re-used elements, and doing less iterations. Currently, you do three iterations over the records that can be condensed into one.
Here's how I would do it (untested):
$(function () {
// cache the elements that you will be re-using
var $minGP = $("#mingp"),
$team = $("#teamFilter"),
$position = $("#position"),
$age = $("#age");
var $rows = $("#myTablePlayers .playerData");
function filterTable() {
// Need some error checking on input not number
var minGP = $minGP.val(),
team = $team.val(),
position = $position.val(),
age = $age.val();
// set the rank as we loop (instead of having a separate iteration for ranking)
var rank = 0;
// when you use show() and .each(), you are iterating over all the rows twice
// instead loop once
$rows.each(function() {
// cache current row as it will be re-used
var $row = $(this);
// set flag to show or hide
var display = true;
if (teams != "" &&
!$row.find('td').eq(colTeam).text().toUpperCase().indexOf(teams.toUpperCase()) > -1) {
display = false;
}
if (Number($row.find('td').eq(colGP).text()) < minGP) {
display = false;
}
if (position != "") {
if (position == "D" &&
$row.find('td').eq(colPos).text().indexOf("D") == -1) {
display = false;
} else if (position == "F" &&
$row.find('td').eq(colPos).text().indexOf("D") != -1) {
display = false;
} else if ($row.find('td').eq(colPos).text() != position) {
display = false;
}
}
if (age != "") {
column = Number($row.find('td').eq(colAge).text())
age = Number(age)
if (column < age || column >= age + 1) {
display = false;
}
}
// hide or show row
$tr.toggle(display);
// set rank number
if (display) {
$row.find('td').eq(colRank).text(rank++);
}
});
}
// attach change event handler
$minGP.add($team).add($position).add($age).change(filterTable);
});
This might speed up your code by few seconds, but ultimately it depends on how much and how big your data is.
When I go to Insert first record into the gridview. What I want is, My Amount column should not be 0 or less than that.
Here is what my code looks like.
function checkAgrmVal() {
for (var i = 0; i < GridPayInfo.Rows.length; i++) {
var AgrmntAmt = GridPayInfo.Rows[i].Cells[5].Value;
alert(AgrmntAmt);
if (AgrmntAmt <= "0") {
alert('Agreement amount cannot be 0 or less than 0');
return false;
}
}
}
It doesn't works when I go to add the first row, but it does work when I go to add the second row.
To get table rows use GridPayInfo.rows[i].cells[5] not Rows and
Cells
To get Cell content use innerText, textContent to get text or innerHTML to get HTML not .Value.
.Value should be .value that works with input and textarea.
So Your example should work see below code:
function checkAgrmVal() {
var GridPayInfo = document.getElementById("tbl");
for (var i = 0; i < GridPayInfo.rows.length; i++) {
var AgrmntAmt = GridPayInfo.rows[i].cells[5].innerText;
if (AgrmntAmt <= "0") {
alert('Agreement amount cannot be 0 or less than 0 found in row: '+ (+i+1));
return false;
}
}
}
<table id='tbl'>
<tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td><td>-1</td></tr>
<tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td><td>5</td></tr>
<tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td><td>-3</td></tr>
<tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td><td>-4</td></tr>
<tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td><td>3</td></tr>
</table>
<button onclick='checkAgrmVal()'>check</button>
im have a code that add and remove dynamically form controls. The add and delete methods works fine. But i like if exist only one control, not remove it.
I defined the next var, outside $(document).ready scope:
var Alumnos = {};
And initialize inside of $(document).ready:
// Valor inicial de casilleros renderizados.
Alumnos.count = 3;
The method that remove controls is:
// Elimina un bloque
$(document).on('click','.closable',function(){
if(Alumnos.count > 1){
var idRow = $(this).attr('data-toggle');
var victim = $(idRow + " .row-fluid:last-child");
victim.remove();
var childs = $(idRow).children();
if(childs.length === 0)
{
$(idRow).remove();
$(this).remove();
Alumnos.count -= 1;
}
}
console.log(Alumnos.count);
return false;
});
The Alumnos.count value persist after delete. Any ideas ?
UPDATE 1
When the user click on "Add more", the code, create a form row with 3 controls, from a prototype.
Because, i cant use children count.
I need the user dont remove all controls.
I think you should have:
if(Alumnos.count >= 1){ //Probably if there is only 1, it's erasable. You had >
And move the decrement outside, like this:
var childs = $(idRow).children();
if(childs.length === 0)
{
$(idRow).remove();
$(this).remove();
}
Alumnos.count -= 1; //This was moved
Hope this helps. Cheers
Thanks for all your replies !! I found the way to control the elements remove with the childs count. May be isnt the best code, but works.
$(document).on('click','.closable',function(){
// Get the id of the row.
var dataToggle = $(this).attr('data-toggle');
// Get the row
var row = $(dataToggle);
// if isnt first row (#id0), ok, remove all if you want.
// if is first row (#id0) and have more than one child, happy remove ^^
if((dataToggle === "#id0" && row.children().length > 1) || dataToggle !== "#id0"){
// remove code...
}
return false;
});
I have one HTML table and I don't want the value of 2nd column to repeat in the grid.
Here is my jQuery:
$('#tb_cartTable tr td:nth-child(2)').each(function() {
$ele=$(this).text();
if($ele==$productCode)
{
flag="x";
return false;
}
});
if($rowCounter>0 && flag=="x")
{
alert("Duplicate");
}
else
{
//...
}
One way will be to "map" the text of the cells into a JavaScript complex array having the text as key, then compare the amount of keys to amount of cells. If more cells than keys it means there are cells with the same text.
Code for this:
var allCells = $('#tb_cartTable tr td:nth-child(2)');
var textMapping = {};
allCells.each(function() {
textMapping[$(this).text()] = true;
});
var count = 0;
for (var text in textMapping)
count++;
if (count !== allCells.length) {
alert("found duplicate values");
} else {
alert("no duplicates found");
}
Live test case.
Note the above is case sensitive: if there is a cell with "hello" and cell with "Hello" those will be considered different and it will think there are no duplicates. If case doesn't matter fix is simple case of changing the line to:
textMapping[$(this).text().toLowerCase()] = true;
Updated test case where it ignores case.
In your specific case you can store all the added values in plain array then check the array using the jQuery inArray() method:
var $addedProductCodes = [];
$("#button_addItem").click(function(event)
{
$("span.errorText").remove();
$(".errorField").addClass("notErrorField");
//Change background color of textbox to normal
$("#frmRegisterForm :input[type='text']").attr('class','notErrorField');
$hasError = false;
$ele = $(event.target);
if($ele.is("input[type=button]"))
{
$td_productCode1=$("#td_productCode1").val();
var index = $.inArray($td_productCode1, $addedProductCodes);
if (index >= 0) {
alert("You already added this product code in line #" + (index + 1));
} else {
$text_productDescription= $("#text_productDescription").val();
$text_basicDealerPrice = $("#text_basicDealerPrice").val();
$('#table_viewContent').append("<tr><td>"+$text_productDescription+"</td><td>"+$td_productCode1+"</td><td><td>"+$text_basicDealerPrice+"</td><td><input type='button' name='deleteRow' id='btn_deleteRow' value='Delete' id='deleteItem' class='deleteItem button-red'></td></tr>");
$addedProductCodes.push($td_productCode1);
}
}
});
Updated fiddle where adding same product code will give alert and won't insert.