I have a table that is created in ASP.NET C# code behind. The table has several levels of groupings, and when I create the rows for the outer most grouping, I add an custom attribute as follows:
foreach (Table2Row row in Table2Data)
{
// skipping a bunch of irrelevent stuff
...
tr_group.Attributes.Add("RowsToToggle", String.Format(".InnerRowGroupId_{0}", row.GroupHeaderId));
...
}
The attribute is the CSS class name of the inner level rows that I would like to toggle. When the user clicks on the outer level row, I would like to call JQuery Toggle function for all inner level rows that match the custom attribute.
To achieve that effect, I have attached an onclick event to the header rows with the following script in the aspx file:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
}
});
function ToggleOnRowClick(row) {
var r = $('#' + row.id);
var innerRows = r.attr('RowsToToggle');
$(innerRows ).toggle();
}
So, clicking anywhere on the header row should call the function ToggleOnRowClick, which should then toggle the set of rows below it via the custom attribute RowsToToggle.
When I set a (FireBug) break point in the ToggleOnRow function, the variable r appears to be pointing to the correct object. However, innerRows is not getting set but instead remains null. So am I setting the custom attribute incorrectly in ASP.NET or reading in incorrectly in JQuery?
You did not post the code to generate inner level rows, I am assuming you sat proper classes to them.
There are few issues with the jquery you posted. This line wouldn't work:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
You don't have any groupRows property defined for table object.
We don't care about table row anymore, we care about groupRows[i] and want to pass it to ToggleOnRowClick function.
This line in next function is also wrong:var r = $('#' + row.id);
Solution: Change your script to this:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
groupRows[i].onclick = function () { ToggleOnRowClick(this); }
}
});
function ToggleOnRowClick(row) {
//var r = $('#' + row.id);
var innerRows = $(row).attr('RowsToToggle');
$("." + innerRows).toggle();
}
I have tested the code with dummy data. So if you have any issue, PM me.
This line is your culprit:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i])
By the time the event handler runs, table.rows might still exist, but i will be set to groupRows.length+1, which is out of bounds for the array. The handler will get called with an argument of undefined.
Remember, Javascript is an interpreted language! The expression "table.rows[i]" will get interpeted when the handler runs. It will use the last value of i (which will still be set to the value that caused your for loop to end, groupRows.length+1).
Just use
table.groupRows[i].onclick = function () { ToggleOnRowClick(this) }
So, First you shouldn't use custom attributes... they are a sin!
Please use data attributes instead, so that is what I'm going to use in the code, should be an easy fix regardless.
If this doesn't work then I'd be very very interested in seeing a dumbed down HTML snippet of the actual output.
$(document).ready(function () {
$('#MYTABLE').on('click', '.Table2GroupHeader', function() {
var attr_if_you_insist_on_sinning = $(this).attr("RowsToToggle");
var data_if_you_like_not_sinning = $(this).data("RowsToToggle");
//if the row is like <tr data-RowsToToggle=".BLAH" or th etc
//asumming you set the attribute to .BLAH then:
var rows_to_toggle = $(data_if_you_like_not_sinning);
rows_to_toggle.toggle();
//assuming you set it to BLAH then:
var rows_to_toggle = $("."+ data_if_you_like_not_sinning);
rows_to_toggle.toggle();
});
});
$(document).ready(function () {
$('#<%= Table2MainTable.ClientID %> .Table2GroupHeader').each(function(){
$(this).click(function(){
$(this).toggle();
});
});
});
Related
I'm not the best at using jQuery, but I do require it to be able to make my website user-friendly.
I have several tables involved in my website, and for each the user should be able to add/delete rows. I created a jquery function, with help from stackoverflow, and it successfully added/deleted rows. Now the only problem with this is the names for those input fields is slightly messed up. I would like each input field to be an array: so like name[0] for the first row, name[1] for the second row, etc. I have a bunch of tables all with different inputs, so how would I make jQuery adjust the names accordingly?
My function, doesn't work completely, but I do not know how to go about changing it.
My Jquery function looks like:
$(document).ready(function() {
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
clone.find("select").val('');
clone.find('input').each(function(i) {
$(this).attr('name', $(this).attr('name') + i);
});
clone.find('select').each(function(i) {
$(this).attr('name', $(this).attr('name') + i);
});
tr.after(clone);
});
$("body").on('click', '.delete_row', function() {
var rowCount = $(this).closest('.row').prev('table').find('tr.ia_table').length;
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
if (rowCount > 1) {
tr.remove();
};
});
});
I also created a jsFiddle here: https://jsfiddle.net/tareenmj/err73gLL/.
Any help is greatly appreciated.
UPDATE - Partial Working Solution
After help from a lot of users, I was able to create a function which does this:
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
clone.find("select").val('');
clone.find('input').each(function() {
var msg=$(this).attr('name');
var x=parseInt(msg.split('[').pop().split(']').shift());
var test=msg.substr(0,msg.indexOf('['))+"[";
x++;
x=x.toString();
test=test+x+"]";
$(this).attr('name', test);
});
clone.find('select').each(function() {
var msg1=$(this).attr('name');
var x1=parseInt(msg1.split('[').pop().split(']').shift());
var test1=msg1.substr(0,msg1.indexOf('['))+"[";
x1++;
x1=x1.toString();
test1=test1+x1+"]";
$(this).attr('name', test1);
});
tr.after(clone);
});
A working jsFiddle is here: https://jsfiddle.net/tareenmj/amojyjjn/2/
The only problem is that if I do not select any of the options in the select inputs, it doesn't provide me with a value of null, whereas it should. Any tips on fixing this issue?
I think I understand your problem. See if this fiddle works for you...
This is what I did, inside each of the clone.find() functions, I added the following logic...
clone.find('input').each(function(i) {
// extract the number part of the name
number = parseInt($(this).attr('name').substr($(this).attr('name').indexOf("_") + 1));
// increment the number
number += 1;
// extract the name itself (without the row index)
name = $(this).attr('name').substr(0, $(this).attr('name').indexOf('_'));
// add the row index to the string
$(this).attr('name', name + "_" + number);
});
In essence, I separate the name into 2 parts based on the _, the string and the row index. I increment the row index every time the add_row is called.
So each row will have something like the following structure when a row is added...
// row 1
sectionTB1_1
presentationTB1_1
percentageTB1_1
courseTB1_1
sessionTB1_1
reqElecTB1_1
// row 2
sectionTB1_2
presentationTB1_2
percentageTB1_2
courseTB1_2
sessionTB1_2
reqElecTB1_2
// etc.
Let me know if this is what you were looking for.
Full Working Solution for Anyone Who needs it
So after doing loads and loads of research, I found a very simple way on how to do this. Instead of manually adjusting the name of the array, I realised that the clone method will do it automatically for you if you supply an array as the name. So something like name="name[]" will end up working. The brackets without any text has to be there. Explanation can't possible describe the code fully, so here is the JQuery code required for this behaviour to work:
$(document).ready(function() {
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
tr.after(clone);
});
$("body").on('click', '.delete_row', function() {
var rowCount =
$(this).closest('.row').prev('table').find('tr.ia_table').length;
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
if (rowCount > 1) {
tr.remove();
};
});
});
A fully working JSfiddle is provided here: https://jsfiddle.net/tareenmj/amojyjjn/5/
Just a tip, that you have to be remove the disabled select since this will not pass a value of null.
I have created javascript in which data is fetched for dropped element and are created. The data is fetched from database using json encoding. I have assigned id to the elements but the click event for every element is not working. only the last elements id is obtained and clicked is performed on that id.
JS :
$(document).ready(function () {
var i,j=0;
var x1,x2,y1,y2;
var sf=pf;
sf=Math.round(sf);
var tmp;
var y=null;
var idiv=[];
var fty=ft;
var fd=fid;
var fetch=data;
var x = null;
var count=fetch['count'];
var i=count+1;
//document.write(count);
var rai=[];
//rai[0]='hello';
//document.write(rai[0]);
var ww=[];
var hh=[];
var xx=[];
var yy=[];
var room=[];
var roomt=[];
for(j=0;j<=count;j++)
{
rai[j]=fetch['room_id'+j];
//document.write(rai[j]);
ww[j]=fetch['width'+j];
//document.write(ww[j]);
hh[j]=fetch['height'+j];
xx[j]=fetch['x'+j];
yy[j]=fetch['y'+j];
room[j]=fetch['room'+j];
roomt[j]=fetch['roomt'+j];
//document.write(room[j]);
// alert("data"+rai+" "+ww+" "+hh+" "+xx+" "+yy);
idiv[j]=document.createElement('img')
$('#droppable').append(idiv[j]);
idiv[j].style.position="absolute";
idiv[j].style.left=(xx[j]*sf)+'px';
idiv[j].style.top=(yy[j]*sf)+'px';
idiv[j].style.width=(ww[j]*sf)+'px';
idiv[j].style.height=(hh[j]*sf)+'px';
idiv[j].style.border=1+'px';
idiv[j].id=room[j];
//y=idiv[j].attr('idd',rai[j]);
if(roomt[j]=='garden')
{
idiv[j].src="images/download.jpg";
}
else
{
idiv[j].src="images/ac.png"
}
$(idiv[j]).draggable();
//alert(y);
//y=idiv[j].id;
// alert(y);
//document.write("data"+rai[j]+" "+(ww[j]*sf)+" "+(hh[j]*sf)+" "+(xx[j]*sf)+" "+(yy[j]*sf) + room[j]);
}
//$(this).bind("click",'idiv',function(){
// alert("hello"+idiv.id);
//window.location.href="tables.php?room_id="+y;
// });
});
can anyone give idea how to bind click on each fetched element.
Ty this : add class to the element created and write a click event handler for all element having that class. See below
Add below html in Loop where you are creating idiv[j] -
idiv[j].className = "clickable";
Now write a click event handler using .on()
$(document).ready(function () {
...... your code start here
......
//loop
for(j=0;j<=count;j++)
{
...
...
}
//loop ends
... more code
....your code end here
$(document).on("click",".clickable", function(){
alert(this.id);
});
});
NOTE: Don't use bind because it is deprecated now after jQuery version 1.5
I've been trying to find a good match to my question, but nothing really concrete. I'm still learning and don't know exactly what I'm missing.
So my code can be found here: Fiddle
This is a simplified version of what I'm working with. In the final version, I will upload a csv file to the html table you see there (id="dvCSV"). Upon uploading, the table will look like it is shown (with added dropdowns and a column of checkboxes). The checkboxes come "pre-chcecked" when I generate them but what I want is the user to be able to turn "off" the rows that I do not want to calculate on.
I'll run you through the process:
This function reads the columns that the user designates. I don't know which column they will upload the data into.
function CheckLocations() {
//Checks the uploaded data for the locations of the Lat/Lon Data based on user dropdowns
colLocs[0] = ($('#Value_0 :selected').text());
colLocs[1] = ($('#Value_1 :selected').text());
colLocs[2] = ($('#Value_2 :selected').text());
colLocs[3] = ($('#Value_3 :selected').text());
LatColumn = colLocs.indexOf("Lat");
LongColumn = colLocs.indexOf("Long");
}
function AllTheSame(array) { //if they do not designate the checkboxes, I prompt them to
var first = array[0];
return array.every(function (element) {
return element === first;
});
}
This function takes all of the data in the designated columns and places them into an array for calculation.
function data2Array() {
//gets the lat and long data from the assigned columns and transfers them to an array for calculation
$("#dvCSV tr td:nth-child(" + (LatColumn + 1) + ")").each(function () {
var tdNode = $("<td/>");
tdNode.html(this.innerHTML);
LatData.push(tdNode.text());
});
LatData.splice(0, 2);
LatData.unshift(1, 1);
$("#dvCSV tr td:nth-child(" + (LongColumn + 1) + ")").each(function () {
var tdNode = $("<td/>");
tdNode.html(this.innerHTML);
LongData.push(tdNode.text());
});
LongData.splice(0, 2); //these two lines remove the first two items then replace them with 0
LongData.unshift(1, 1);
}
The first of these functions removes the checkbox column after calculations are done then new calculated columns are appended at the end. The second one was my attempt to read the checkboxes into an array. Ideally I'd want an array of values true or false, then do the calculations and return the calculated values back to the dvCSV table. For the td's where no calculation was performed, the cell would be empty.
function removeChecks() {
$("#dvCSV th:last-child, #dvCSV td:last-child").remove();
}
function makeCheckArray() {
var searchIDs = $("#dvCSV tbody td:last() input:checkbox:checked").map(function () {
return $(this).val();
}).get();
alert(searchIDs);
}
Hopefully I made the problem clear. Any help would be appreciated.
Pass a class when your table is generated into the tr element. Then create an on change method for your checkboxes. Read more here: http://api.jquery.com/on/
Also if you cannot get the inserted rows id's from your table then start a counter outside of your js like this
counter = 0;
Then inside of your loop add counter++
SO..
<tr class="row-1">
<td>
</td>
</tr>
Then add this snippet outside all of your other JS
$( "tr" ).on( "change", function() {
//do something
$(this+'.row-'+(counter)).hide();
});
This should get you headed in the right direction.
What I am trying to do is to call a function every time a person scrolls that checks the current class of container and adds +1 to the current value of the current data attribute and then toggles the class relative to the data attribute it is currently changing the class on scroll but giving a "NaN. I am already running this function on click and it works fine.
here is a fiddle.
http://jsfiddle.net/kaL63/1/
This is my function on scroll
var timeout;
$(window).scroll(function() {
if(typeof timeout == "number") {
window.clearTimeout(timeout);
delete timeout;
}
timeout = window.setTimeout( check, 100);
});
My html Looks like this
<div class="container year-1987" data-year-index="1987">
Some Content
</div>
the function I am calling right now that I think should work..
function check(){
var
animationHolder = $('.container'),
currentClass = animationHolder.attr("class").match(/year[\w-]*\b/);
var goToYear = $('.container').data('year-index');
var goToYear2 = parseInt(goToYear,1000) + 1;
animationHolder.toggleClass(currentClass + ' year-' + goToYear2);
animationHolder.attr('data-year-index', goToYear2);
}
My working code on click
$("a").click(function (e) {
e.preventDefault();
var
animationHolder = $('.container'),
currentClass = animationHolder.attr("class").match(/year[\w-]*\b/);
var goToYear = $(this).data('year-index');
animationHolder.toggleClass(currentClass + ' year-' + goToYear);
animationHolder.attr('data-year-index', goToYear);
I rewrote your check method:
function check() {
var $container = $('.container'),
currentYear = $container.data('m-index'),
nextYear = 1 + currentYear;
$container.removeClass('m-' + currentYear).addClass('m-' + nextYear);
$container.data('m-index', nextYear);
}
I made the following changes:
There is no need for the regular expression since we can generate the class name ourselves.
I am not sure why you were originally using two separate data-attributes (m-index and year-index), but I switched them to both match. If you need both of them, some more logic is needed to use year-index after the initial call.
I am now updating m-index via .data() rather than setting a data attribute.
This method seemed to work fine for me.
I been trying to figure this out, but I haven't yet.
I am building column in html of anchor tags and I would like to know the id of the one that has the mouse over it.
It should be simple, but seems like I hit a wall and I can't see how to solve this.
The problem I have is that the id that is display on the console is all the time the last id of the array. And instead of that I want to the id of the specific anchor.
Any suggestions are really welcome.
Here is my code:
//Anchor builder
var numberOf = flatParamDateArray.length;
for (i = 0; i < numberOf; i++) {
var param2Slider = document.createElement("a");
param2Slider.id = 'sliderAnchor' + i;
sliderAnchorId = param2Slider.id;
param2Slider.name = 'param2Slider';
param2Slider.className = 'nav2Slider a';
document.getElementById('nav2Slider').appendChild(param2Slider);
$('.nav2Slider a').onmouseover = function () {
console.log('flatParamDateArray index: ' + param2Slider.id);
}
}
1. Move this out, and after the for-loop:
$('.nav2Slider a').onmouseover = function () {
console.log('flatParamDateArray index: '+param2Slider.id);
}
2. Change onmouseover() to mouseover():
$('.nav2Slider a').mouseover(function() {
console.log('flatParamDateArray index: '+param2Slider.id);
});
3. To get the ID, this is the code you need:
console.log('flatParamDateArray index: '+ $(this).prop('id'));
Bonus:
Since you are dynamically adding links, you should use the .on() function, to reduce the number of event handlers to one (as opposed to one per element):
$('.nav2Slider').on('mouseover', 'a', function() {
console.log('flatParamDateArray index: '+ $(this).prop('id'));
});
Your variable param2Slider is global and the for loop changes the value on every loop. This means that after the loop is finished param2Slider just contains the last value.
Try this:
$('.nav2Slider a').on('onmouseover', function () {
console.log('flatParamDateArray index: ' + $(this).attr('id'));
});
Edit: onmouseover... & of course you should move this snippet out of the loop