I have a table with the following 3 columns where each row is dynamically appended.
Condition : Is a mere WHERE clause conditional statement string
Remove : A button that removes that row (Removes a condition)
Join with : A drop down combo
When the user clicks on the Remove button, that particular row needs to be removed.
I have written the code for this, but nothing happens and am not getting any errors on the console as well.
Code in Context
$("#whereConditionTable").append(
"<tr>"+
"<td>"+conditionString+"</td>"+
"<td><button id='removeConditionBtn' name='removeConditionBtn' class='btn btn-default'><img src='resources/images/removeWhereCondition.png' width='25px' height='25px'></button>"+
"<td>"+
"<select id='where-Condition-Join-Combo' name='where-Condition-Join-Combo' class='form-control'>"+
"<option value='1'>Join using</option>"+
"<option value='2'>AND</option>"+
"<option value='3'>OR</option>"+
"</select>"+
"</td>"+
"</tr>"
);
document.getElementById("removeConditionBtn").addEventListener("click", function() {
removeWhereCondition();
}, false);
removeWhereCondition()
function removeWhereCondition()
{
$(this).closest("tr").remove();
}
Any suggestions in this regard will be highly appreciated.
function deleteRow(r) {
var i = r.parentNode.parentNode.rowIndex;
document.getElementById("myTable").deleteRow(i);
}
<!DOCTYPE html>
<html>
<head>
<style>
table, td {
border: 1px solid black;
}
</style>
</head>
<body>
<table id="myTable">
<tr>
<td>Row 1</td>
<td><input type="button" value="Delete" onclick="deleteRow(this)"></td>
</tr>
<tr>
<td>Row 2</td>
<td><input type="button" value="Delete" onclick="deleteRow(this)"></td>
</tr>
<tr>
<td>Row 3</td>
<td><input type="button" value="Delete" onclick="deleteRow(this)"></td>
</tr>
</table>
</body>
</html>
Few things to fix:
You're combining jQuery and vanilla JavaScript (getElementById), so I've tidied some of that up and rewritten it as jQuery.
HTML documents can not have repeating IDs. If your append ran more than once, it would create additional #removeConditionBtn and #where-Condition-Join-Combo elements, and JS would cease to work. I've changed these to classes, which are reusable.
Your addEventListener to bind a click event was only going to bind to (one) #removeConditionBtn element that existed when the code was first run. If the table contents changed to include additional buttons, your binding wouldn't have updated (even if you were using class rather than ID). I've rewritten this using jQuery on on the table itself, so the click event will still fire even as the contents of the table change.
Working demonstration below:
var conditionString = "text";
$("#whereConditionTable").append(
"<tr>" +
"<td>" + conditionString + "</td>" +
"<td><button class='removeConditionBtn' name='removeConditionBtn' class='btn btn-default'><img src='resources/images/removeWhereCondition.png' alt='Remove' width='25px' height='25px'></button>" +
"<td>" +
"<select class='where-Condition-Join-Combo' name='where-Condition-Join-Combo' class='form-control'>" +
"<option value='1'>Join using</option>" +
"<option value='2'>AND</option>" +
"<option value='3'>OR</option>" +
"</select>" +
"</td>" +
"</tr>"
);
$("#whereConditionTable").on("click", ".removeConditionBtn", function() {
$(this).closest("tr").remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="whereConditionTable"></table>
Apparently you are using jQuery. You could try:
$('#removeConditionButton').on('click', function(element) {
$(element).closest('tr').remove();
})
By the way, it seem you are using id-property incorrectly. Id's should be unique and each page can have only one element with same id. In this case, you should use class instead of id.
Related
I have multiple toggle switches on my page. They are from bootstrap.
Everything works as expected, however, I have come across an error within the javascript console. Or warning should I say.
When I have only one toggle on the page and I click it it will print one line in the console, which is as expected. When I dynamically add another toggle, using the script below, when I click on the last added toggle it will print again only one line, but every other will print multiple lines.
I.e. when I have 5 toggles and click on the last one, it will print one line in the console.
When I click on 4th it will print two lines and so on. When I click on the 1st it will print 5 lines.
If I have multiple toggles set from beginning without adding them dynamically it works fine.
Any ideas?
<script>
$(window).ready(function() {
$("[data-toggle='toggle']").bootstrapToggle({
on: 'On',
off: 'Off',
size: 'small'
});
$('#addRow').on('click', function(event) {
event.preventDefault();
var rowID =+ $('table tr:last').attr('id')+1;
$('#users').find('tbody').append([
"<tr class='userRow' id='"+rowID+"'>",
"<td>"+rowID+"</td>",
"<td><input type='text' class='form-control'></td>",
"<td><input type='text' class='form-control'></td>",
"<td><input type='text' class='form-control'></td>",
"<td><input type='checkbox' class='toggle-voicemail' data-toggle='toggle'></td>",
"<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>",
"<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>",
"<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>",
"<td><a class='deleteRow btn btn-danger' value='"+rowID+"'>Delete</a></td>",
"</tr>"
].join(''));
$("[data-toggle='toggle']").bootstrapToggle('destroy');
$("[data-toggle='toggle']").bootstrapToggle({ size: 'small' });
$('.toggle-voicemail').on('change', function(event) {
event.preventDefault();
var id = $(this).parents('tr').attr('id');
console.log("Voicemail for userID:"+id);
});
});
$('.toggle-voicemail').on('change', function(event) {
event.preventDefault();
var id = $(this).parents('tr').attr('id');
console.log("Voicemail for userID:"+id);
});
$('#users').on('click', 'a.deleteRow', function(event) {
event.preventDefault();
//var id = $(this).find('a').attr('value');
$(this).parents('tr').remove();
});
});
</script>
HTML
<div class="box box-primary" id="usersDetails" style="">
<div class="box-header with-border">
<h3 class="box-title">Users</h3>
</div>
<div class="box-body">
<table class="table table-condensed text-center" id="users">
<thead>
<tr>
<th>ID</th>
<th width="300">Username</th>
<th>Phone</th>
<th></th>
<th>Voicemail</th>
<th width="50">RG 1</th>
<th width="50">RG 2</th>
<th width="50">RG 3</th>
<th width="100"></th>
</tr>
</thead>
<tbody>
<tr class='userRow' id='1'>
<td>1</td>
<td><input type='text' class='form-control'></td>
<td><input type='text' class='form-control'></td>
<td><input type='text' class='form-control'></td>
<td><input type='checkbox' class='toggle-voicemail' data-toggle='toggle'></td>
<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>
<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>
<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>
<td></td>
</tr>
</tbody>
</table>
<input type="button" id="addRow" value="Add another user" class="btn btn-success">
</div>
</div>
You're binding this event inside of your "add row" functionality:
$('.toggle-voicemail').on('change', function(event) {
Which means every time you add a row, you're adding another binding to every matching .toggle-voicemail element on the page, including the ones which already have that event binding.
Instead of re-binding when adding a row, create a delegated binding once when the page loads that handles dynamically added elements. Basically, do this outside of the "add row" functionality:
$(document).on('change', '.toggle-voicemail', function(event) {
event.preventDefault();
var id = $(this).parents('tr').attr('id');
console.log("Voicemail for userID:"+id);
});
You are adding the event function multiple times. The solution to this is to make your function non-anonymous:
var myFunc = function(event) {
event.preventDefault();
//var id = $(this).find('a').attr('value');
$(this).parents('tr').remove();
}
And then call .off to before calling .on to prevent multiple listeners
$('.toggle-voicemail').off('change', myFunc);
$('.toggle-voicemail').on('change', myFunc);
That is caused because every time you add a new toggle, you reattach the event listener to all of the existing toggles and not only for the newly created one.
You can make a let variable to store the newly generated toggle, and then instead of doing
$('.toggle-voicemail').on('change', function(event) { ...
you can do:
$elem.on('change', function(event) { ...
It looks like your problem is that you are just adding event handlers and never removing them. So you need to only add an event handler to the newly-added element, or remove all event handlers (using .off()) ,and then adding them again.
I would opt for the former approach (adding an event listener to the new element only).
The best way to do this is the create the elements, then add all your event handlers (and whatever else you want to change about the element). THEN append it to the DOM.
so:
// create the new row.
// reusing your `.join()` technique for ease of demo here.
var newRow = $("<tr class='userRow' id='"+rowID+"'>",
"<td>"+rowID+"</td>",
"<td><input type='text' class='form-control'></td>",
"<td><input type='text' class='form-control'></td>",
"<td><input type='text' class='form-control'></td>",
"<td><input type='checkbox' class='toggle-voicemail' data-toggle='toggle'></td>",
"<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>",
"<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>",
"<td><input type='checkbox' data-toggle='toggle' class='toggle-ringgroup'></td>",
"<td><a class='deleteRow btn btn-danger' value='"+rowID+"'>Delete</a></td>",
"</tr>".join(''));
// toggle-ify the element.
newRow.find("[data-toggle='toggle']").bootstrapToggle({ size: 'small' });
newRow.find('.toggle-voicemail').on('change', function(event) {
event.preventDefault();
var id = $(this).parents('tr').attr('id');
console.log("Voicemail for userID:"+id);
});
newRow.find('a.deleteRow').on('click', function(event) {
event.preventDefault();
//var id = $(this).find('a').attr('value');
$(this).parents('tr').remove();
});
// append to table.
$('#users').find('tbody').append(newRow);
I am facing an issue while using Jquery and PHP in same files as to sort the table. I searched quite a while found that a solution has been presented using JQuery UI to save the sorted list and then send it to php form using ajax, however due to project constraints I can't include JQuery UI as we are already using Bootstrap. So I am limited to use vanilla javascript or jquery 1.7 . Here is a snippet of my code
echo '<tr>';
echo '<td><a class="icon-pencil icon-gray" href="unit_custom_fields.php?szAction=Edit&szUnitCustomFieldId=' . $pUnitCustomField->m_uId . '" title="Edit"></a></td>';
echo '<td>' . $pUnitCustomField->m_szFieldPlaceholder . '</td>';
echo '<td>' . $pUnitCustomField->m_szFieldDescription . '</td>';
echo '<td>' . ($pUnitCustomField->m_bShowInUnitList == 1 ? "yes" : "no") . '</td>';
echo '<td>' . ($pUnitCustomField->m_bIsPasswordField == 1 ? "yes" : "no") . '</td>';
echo '<td><a class="icon-arrow-down moveDown" href="javascript:;" onclick="sortUnitCustomFields()"></a><a class="icon-arrow-up moveUp" href="javascript:;" onclick="sortUnitCustomFields()"></a>';
echo '</tr>';
Here is how the user can sort the table with up and down arrows using Jquery
global $g_szUnitCustomFieldPriority;
$g_szUnitCustomFieldPriority .= <<< END
<script type="text/javascript">
function sortUnitCustomFields() {
$('.moveUp').live('click', function(){
var row = $(this).closest('tr');
var prev = row.prev();
if (prev.length == 1) {
row.detach();
prev.before(row);
}
});
$('.moveDown').live('click', function(){
var row = $(this).closest('tr');
var next = row.next('tr');
if (next.length == 1) {
row.detach();
next.after(row);
}
});
}
</script>
END;
In order to save changes to the form I am using POST methods when the save button is clicked like
if ($szAction == 'Save') {
$pUnitCustomField->m_szFieldPlaceholder = $_POST['szFieldPlaceholder'];
}
So How can I save the sort order in the m_szFieldPlaceholder without using Jquery UI.
If the table is inside the form tag change this line and pass the placeholder through a hidden form input like:
echo '<td>' . $pUnitCustomField->m_szFieldPlaceholder . '<input type="hidden" name="szFieldPlaceholder[]" value="'.$pUnitCustomField->m_uId.'" /></td>';
Then retrieve the data like:
if ($szAction == 'Save') {
$flip = array_flip($_POST['szFieldPlaceholder']);
$order = $flip[$pUnitCustomField->m_uId];
$pUnitCustomField->m_szFieldPlaceholder = $order;
}
jQueryUI should not be needed to save your information back to the PHP-side database.
What you need to do is to:
get an updated ordering of the table rows and store in an array or some such; then
send that order back to the PHP side via ajax. (Ajax is the "system" by which javascript communicates with php).
On the PHP side, you receive the table order and
store that order into a table. THEN
you modify your normal page build to retrieve the row order data from teh database (need to also handle if it does not exist - i.e. user has not re-ordered the rows), and
then re-order the table into that order before handing control over to the user.
jQueryUI would not be needed for that process (nor can I imagine how it could be used to do the front-end/back-end communications. That is not what jQueryUI is for.)
If you would like to use jQuery UI Sortable, you can do so with jQuery v1.7. Simply use jQuery UI 1.11.4. Here is an example:
$(function() {
$("table tbody").sortable({
items: "> tr",
handle: ".sort-handle"
});
$("table .ui-icon-pencil").on("click", function() {
var id = $(this).parents("tr").data("id");
var url = "unit_custom_fields.php?szAction=Edit&szUnitCustomFieldId=" + id;
console.log("Edit: " + url);
//window.location.href = url;
});
$("button").click(function() {
var data = $("table tbody").sortable("serialize");
console.log("Sort Data: " + data);
});
});
<link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<table>
<tr id="m_uId-1" data-id="1">
<td>
<span class="ui-icon ui-icon-pencil"></span>
</td>
<td>FieldPlaceHolder 1</td>
<td>ShowInUnitList 1</td>
<td>IsPasswordField 1</td>
<td>
<span class="ui-icon ui-icon-grip-dotted-vertical sort-handle"></span>
</td>
</tr>
<tr id="m_uId-2" data-id="2">
<td>
<span class="ui-icon ui-icon-pencil"></span>
</td>
<td>FieldPlaceHolder 2</td>
<td>ShowInUnitList 2</td>
<td>IsPasswordField 2</td>
<td>
<span class="ui-icon ui-icon-grip-dotted-vertical sort-handle"></span>
</tr>
<tr id="m_uId-3" data-id="3">
<td>
<span class="ui-icon ui-icon-pencil"></span>
</td>
<td>FieldPlaceHolder 3</td>
<td>ShowInUnitList 3</td>
<td>IsPasswordField 3</td>
<td>
<span class="ui-icon ui-icon-grip-dotted-vertical sort-handle"></span>
</tr>
</table>
<button>Save</button>
Now you can make use of Sortable and it's methods, like "serialize" and "toArray" as you desire.
Hope that helps.
I am trying to bind column dynamically in a table using jQuery .but click event is not working while trying to click 'btnASizeR' and 'btnWdDelete' button event is not working .Any idea would be appreciated.
$(function() {
var i = 0;
$('#btnASizeR').click(function() {
/* To check the count of already exist tr in WireDimTbl and then assigning the i value for controlids*/
var i = $("#WireDimTbl tbody>tr").length + 1;
/* To check the count of already exist tr in WireDimTbl and then assigning the i value for controlids*/
var sizerangeMin = "<input type='text' ID='SizeMin" + i + "' name='SizeMin' value='2.00' />";
var sizerangeMax = "<input type='text' ID='SizeMax" + i + "' name='SizeMax' value='3.00' />";
var ToleranceMin = "<input type='text' ID='TolMin" + i + "' name='TolMin' value='1' />";
var ToleranceMax = "<input type='text' ID='TolMax" + i + "' name='TolMax' value='1' />";
var markup = "<tr><td>" + sizerangeMin + "</td><td>" + sizerangeMax + "</td><td>" + ToleranceMin + "</td><td>" + ToleranceMax + "</td></tr>";
$("#WireDimTbl tbody").append(markup);
});
$('#btnWdDelete').click(function() {
$("#WireDimTbl tbody>tr:last").remove();
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<tr>
<td class='text-left'><strong>Wire Dimensions</strong></td>
</tr>
<tr>
<td class='text-left'><strong>Standard Sizes & Tolerances</strong></td>
<td>
<input type="button" id="btnASizeR" value="AddSizeRange" />
<input type="button" id="btnWdDelete" value="Delete" />
<table id="WireDimTbl" class="table table-bordered">
<thead>
<tr>
<th class="text-center">Size Range Min (mm)</th>
<th class="text-center">Size Range Max (mm)</th>
<th class="text-center">Tolerance (-)mm</th>
<th class="text-center">Tolerance (+) mm</th>
</tr>
</thead>
<tbody></tbody>
</table>
</td>
</tr>
You mentioned that you are loading the table dynamically. Do you mean that when the page first loads the table is missing and its added later?
If that is the case, are you sure the code is called that binds the click events? The above example binds the events on page_load however, if the buttons are not yet available on the page it won't be able to bind it. JQuery will not automatically bind future elements.
Try settings a console.log($('#btnASizeR')); before binding the click event to make sure that JQuery can actually find the button.
I have a html table that I'm running at the server level. However, I'm having trouble accessing the data that it is being populated with.
I'm populating the table using javascript but I need to access the data using vb.net.
I'm using jquery to get the information to the page by using the .html method.
Here is my javascript,
function ShowProj(strId, qno,ar) {
$('#hiddenQno').val(qno);
$('#qnoLbl').val(qno);
var output = '';
output = "<tr><th>Product</th>";
output += "<th>Bond</th>";
output += "<th>Cut</th>";
output += "<th>Pack</th>";
output += "<th>Delivery date</th></tr>";
for (i = 0; i < ar.length; i++) {
output += "<tr>";
output += "<td style='width: 40%;'>" + ar[i][0] + "</td>";
output += "<td style='width: 10%; text-align: center;'><input type='checkbox' " + (ar[i][1] == 1 ? 'checked' : '') + " /></td>";
output += "<td style='width: 10%; text-align: center;'><input type='checkbox' " + (ar[i][2] == 1 ? 'checked' : '') + " /></td>";
output += "<td style='width: 10%; text-align: center;'><input type='checkbox' " + (ar[i][3] == 1 ? 'checked' : '') + " /></td>";
output += "<td style='width: 30%;'><input type='text' value='" + ar[i][4] + "'/><input type='hidden' value='" + ar[i][5] + "' /></td>";
output += "</tr>"
}
$('#projGrid').html(output);
}
I am passing the information from vb.net using an `ArrayList.
Here is my html,
<div class="modalPopup" id="projPopup" style="width: 40%;">
<table style="width:100%;">
<tr>
<td colspan="2">
<table id="projGrid" runat="server" style="width: 100%;border: 1px solid black; font-size: 16;">
</table>
</td>
</tr>
<tr>
<td>
</td>
<td>
</td>
</tr>
<tr>
<td>
<asp:Button ID="projOk" runat="server" Text="Update" /></td>
<td>
<asp:Button ID="projCncl" runat="server" Text="Cancel" />
</td>
</tr>
</table>
</div>
And here is my vb.net.
For Each row As HtmlTableRow In projGrid.Rows
'Dim chkBond As HtmlInputCheckBox = row.Cells(1).Controls(0)
Dim str As String
str = row.Cells(0).InnerText
Next
dynamic rows created in JS will not be available on server after postback as it is not in the viewstate
to workaround this you may do the following
you can add hidden input field to the page like
<input type="hidden" id="hiddenTableData" name="hiddenTableData" value="" />
then in your script add the data you need to the hidden input field,
$('#hiddenTableData').val(JSON.stringify(ar));
then on server on page post back, get the value of the form hidden field
String tableData= Request.Form["hiddenTableData"];
parse the hidden field value, populate your table and process it
if you are using JavaScript Method or service to fill any controls then you will not get data at code page. but you can pass that array to code page and then can get easily data as you want .
For this you should create a class same as array(in web page you are using) and a web-method
which accepts this(array) class type.
I have tried the same example in my end, and faced the same issue that , generated TR are not accessible in code behind. This is because, they are added using dynamic JS, and those are not put into VIEWSTATE, as you now, ASP control value are available in code behind on POSTBACK only if those are in VIEWSTATE. In this case it was not, so does the debugger says that projGrid.Rows.Count = 0. To make it work, you need to put changed/dynamic JS added TR into VIEWSTATE, but again those are encoded format, i afraid, how to do that.
But if you put any static TR inside table, then definitely those are accessible, I have verified that in debugger, it says projectGrid.Rows.Count = 1, if there is only one static TR inside table. And again because, that static TR is in VIEWSTATE only.
So to conclude, in my opinion, it is better to handle in JS side, if you are going to save those value to DB , then make AJAX call and save, and pass data in JSON format. Or use a hidden field, and save those data in JSON format, and after post, get those in code behind, read JSON format data, and operate.
I'm removing table tbody set and inserting new ones but I'm loosing click event on chekcbox. How can I solve this issue?
I went through append(), clone() but failed to apply to my code so for that reason I created a JSFIDDLE which has everything.
Please tell me what I need to do.
Thanks in advance.
JSFIDDLE - CODE IS HERE
JQUERY:
$(window).load(function(){
$('.add-selected').on("click",function() {
alert('hello');
});
$('#removeAndAdd').click(function(event) {
event.preventDefault();
var output = '';
output += '<tbody class="filter-rows">';
output += '<tr class="filter">';
output += '<td><input type="checkbox" id="c-1" class="add-selected" /></td>';
output += '<td>1</td>';
output += '</tr>';
output += '</tbody>';
output += '<tbody class="filter-rows">';
output += '<tr class="filter">';
output += '<td><input type="checkbox" id="c-2" class="add-selected" /></td>';
output += '<td>2</td>';
output += '</tr>';
output += '</tbody>';
$('.filter-rows').empty();
$('#add-new-table tbody:last').after(output);
});
});
HTML:
<table id="add-new-table" border="1px">
<thead>
<th>ID</th>
<th>SKU</th>
</thead>
<tbody>
<tr>
<td>Lbel</td>
<td>011</td>
</tr>
</tbody>
<tbody class="filter-rows">
<tr class="filter">
<td><input type="checkbox" id="c-1" class="add-selected" /></td>
<td>1</td>
</tr>
</tbody>
<tbody class="filter-rows">
<tr class="filter">
<td><input type="checkbox" id="c-2" class="add-selected" /></td>
<td>2</td>
</tr>
</tbody>
<tbody class="filter-rows">
<tr class="filter">
<td><input type="checkbox" id="c-3" class="add-selected" /></td>
<td>3</td>
</tr>
</tbody>
</table>
<br />
<span id='removeAndAdd'>Click me to Remove all first and Add new rows</span>
There some bad practices here. Firstly the fixed version:
http://jsfiddle.net/678CP/5/
$('#add-new-table').on('change', 'input', function() {
alert('hello');
});
$('#removeAndAdd').click(function(event) {
event.preventDefault();
var rows = $('#add-new-table .filter-rows');
rows.first().add(rows.last()).remove();
});
I am going to assume you need to make a new tbody for every row - otherwise remove it.
Why re-create the whole table? I am assuming you don't need to, if you do the code needs some changes.
Why wait for domLoad? I have change it to onDomReady (fiddle settings)
A clickable element should be an anchor <a> with an href
I know this is just a demo but I am hoping you don't mix double and single quotes in your html and javascript and that you don't use IDs everywhere
How it works:
By using the second parameter of jQuery's on we have created an event delegate. This means that the event is placed on the table itself #add-new-table and it is listening for changes to any inputs inside the table. So it is one single event and it doesn't care if stuff inside is updated/removed etc. It is also more efficient.
And a small explanation of var rows = $('#add-new-table .filter-rows'); rows.first().add(rows.last()).remove();:
"Get all the filter rows and store that. Then select the first row and add the last row to that selection, finally remove them"