Javascript - Change event trigger multiple times - javascript

I have the following table.
<table class="table invoice-items-table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr class="invoice-item-row">
<td>
<select class="selectpicker invoice-item-select" title="Select an Item">
<option value="1">PHP Development</option>
</select>
</td>
<td class="text-right">
<input class="form-control invoice-item-quantity" value="1" type="text">
</td>
<td class="text-right">
<input class="form-control invoice-item-price" value="0.00" type="text">
</td>
<td class="text-right" style="padding-top:18px!important;">
<span class="invoice-item-amount">0 </span>
<span class="invoice-currency">₹</span>
</td>
</tr>
<tr class="invoice-item-add-row">
<td colspan="7">
<a href="#" class="link invoice-item-add text-center">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
Add an Item
</a>
</td>
</tr>
</tbody>
</table>
For on-click event of a.invoice-item-add I append more table rows tr to the table, here is the code for that.
$('.invoice-item-add').on('click', function() {
var itemRowClone = $('.invoice-item-row').last().clone();
itemRowClone.find('input, textarea').val('');
itemRowClone.find('.bootstrap-select').replaceWith(function() { return $('select', this); });
itemRowClone.find('.selectpicker').selectpicker();
$('.invoice-item-add-row').before(itemRowClone);
return false;
});
This works perfectly fine, until I want to trigger select.invoice-item-select, here is how I trigger it.
$(document).on('change', '.invoice-item-select', function() {
// Code here...
});
my problem is, this on-change gets fired multiple times based on the number of elements added dynamically, if there is one tr.invoice-item-row it gets fired twice, if there are two tr.invoice-item-row it gets fired four times, basically it fires times two.
I understand that the tr.invoice-item-row are added dynamically and we are using $(document).on('change', '.invoice-item-select', function()... to listen to the trigger.
How do I make sure this on-change event is fired only once?
Thanks.

$(document).on('change') event should called once on page load. No need to add document change on row add.
OR
You can first unbind event then bind again like
$(document).off('change','.invoice-item-select').on('change', '.invoice-item-select', function() {
// Code here...
});

I ended up using this solution
$(document).on('change', '.invoice-item-select', function(e) {
if (e.handled !== true) {
e.handled = true;
return;
}
// Code here
});
Although this does not stop from multiple firing of events, I can at-least stop the code execution for subsequent triggers.

Below code save my time. Your code should run inside the 'if' function and element's 'click' event. Then you can avoid the item duplication.
$(document).on('click', '.selectpicker', function(e) {
if (e.handled !== true)
{
e.handled = true;
// Your code here
return;
}
});

You can try in alternative way like this,
$('.invoice-item-select.bootstrap-select').on('changed.bs.select', function(){
// your code
});
bootstrap-select class should be applied after loading DOM into the browser.
I hope this will solve your problem.

Related

How to hide a row if checkbox is not selected inside html table?

I have dynamically created checkboxes inside HTML table like given in the following code. And I am trying to hide the rows whose checkbox is not checked by using below lines of code on the another button click() function.
$(document).on("click", "#allotBtn", function() {
$('#studentListBody tr [type="checkbox"]').each(function(i, chk) {
if (!chk.checked) {
$("#studentList tr:nth-child(" + i + ")").css("display", "none");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<tbody id="studentListBody">
<tr role="row" class="odd">
<td class="centeralign hideFirstTD sorting_1">
<div class="checkbox checkbox-success ">
<input class="commoncheckbox" type="checkbox" id="studentId_-5ab87edaff24ae1204000857" name="studentId_-5ab87edaff24ae1204000857" value="5ab87edaff24ae1204000857">
<label></label>
</div>
</td>
<td class=" align-middle ">
<img alt="image" class="img-circle listProfilePicture" src="../img/studentcap.png">
</td>
<td>Raja Mir</td>
<td>7th</td>
<td>Male</td>
<td>Active</td>
<td>2016</td>
</tr>
<tr role="row" class="even">
<td class="centeralign hideFirstTD sorting_1">
<div class="checkbox checkbox-success ">
<input class="commoncheckbox" type="checkbox" id="studentId_-5ab8d5f8ff24ae120400085f" name="studentId_-5ab8d5f8ff24ae120400085f" value="5ab8d5f8ff24ae120400085f">
<label></label>
</div>
</td>
<td class=" align-middle ">
<img alt="image" class="img-circle listProfilePicture" src="../img/studentcap.png">
</td>
<td>Omer Jan</td>
<td>4th</td>
<td>Male</td>
<td>Active</td>
<td>2018</td>
</tr>
</tbody>
If there are more than 3 rows in the table, the above code hides the rows haphazardly.
Please help!!!
Try this:
$("#allotBtn").click(function(){
$('#studentListBody tr [type="checkbox"]:checked').closest("tr").hide();
});
The issue with your code is that i in the .each() loop starts indexing the elements at 0, whereas when you call nth-child in CSS, the first element is numbered as 1. Therefore the row you hide is always off by 1.
The fix is simple - add 1 to i each time you use it to set nth-child:
$(document).on("click", "#allotBtn", function () {
$('#studentListBody tr [type="checkbox"]').each(function(i, chk) {
if (!chk.checked) {
$("#studentListBody tr:nth-child("+(i+1)+")").css("display", "none");
}
});
});
Working demo: http://jsfiddle.net/jqabpru2/9/
Reference:
https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child
https://api.jquery.com/each/
Or of course you can simplify it much more like in Viam's answer (https://stackoverflow.com/a/51762843/5947043) by finding the row which is the parent of the checkbox instead.
Again, credit to Viam, this can be done by writing
$("#allotBtn").click(function(){
$('#studentListBody tr [type="checkbox"]:checked').closest("tr").hide();
});
instead. Demo of this approach: http://jsfiddle.net/jqabpru2/10/
All you have to do is write the following code instead of your current jQuery code in a click function:
var checkList = $("tr[role='row'] .commoncheckbox");
checkList.each(function(){
$($(this).closest("tr[role='row']").hide());
if($(this).is(":checked")){
$($(this).closest("tr[role='row']").show());
}
});
Here is jsfiddle link on this.
Here is how to check a checkbox is checked or not using jQuery.
This one-liner should do it. No need for loops.
$(function() {
$(document).on("click", "#allotBtn", function() {
$('#studentListBody input[type=checkbox]:not(:checked)').closest('tr').hide();
});
});
Also, attaching the click event like this seems super strange - what exactly are you delegating the event to the document itself for anyway? Is the whole thing loaded dynamically?

How to iterate js function?

I have some repeat button control functions as below, is there a way to iterate them and reduce amount of code?
$('[id$=cBC1]').change(function () {
if ($(this).is(':checked')) {
$(".cBC1_Row").prop("disabled", true);
}
else {
$(".cBC1_Row").prop("disabled", false);
}
$('select').material_select();
});
$('[id$=cBC2]').change(function () {
if ($(this).is(':checked')) {
$(".cBC2_Row").prop("disabled", true);
}
else {
$(".cBC2_Row").prop("disabled", false);
}
$('select').material_select();
});
...
Add HTML code as requested, it's wrapped in a visualforce page, each checkbox will manage text fields on the same row in table.
<table>
...
<tbody>
<tr>
<td>
<apex:inputCheckbox id="cBC1"/>
<label for="j_id0:j_id1:cBC1"></label>
</td>
<td>
<div class="input-field">
<apex:inputField styleClass="validate cBC1_Row"/>
</div>
</td>
<td>
<div class="input-field">
<apex:inputField styleClass="validate cBC1_Row"/>
</div>
</td>
</tr>
<tr>
<td>
<apex:inputCheckbox id="cBC2"/>
<label for="j_id0:j_id1:cBC2"></label>
</td>
<td>
<div class="input-field">
<apex:inputField styleClass="validate cBC2_Row"/>
</div>
</td>
<td>
<div class="input-field inline">
<apex:inputField styleClass="validate cBC2_Row"/>
</div>
</td>
</tr>
</tbody>
</table>
You could drop the last number in the selector, and use "attribute contains" instead, assuming you don't have several elements containing the string cBC.
An other, and better option, would be to use classes
$('[id*=cBC]').on('change', function () {
$(".cBC"+ this.id.match(/\d+$/)[0] +"_Row").prop("disabled", this.checked);
$('select').material_select();
});
Yes, following your pattern you can do:
for (let i = 1; i < amoutOfIds; i++) {
$('[id$=cBC'+i+']').change(function () {
if ($(this).is(':checked')) {
$(".cBC"+i+"_Row").prop("disabled", true);
}
else {
$(".cBC"+i+"_Row").prop("disabled", false);
}
$('select').material_select();
});
}
You have to set correctly the amountOfIds you have, and also you should be changing let i = 1 also to begin with the first id you have.
If you can refactor your event handler to work for each element, you could write a single jquery selector and bind the same anonymous event handler to both elements. It is difficult to determine whether or not this refactoring is feasible without seeing the markup of the elements your script is interacting with.
From your code it seems the IDs are matched.
Why not using:
$('[id^="cBC"]').change(function () {
var _id = $(this).id();
$("."+_id+"_Row").prop("disabled", $(this).is(':checked'));
$('select').material_select();
});

Click event also firing when check box check event within a row gets fired

I have checkboxes within table individual rows.
I want some event to get fired , when elsewhere in the row click happens . But when a checkbox is checked , I do not want to fire any event.
This is my markup.
<tbody data-bind="foreach:CustomerList">
<tr onclick="removepage();" onmouseover="changeRowColor(this)" onmouseout="restoreRowColor(this)">
<td>
<input class="checkbox" data-bind="attr: { Id: 'checkbox' + $data.Id },click:$parent.customerClick" type="checkbox">
</td>
<td class="col-md-4">
<span class="name" data-bind="text:customerName" />
</td>
<td>
<span data-bind="text:siteName" />
</td>
</tr>
</tbody>
So , if removepage() gets fired for everything , when
customerClick() happens , I do not want the removepage() to get fired.
I tried
customerClick: function () {
debugger;
e.stopPropagation();
},
but it did not work.
What did I do wrong ?
your customerClick function should be:
customerClick: function (event) {
event.stopPropagation();
}
,
You are using e without adding it as a parameter for the function
so just add e in your function()
customerClick: function(e) {
e.stopPropagation();
},
In java script you can stop the bubbling of event listner, because you have a few that listenrs to your event you can stop bubbling it to the other events...
event.stopPropagation()
is the method you looking for
You should bind your events like this:
$("#test > tbody > tr")
.on("click", "td:not(.notfiring)", function(){
alert("click tr");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test">
<tbody>
<tr>
<td class="notfiring">
<input class="checkbox" type="checkbox">
</td>
<td>
Col 1
</td>
<td>
Col 2
</td>
</tr>
</tbody>
</table>
I hope this helps you

Mouseenter not working for dynamic content

I have written a code where i need to trigger a functionality when mouse is over to specific elements.
Its working fine for below code for all static
$("table td").on("mouseenter",function(){
console.log("mouse entered")
});
but for all dynamic <td class="editcolumn">XYZ</td> event is not triggering even if i use below code
$("table td").on("mouseenter",".editcolumn",function(){
console.log("mouse entered")
});
Any idea how to make it work. I'm using jQuery 1.11
I know I just commented, but I figured I would show you an example:
HTML:
<table id="tablee" cellspacing="0">
<thead>
<tr class="tablehead">
<th>This</th>
<th>is</th>
<th>a</th>
<th>table</th>
<th>header</th>
<th>and</th>
<th>stuff</th>
<th>though</th>
</tr>
</thead>
<tr class="append">
<td class="edit-column">asdf</td>
<td class="edit-column">qwer</td>
<td class="edit-column">zxcv</td>
<td class="edit-column">rtyu</td>
<td class="edit-column">tyui</td>
<td class="edit-column">dfgh</td>
<td class="edit-column">dfgh</td>
<td class="edit-column">wert</td>
</tr>
<!-- ... -->
</table>
<br/>
<br/>
<input type="button" class="add-column" value="Add Column" />
Javascript:
$(function() {
$('.add-column').click(function() {
$('.append').append("<td class='edit-column'>iueo</td>");
$('.tablehead').append("<th>Mo columns</th>");
});
/* vvv - this */
$("#tablee").on('mouseenter', '.edit-column', function() {
/* ^^^ should be children or a child of this */
$(this).css('background-color', 'yellow');
});
});
Here is a fiddle
This question's answer gives a much better explanation of delegated events.
I too faced a similar problem for dynamic elements that are added or removed. In such situations you can create dynamic elements with event-handlers attached to their attributes i.e. in your case you can put the desired operations in a function which gets called by your attribute event handlers:
It should be something like this:
Javascript:
function whenMouseEnters() {
// perform some operations
}
Html:
<td onmouseenter="whenMouseEnters()">
If table is aviable on DOM load you can write delgated event for the td with class editColumn like this:
$("table").on("mouseenter",".editcolumn",function(){
console.log("mouse entered")
});

Why jquery "change" event does not work in my example?

When a [name="tip"] has the first value, display a specific element, otherwise it would display another element.
Both elements have the display:none property. When I load the page I check the select value and fadeIn the desired element automatically.
Everything works fine except when I try to change the selected option: nothing happens. I added both javascript onchange to that item and jquery .change() and nothing happens. Can you tell me why it does not work in my example?
<form id="fm-account-properties-tab" method="POST">
<table width="300px" style="margin-top:10px;" align="center" >
<tr>
<td align="left">
<select class="easyui-combobox" name="tip" style="width:200px;" class="easyui-validatebox" required="true" onchange="changeType();">
<option value="l1">l1</option>
<option value="l2">l2</option>
<script>
$(document).ready(function(){
$('[name="tip"]').val('<?php echo $a['tip'];?>');
});
</script>
</select>
</td>
</tr>
<tr id="l1" style="display:none">
<td align="left">
<select class="easyui-combobox" name="l1" style="width:200px;" class="easyui-validatebox" required="true">
</select>
</td>
</tr>
<tr id="l2" style="display:none">
<td align="left">
<select class="easyui-combobox" name="l2" style="width:200px;" class="easyui-validatebox">
</select>
</td>
</tr>
</table>
</form>
<script>
function changeType()
{
if($('[name="tip"]').val()=='l1')
{
$('#l1').fadeIn();
$('#l2').hide();
}
else
{
$('#l2').fadeIn();
$('#l1').hide();
}
}
$(document).ready( function () {
changeType();
$('[name="tip"]').change(function(){ alert('1');});//it never alerts me
});
use .on for newer jQuery versions (jQuery > 1.7.x reference)
function changeType() {
if ($('[name="tip"]').val() == '___') {
$('#1').fadeIn();
$('#2').hide();
} else {
$('#2').fadeIn();
$('#1').hide();
}
}
$(document).ready(function () {
changeType();
$('select[name="tip"]').on('change', function() {
changeType();
});
});
you have a double class attribute on your select.
here is a working sample http://jsfiddle.net/tvhKH/
May be you should use js error event to figure out the error in that code. E.g, <script> try
{....all your codes here...}
catch(err)
{alert("THE ERRor" + err.message);} </script>. These code will alert your error and the exact point it occurs. Good luck!
First, you should try to add a
console.log("It works");
or a
alert("It works")
in your method so you know if it is actualy called.
Then I think the issue may come from FadeIn() only works on elements with css {display: none} and visibility different of 'hidden', so are you sure your elements are ? In doubt, you may replace
.fadeIn();
by
.css('visibility','visible').hide().fadeIn(); // hide() does the same as display: none
Then please let me know if you have more information after doing that.

Categories

Resources