Decide when to load html file - javascript

The problem I am encountering is that I want to be able to view the row variable without the waiting for event click.
Works: JQuery event waiting for click, row is view-able:
$('[data-row]').on('click', function() {
var row = $(this).attr('data-row');
alert(row); //
});
Does not work: This is what I want to work...?:
$('[data-row]').(function() {
var row = $(this).attr('data-row');
alert(row);
});

You are missing each
$('[data-row]').each(function() {
var row = $(this).attr('data-row');
alert(row);
});

Unclear. What does alert($row) have to do with deciding to load an HTML file?
You could use setTimeout function to avoid clicking.

Delete the line 1 and 4 of your 2nd code.
This must be inside of jquery document.ready
Your code must be like this
var row = $(this).attr('data-row');
alert(row);

Related

JQuery: Finding a way to name cloned input fields

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.

Javascript - Listener executing on assignment

So, I'm currently working on a HTML page that displays a table with an editable text box and a delete button for the row for every quote in a list. The list is fetched from a stored file, so I need to dynamically generate this table and its rows every time I fetch it. However, when this code runs, the table generated is empty, because when the listener is added, the delete row function executes and just removes the row right after it's added.
for (var i = 0; i < quotesArray.length; i++) {
//Insert a new row into the table.
var newQuoteRow = quoteList.insertRow(-1);
var cellOne = newQuoteRow.insertCell(0);
var cellTwo = newQuoteRow.insertCell(1);
//Insert editable text boxes for a quote into the row.
var quoteInput = document.createElement('input');
quoteInput.value = quotesArray[i];
quoteInput.className = "quote";
cellOne.appendChild(quoteInput);
//Put a delete button at the end of the row.
var deleteQuoteButton = document.createElement('button');
deleteQuoteButton.innerHTML = "x";
cellTwo.appendChild(deleteQuoteButton);
deleteQuoteButton.addEventListener('click', deleteCurrentQuoteRow(deleteQuoteButton));
}
});
}
function deleteCurrentQuoteRow(buttonToDelete) {
var currentRow = buttonToDelete.parentNode.parentNode; //get the grandparent node, which is the row containing the cell containing the button.
currentRow.parentNode.removeChild(currentRow); //delete the row in the table
}
From what I understand, this problem occurs because the function linked to in the addEventListener method has a parameter, which causes it to execute immediately instead of waiting for a click. However, I can't think of a way to implement this without passing the button being clicked as the parameter, because then I won't know which row to delete. How can I fix this so that the table will actually populate, and the delete button will actually delete a row?
Currently you are invoking the function deleteCurrentQuoteRow and assigning its return value which is undefined as event listener.
Use
deleteQuoteButton.addEventListener('click', function(){
deleteCurrentQuoteRow(this); //Here this refers to element which invoke the event
});
OR, You can modify the function deleteCurrentQuoteRow as
function deleteCurrentQuoteRow() {
var currentRow = this.parentNode.parentNode; //get the grandparent node, which is the row containing the cell containing the button.
currentRow.parentNode.removeChild(currentRow); //delete the row in the table
}
Then you can just pass the function reference as
deleteQuoteButton.addEventListener('click', deleteCurrentQuoteRow);

How can I bind a click event to dynamically created TDs?

I have a function that takes some json data and puts it into a table. I'm trying to bind a click event to certain table elements. In this case the table has two columns 'Drink Name' and 'Drink Type'. I want the two columns to have different events so I'm trying to give them class tags so I can bind the event to a given class.
The lines wrapped in ** are pseudo code for what I'm trying to do. I've tried looking at a bunch of stuff and can't quite figure this out...thanks!!
function totable(data){
var d = document.getElementById("drinkList");
d.setAttribute("class","panel panel-default");
var dd = document.createElement("div");
dd.setAttribute("class","panel-heading");
dd.appendChild(document.createTextNode("Drink list"));
d.appendChild(dd);
var mytable = document.createElement("table");
mytable.setAttribute("class","table");
var thr = document.createElement("tr");
for(var key in data[0]){
var th = document.createElement("th");
th.appendChild(document.createTextNode(key));
thr.appendChild(th);
}
mytable.appendChild(thr);
for(var i=0;i<data.length;i++){
var r = document.createElement("tr");
for(var key in data[i]){
var td = document.createElement("td");
**td.setClassName("drinkEntry");**
td.appendChild(document.createTextNode(data[i][key]));
r.appendChild(td);
}
mytable.appendChild(r);
}
d.appendChild(mytable);
**$("#drinkEntry").on("click", viewDrink);**
}
Replace **td.setClassName("drinkEntry");** with $(td).click(viewDrink);.
you can use method .on() with document to bind the event instead directly to the class (not id) because the instance doesn't exist already
try this:
$(document).on("click",".drinkEntry", function(){
});
Try this
$('body').on('click','#drinkEntry',function(){
//Your Codes
});
To bind event to dynamically created items you must use .on() jQuery function.
In your case it should looks like:
$('#drinkEntry').on("click", function () {
//logic
});
try out
$('body').on('click', 'td.drinkEntry', function() {
alert("td clicked");
});
JsFiddler Demo
you can also read help full aticle for this : Bind events to dynamically created elements using jQuery

Adding a custom attribute in ASP.NET. accessing it in JQuery

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();
});
});
});

Delete current parent node in recursion

I created multiple divs which class="extra". Then I add delete buttons to each div in order to remove each div respectively. So my code is:
var exr = document.getElementsByClassName("extra");
for(var i = 0 ;i<exr.length;i++){
var delbt = document.createElement("button");
delbt.className="floatbutton_3 font_b"
delbt.innerHTML="delete";
exr[i].appendChild(delbt);
delbt.onclick= function(i){ return function(){ exr[i].parentNode.removeChild(exr[i]) } }(i);
}
The problem is, the button can't removethe button it should remove. It seems that after last delete, the index is changed. How to avoid this from happening?
Thanks!
Use this within the onclick function to reference the button that was clicked — so by replacing excr[i] with this.parentNode, your code should execute as intended.
Do this...
var exr = document.getElementsByClassName("extra");
for(var i = 0 ;i<inserter.length;i++){
var delbt = document.createElement("button");
delbt.className="floatbutton_3 font_b"
delbt.innerHTML="delete";
exr[i].appendChild(delbt);
delbt.index = i;
delbt.onclick= function(i){ var me = this; return function(){ exr[me.index].parentNode.removeChild(exr[i]) } }(i);
}
Since getElementsByClassName() returns a live set, you could make a shallow copy first:
var exr = [].slice.call(document.getElementsByClassName("extra"), 0);
You could use currentTarget on the click event.
This will only remove the parent div of the button clicked.
var exr = document.getElementsByClassName("extra");
for(var i = 0 ;i<exr.length;i++){
var delbt = document.createElement("button");
delbt.className="floatbutton_3 font_b"
delbt.innerHTML="delete";
exr[i].appendChild(delbt);
delbt.onclick= function( event ){
event.currentTarget.parentElement.remove();
}
}
The code looks like it should work, but only as long as you don't add or remove elements. And that's what you are doing.
There is a simpler and more reliable solution: You can use this inside the event handler to refer to the current element.
delbt.onclick = function() {
var div = this.parentNode; // you want to remove the div, not the button
div.parentNode.removeChild(div);
};
I recommend to read the excellent articles about event handling on quirksmode.org, especially about traditional event handling (since that's what you are using).
getElementsByClassName() returns an HTMLCollection. This is a live list that changes when the underlying structure changes. So even if you don't activly delete the elements from the list, they still will be removed from it automatically when you remove the corresponding HTML Element.
By passing i to the anonymous function, you kind of fixed the index. So whenever you click on the third delete button it will try to delete the third element in the list. But if you have already deleted the first and the second element, the list will be modified too. So your third button will be represented by the first item in your list but it will try to find the third one.
To avoid this problem you can pass the complete element to the anonymous function and not just the index:
for(var i = 0 ;i<exr.length;i++){
var delbt = document.createElement("button");
delbt.className="floatbutton_3 font_b"
delbt.innerHTML="delete";
exr[i].appendChild(delbt);
delbt.onclick = function(el){ return function(){ el.parentNode.removeChild(el) } }(exr[i]);
}
I'll add a jQuery solution:
$('.extra').append(function() {
return $('<button />', {'class':'floatbutton_3 font_b', html:'delete'});
});
$('.floatbutton_3').on('click', function() {
$(this).closest('div').remove();
});
FIDDLE

Categories