JavaScript table for loop wrong checkbox value - javascript

I'm for looping data in my page, and they are showing fine, but when I'm trying to click one of three checkboxes and hide desired rows, it seems that get the wrong value.
This is the link of the live page in action.
This is the code that needs to be fixed.
https://musing-jang-0e572c.netlify.com/senate-data.html -> PAGE
https://github.com/Makkoyev/ubiqum-task2/blob/master/assets/js/manipulation.js -> Checkboxes section GitHub
This is the code:
(function () {
if (currentURL.indexOf("senate-data.html") == true) {
getSenate();
cbs = document.querySelectorAll("input[type=checkbox]");
targets = document.querySelectorAll("#table tr td:nth-child(2)");
tr = document.querySelectorAll("#table tr");
for (i = 0; i < cbs.length; i++) {
cbs[i].addEventListener('change', function () {
if (this.checked) {
// Checkbox is checked..
console.log("Checkbox checked!", this.value);
for(i = 0; i < targets.length; i++){
if(this.value == targets[i].innerHTML){
console.log("Uguale", targets[i]);
targets[i].parentNode.classList.add("hide-row");
}
}
} else {
// Checkbox is not checked..
console.log("Checkbox unchecked!", this.value)
}
});
}
}
if (currentURL.indexOf("house-data.html") == true) {
getHouse();
}
})();

You likely want something like this
FIDDLE
window.addEventListener("load", function() { // on page load
[...document.querySelectorAll("input[type=checkbox]")].forEach(function(cbs) { // take all checkboxes
cbs.addEventListener('change', function() { // when they change
var vals = [...document.querySelectorAll(".filters input[type=checkbox]:checked")].map(chk => chk.value); // get all checked values
[...document.querySelectorAll("#table tr td:nth-child(2)")].forEach(function(target) { // for all cell 2
target.parentNode.classList.toggle("hide-row",
vals.indexOf(target.textContent) == -1); // hide the ones NOT in the above list
});
});
});
})

Related

Changing DOM with Select Option and checking no of required fields

There is a webpage with certain number of required fields that needs to be filled in order to submit a form successfully.
The biggest indicator of required field is that it has a * and its label has a class 'required' in it.
The number of required fields change when we change dropdown value. I have written some javascript and jquery code that changes the dropdown value and then checks the number of required fields but for some reason(most probably DOM changes is taking time and code executes before that so actually the change in number of required fields is not reflected in page). However if I change the dropdown value manually and then run the checkRequired() function, it works fine but I want to automate the procedure. How can I achieve that?
var count = 0;
var allRequired = []; // total number of required fields in the page
var newRequired = []; // change in the no. of required fields
$('select').each(function(){
var id = $(this).attr('id');
$('#'+id+' option').each(function() {
$(this).attr('selected','selected');
if(count == 0){
getAllRequiredFields();
}
else{
setTimeout(() => {
checkRequired();
for (let index = 0; index < allRequired.length; index++) {
console.log('for else',allRequired[index]);
if(!newRequired.includes(allRequired[index])){
console.log('allRequired',allRequired[index]);
}
}
}, 3000);
}
count++;
})
});
function getAllRequiredFields(){
$('span.required').each(function () {
var text = $(this).parent().text()
var id = $(this).closest("td").attr('id').split("_label")[0];
allRequired.push(id);
});
}
function checkRequired() {
newRequired = [];
$('span.required').each(function () {
var text = $(this).parent().text()
var id = $(this).closest("td").attr('id').split("_label")[0];
newRequired.push(id);
});
for (let index = 0; index < allRequired.length; index++) {
console.log('for else',count);
if(!newRequired.includes(allRequired[index])){
console.log('allRequired',allRequired[index]);
}
}
}
Just added change event fixed my problem
$('#'+id+' option').each(function() {
$(this).attr('selected','selected');
$('#'+id).change();
if(count == 0){
getAllRequiredFields();
}
else{
setTimeout(() => {
checkRequired();
for (let index = 0; index < allRequired.length; index++) {
console.log('for else',allRequired[index]);
if(!newRequired.includes(allRequired[index])){
console.log('allRequired',allRequired[index]);
}
}
}, 3000);
}
count++;
})

Hide data if an array does not have matching value with another array on button click

I have a list of checkboxes with a value and table data's with the same value as an attribute and a button to compare them. What I have done is created an array when a checkbox is checked (checkedArray) and another array of table data attributes (dataArray). Then checked if checkedArray has dataArray values. On button click, if checkedArray has dataArray value then add class to the table data. In the following code, it is showing the data but not removing after I unchecked the checkbox again and compare them.
An example of my code is here.
var checkedArray = [];
$('.checkboxes input').on('change', function() {
var checkedVal = $(this).val();
if($(this).is(':checked')) {
checkedArray.push(checkedVal);
} else {
checkedArray.splice($.inArray(checkedVal, checkedArray), 1);
}
});
var tabledata = $('table td');
function displayData(arr) {
var tableArr = $('table td').map(function() {
return $(this).attr('key');
}).get();
for (var i = 0; i < tableArr.length; i++) {
for (var j = 0; j < arr.length; j++) {
if (tableArr[i] === arr[j]) {
$('table td[key="'+ arr[j] +'"]').addClass('show')
} else {
//$('table td:not[key="'+ arr[j] +'"]').addClass('hide')
}
}
}
}
$('#compare').on('click', function(e) {
e.preventDefault();
displayData(checkedArray);
});
you can hide all td in your table before adding show class for checked ones. for that you can add $('table tr td').removeClass('show') before your for loop, like this:
function displayData(arr) {
var tableArr = $('table td').map(function() {
return $(this).attr('key');
}).get();
$('table tr td').removeClass('show');
for (var i = 0; i < tableArr.length; i++) {
for (var j = 0; j < arr.length; j++) {
if (tableArr[i] === arr[j]) {
$('table td[key="'+ arr[j] +'"]').addClass('show')
} else {
//$('table td:not[key="'+ arr[j] +'"]').addClass('hide')
}
}
}
}
Looking at the fiddle, wouldn't you need to add 'hide' after the 1st css element? 'hide' is only called in the JS as a class but not referenced anywhere else that I'm seeing.
That is,
td {
display: none;
}
should be
td.hide {
display: none;
}

Function to display returned results count isn't working as expected

My jQuery checkbox filter works normally:
http://jsfiddle.net/EducateYourself/Lmehmj26/3/
Under checkbox form I want to show the number of results. It is 7 by default.
When I filter the results, it does not show the correct number of displayed results.
Could you please help me to find my mistake?
I commented the lines in my jsfiddle code where I added variable n to achieve the result I want.
$('.category').on('change', function () {
var n; //declare variable n
var category_list = [];
$('#filters :input:checked').each(function () {
var category = $(this).val();
category_list.push(category);
});
if (category_list.length == 0) {
$('.resultblock').show();
} else {
$('.resultblock').hide();
});
$('#count').text(n); // change the results qunatity
}
});
The problem is that you are incrementing n multiple times for a single element if it contains multiple matching tags.
You should only increment n once, at most, for each element:
Updated Example
$('.resultblock').each(function() {
var item = $(this).data('tag'),
itemArray = item.split(' '),
hasTag = false;
for (var i = 0; i < category_list.length; ++i) {
if (itemArray.indexOf(category_list[i]) >= 0) {
hasTag = true;
}
}
if (hasTag) {
$(this).show();
n++; // Only increment n once, at most, for each element.
}
});
Here is a cleaner, simplified version of your code:
Updated Example
$('.category').on('change', function() {
var categoryList = $('#filters :input:checked').map(function() {
return this.value;
}).get();
var count = 0;
$('.resultblock').hide().each(function() {
var itemTagsArray = $(this).data('tag').split(' ');
var hasTag = false;
categoryList.forEach(function(tag) {
if (itemTagsArray.indexOf(tag) > -1) {
hasTag = true;
}
});
if (hasTag) {
$(this).show();
count++;
}
});
$('#count').text(count);
});
You're counting doubles, a very easy fix is to add a check for visibility in your for loop like so
for (i = 0; i < category_list.length; ++i) {
if (itemArray.indexOf(category_list[i]) >= 0 && !$(self).is(":visible")) {
$(self).show();
n=n+1; //increase the value of n if found a result
}
}
As shown in this fiddle, that works
As a sidenote, your numbering breaks when you've selected one or more checkboxes and then deselect all. To prevent this you should change your check if there's been any checkboxes checked to
if (category_list.length == 0) {
$('.resultblock').show();
$('#count').text($('.resultblock').length);
}

Asp.net multiple gridviews, checkboxes in headertemplate select all / deselect all functionality

I am using two gridview controls in my aspx page. And I have a column of checkbox in both my controls. I am facilitating the user to select/deselect all checkboxes in my both gridviews by providing a checkbox in the header template of both gridviews and using java script functions. below is the code
<script type="text/javascript">
function UncheckParent(obj) {
var isUnchecked = obj.checked;
if (isUnchecked == false) {
var frm = document.forms[0];
for (i = 0; i < frm.length; i++) {
if (frm.elements[i].id.indexOf('chkSelectAllCheckboxes') != -1) {
frm.elements[i].checked = false;
}
}
}
}
function CheckAll(obj) {
var row = obj.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
var inputs = row.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type == "checkbox") {
inputs[i].checked = obj.checked;
}
}
}
</script>
But the problem is that once i select or deselect one of such checkboxes all checkboxes in both the gridviews get checked. I can also give a short example of what is happening. Two gridviews gdvwStudents and gdvwTeachers. Both have checkbox column and a check box in header template. using above code when I click header checkbox of gdvwStudents, all checkboxes in gdvStudents and gdvTeachers get selected. Please
You are doing it wrong. You should be getting the check boxes inside the particular grid where the header is clicked; instead, you are getting ALL the checkboxes created on the form! That's incredibly inefficient and explains why everything is checked/unchecked regardless of which header you click.
If you can use jQuery, you should be able to rewrite those functions into something like this:
function checkAll(gridID,checkbox) {
$("#"+gridID+" input:checkbox").attr("checked",checkbox.checked);
}
See this jsfiddle for a quick example.
Add the javascript function as per below
<script type="text/javascript">
function SelectAll(id, grd) {
//get reference of GridView control
var grid = null;
if (grd = "1") {
grid = document.getElementById("<%= GridView1.ClientID %>");
}
else {
grid = document.getElementById("<%= GridView2.ClientID %>");
}
//variable to contain the cell of the grid
var cell;
if (grid.rows.length > 0) {
//loop starts from 1. rows[0] points to the header.
for (i = 1; i < grid.rows.length; i++) {
//get the reference of first column
cell = grid.rows[i].cells[0];
//loop according to the number of childNodes in the cell
for (j = 0; j < cell.childNodes.length; j++) {
//if childNode type is CheckBox
if (cell.childNodes[j].type == "checkbox") {
//assign the status of the Select All checkbox to the cell checkbox within the grid
cell.childNodes[j].checked = document.getElementById(id).checked;
}
}
}
}
}
</script>
and handle Rowbound event of gridviews bind call of javascript function as per below
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
//Find the checkbox control in header and add an attribute
((CheckBox)e.Row.FindControl("cbSelectAll")).Attributes.Add("onclick", "javascript:SelectAll('" +
((CheckBox)e.Row.FindControl("cbSelectAll")).ClientID + "'" + ", '1')" );
}
}
protected void GridView2_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
//Find the checkbox control in header and add an attribute
((CheckBox)e.Row.FindControl("cbSelectAll")).Attributes.Add("onclick", "javascript:SelectAll('" +
((CheckBox)e.Row.FindControl("cbSelectAll")).ClientID + "'" + ", '2')" );
}
}
This is how I managed it:
function UnCheckAllContainer(obj) {
var isUnchecked = obj.checked;
if (isUnchecked == false) {
var frm = document.forms[0];
for (i = 0; i < frm.length; i++) {
if (frm.elements[i].id.indexOf('chkSelectAllCheckboxesContainers') != -1
) {
frm.elements[i].checked = false;
}
}
}
}
function CheckAllContainer(chk) {
$('#<%=gdvwContainers.ClientID %>').find("input:checkbox").each(function () {
if (this != chk) {
this.checked = chk.checked;
}
});
}

Making a row editable based on a checkbox in HTML

I have a table in HTML. The contents of this table are dynamically populated. Every row of the table has text boxes and one checkbox. When the page is loaded, all the text boxes in the rows will be in a read-only state.
Now, i want to change the state of the text boxes in a particular row to editable, if the check-box in that row is selected. Also, the text boxes should be made read-only if the check box is de-selected.
How could I accomplish this using Javascript? Please help me.
stating this with plain javascript would be pure pain :)
i suggest using jQuery, eg:
$(':checkbox').click(function() {
var checkbox = $(this);
var row = checkbox.closest('tr');
var inputText = $('input[type=text]', row);
if (checkbox.is(':checked')) {
inputText.attr('readonly', 'readonly');
}
else {
inputText.removeAttr('readonly');
}
});
otherwise
function HandleClickOnCheckbox() {
var checkbox = this;
var row;
var iter = checkbox;
while (!row) {
iter = iter.parent;
if (iter == window) {
break;
}
if (iter.tagName == 'tr') {
row = iter;
break;
}
}
if (!row) {
alert('row not found');
return false;
}
var textBoxes = GetTextBoxes(row);
var method;
if (checkbox.checked) {
var disabledAttribute = document.createAttribute('disabled');
disabledAttribute.nodeValue = 'disabled';
method = function(textBox) {
textBox.setAttributeNode(disabledAttribute);
};
}
else {
method = function(textBox) {
textBox.removeAttribute('disabled', 0);
}
}
for (var i = 0; i < textBoxes.length; i++) {
var textBox = textBoxes[i];
method(textBox);
}
}
function GetTextBoxes(element) {
var textBoxes = new Array();
for (var i = 0; i < element.children.lenght; i++) {
var child = element.children[i];
if (child.tagName == 'input') {
if (child.type == 'text') {
textBoxes.push(child);
}
}
if (child.tagName == 'td') {
var childTextBoxes = GetTextBoxes(child);
if (childTextBoxes.length) {
for (var j = 0; j < childTextBoxes.length; j++) {
var childTextBox = childTextBoxes[j];
textBoxes.push(childTextBox);
}
}
}
}
return textBoxes;
}
this is not tested!
Perhaps, you can start by handling the click event of the checkbox using an if/else statement to check if the checkbox is actually checked. If it is you can use the row within which the checkbox resides to find all the textboxes in the different cells and enable/disable them.
Are you using JQuery or plain Javascript?
If you don't mind using jQuery, you could do:
$('checkbox').click(function() {
if ($(this).attr('checked')) {
$(this).parents('tr').children('input[type="text"]').each().attr('readonly', 'readonly');
} else {
$(this).parents('tr').children('input[type="text"]').each().removeAttr('readonly');
}
})
Or something like that. I'd have to test it to be sure.
Edited to reflect Andreas's comment.
Try this snippet (assumes that the checkbox has a class called "checkbox") if you are using Jquery.
jQuery('tr.checkbox').click(function() {
if (jQuery(this).is(":checked")) {
jQuery('td', this).removeAttr('disabled');
} else {
jQuery('td', this).attr('disabled', '');
}
});`

Categories

Resources