Dynamically create event and pass argument to function - javascript

I have dynamically created <li> links through javascript, but while creating onclick event I am not able to pass argument to a function. Please find the script below which is working without argument.
function printa() { $('#output').html(yDev[0]); }
for(var n=0;n<sns.length;n++) {
$("#ulDev").append('<li><a href="#" id=btnDev'+n+'>'+sns[n]+'</a></li>');
document.getElementById('btnDev'+n).onclick=printa
}
I need to use something like the below with arguments in function
function printa(m) { $('#output').html(yDev[m]); }
for(var n=0;n<sns.length;n++) {
$("#ulDev").append('<li><a href="#" id=btnDev'+n+'>'+sns[n]+'</a></li>');
document.getElementById('btnDev'+n).onclick=printa(n)
}
I have tried the following options but no luck.
1. onclick in <a> tags
2. $('#btnDev'+n).addEventListener('click', printa(n))
3. $("#btnDev"+n).on("click", function(evt){ evt.preventDefault(); printa(n); })
Kindly advice on how to proceed or any alternate method.

Firstly, don't use incremental id attributes. It's a pain to maintain. Instead, attach information thats unique to each element using data attributes. The common classname will also then allow you to use a single delegated event handler. Try this:
for (var n = 0; n < sns.length; n++) {
$("#ulDev").append('<li>' + sns[n] + '</li>');
}
$('#ulDev').on('click', 'a', function(e) {
e.preventDefault();
var sns = $(this).data('sns');
$('#output').html(yDev[sns])
});
var sns = [ 'foo', 'bar' ];
var yDev = {
0: 'foooooooo',
1: 'baaaaaaar'
}
for (var n = 0; n < sns.length; n++) {
$("#ulDev").append('<li>' + sns[n] + '</li>');
}
$('#ulDev').on('click', 'a', function(e) {
e.preventDefault();
var sns = $(this).data('sns');
$('#output').html(yDev[sns])
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="ulDev"></ul>
<div id="output"></div>

Instead of using plaintext appended to your parent element, you need to create the element with jquery so jquery knows it exists.
See this answer here for how to do that

Related

jquery function not firing when I use datatable.fnAddData to append the HTML string

jquery function not firing when I use dataTable.fnAddData to append the HTML string.
So I have a function populateDataTable(), there are two columns I needed to render an icon instead of data from JSON.
Hence, I tried to like appending the HTML string including classes for the element in fnAddData(). But somehow it's not firing the click event on the icon.
function populateDataTable(data) {
$("#customerTable").DataTable().clear();
var length = Object.keys(data).length;
for(var i = 1; i < length+1; i++) {
var index = i - 1;
var name = data[index].name;
var queue = data[index].queue;
var expire = data[index].expire;
$('#customerTable').dataTable().fnAddData( [
i,
name,
queue,
'<td id="tb-manage-key" class="tb-manage-key"><div class="tb-btn manage-key-btn switch-view" data-hide="manageCustomers" data-title="#Resources.ManageKeys" data-target="manageKeys"><span></span></div></td>',
'<td class="tb-manage-subs"><div class="tb-btn manage-subs-btn switch-view" data-hide="manageCustomers" data-title="#Resources.ManageSubscriptions" data-target="manageSubscriptions"><span></span></div></td>',
expire,
name
]);
}}
$('.tb-btn.switch-view').on('click', function(e) {
e.preventDefault();
switchView(this);
console.log('Testing'); //not firing
});
Icon is showing, but not firing click event as it supposed to be. Attached below shows that we can see it appends the div as expected.
Solutions
Adding the click event within the populateDataTable() works.
$('#customerTable tbody').on('click', '.tb-btn.switch-view', function() {
switchView(this);
});
You can try a different syntax to listen to the click event...
$('td').on('click', '.tb-btn.switch-view', function(e) {
e.preventDefault();
switchView(this);
console.log('Testing'); //not firing
});

jQuery - click function does not work on dynamically generated button with innerHTML

I have this tag on my HTML file
<tbody id="list" >
in which I integrated some other tags to generate multiple buttons using jquery :
var html = '';
for (i = 0; i < list.length; i++)
{ html += '<tr>';
html += '<td>';
html +='<a class="btn btn-primary btn-delete-item" id="' +i+'" >Remove</a>';
html += '</td>';
html += '</tr>';
}
document.getElementById("list").innerHTML = html;
});
and then I wanted to add a functionnality to every generated button so I wrote this:
$("#list ").click(function(id) {
console.log(id); // to check if the id parameter is passed to the function
// rest of the function
}
My problem is that console.log's output is "undefined", so how can I pass the id to the function parameter?
$("#list").on("click", ".btn", function(e) {
var id = $(this).attr('id');
});
or
$("#list").delegate(".btn", "click", function(e) {
var id = $(this).attr('id');
});
read Delegates on Jquery
Hope this helps
The argument to your click event handler is the event object. The scope within the handler will be the sender so:
$("#list").click(function(event)
{
var elem = $(this);
// you can inspect any property of the element here
console.log(elem.attr('id'));
}
You might also want to look into event delegation using jQuery.
$(".btn-primary").on('click',function(id) {
console.log($(this).attr('id')); // to check if the id parameter is passed to the function
// rest of the function
});
This will work!!
check this jsbin for working code!!
You can use the on function for event delegation:
$('#list').on('click','.btn-delete-item',function(){
console.log($(this).attr('id'));
});

Using JQuery on and off method to attach and remove selected event handlers

I'm using JQuery on method to attach an event handler to the window object:
$(window).on('resize', function(e){
/** my functional code goes here **/
e.stopPropagation();
});
This is event handler is being called multiple times: The reason this is so is because the event handler is in the initialization section of a JQuery plugin, so when someone calls the plugin constructor like so:
$('selector').myPlugin({settings_1});
$('selector').myPlugin({settings_2});
$('selector').myPlugin({settings_3});
The event handler gets attached 3 times.
I'm looking for a way to identify and decommission all but one of the 3 event handlers (using off method) so that during a resize, only one of them will get triggered.
How do I identify the event handlers and remove the ones I want?
Try this:
function myHandler(e){
/** my functional code goes here **/
e.stopPropagation();
}
$(window).on('resize', function (e){
$(window).off('resize', myHandler);
$(window).on('resize', myHandler);
});
If your event handlers have been attached only with jquery (not with plain javascript), read the answer to this question to check if a DOM element already has an event handler and, in your case, avoid duplicating it.
You can leverage an array of {key, callback}. Something like this:
window.resizeCallbacks = [];
function addResizeCallback(key, callback) {
window.resizeCallbacks.push({
key: key,
callback: callback
});
}
function removeResizeCallback(key) {
var index = -1;
for (var i = 0; i < window.resizeCallbacks.length; i++) {
if (window.resizeCallbacks[i].key === key) {
index = i;
}
}
if (index >= 0) {
window.resizeCallbacks.splice(index, 1);
}
}
$(function() {
$(window).resize(function() {
for (var i = 0; i < window.resizeCallbacks.length; i++) {
window.resizeCallbacks[i].callback();
}
});
});

Jquery creating checkboxs dynamically, and finding checked boxes

I have information that comes out of a database and gets put into a list with a checkbox by each element. This is how it is currently done:
function subjects(){
$.ajax({
url: "lib/search/search.subject.php",
async: "false",
success: function(response){
alert(response);
var responseArray = response.split(',');
for(var x=0;x<responseArray.length;x++){
$("#subjects").append("<br />");
$("#subjects").append(responseArray[x]);
$("#subjects").append("<input type='checkbox' />");
}
}
});
}
it works fine, but I need a way to pick up on if a checkbox is clicked, and if it is clicked then display which one was clicked, or if multiple ones are clicked.
I can't seem to find a way to pick up on the checkboxs at all.
the response variable is "math,science,technology,engineering"
Because you are populating the Checkboxes Dynamically you need to Delegate the event
$("#subjects").on("click", "input[type='checkbox']", function() {
if( $(this).is(":checked") ) {
alert('Checkbox checked')
}
});
To better capture the data it is better if you encase the corresponding data into a span , so that it can be easier to search..
$("#subjects").append('<span>'+responseArray[x] + '</span>');
$("#subjects").on("click", "input[type='checkbox']", function() {
var $this = $(this);
if( $this.is(":checked") ) {
var data = $this.prev('span').html();
alert('Current checkbox is : '+ data )
}
});
It would be best to give your dynamically injected checkboxes a class to target them better, but based on your code try:
$("#subjects").on("click", "input", function() {
if( $(this).is(":checked") ) {
// do something
}
});
Since your input elements are added dynamically, you need to use jQuery's .on() function to bind the click event to them. In your case you need to use .on() to bind to an element that exist in the DOM when the script is loaded. In your case, the element with the ID #subjects.
This note from the docs is mainly for machineghost who downvoted my answer for no apparent reason:
Event handlers are bound only to the currently selected elements; they
must exist on the page at the time your code makes the call to .on().
To ensure the elements are present and can be selected, perform event
binding inside a document ready handler for elements that are in the
HTML markup on the page. If new HTML is being injected into the page,
select the elements and attach event handlers after the new HTML is
placed into the page.
$('#subjects input[type=checkbox]').on('click',function(){
alert($(this).prop('checked'));
});
or the change event: in case someone uses a keyboard
$('#subjects input[type=checkbox]').on('change',function(){
alert($(this).prop('checked'));
});
simple fiddle example:http://jsfiddle.net/Dr8k8/
to get the array example use the index of the inputs
alert($(this).prop('checked') +'is'+ $(this).parent().find('input[type=checkbox]').index(this)+ responseArray[$(this).parent().find('input[type=checkbox]').index(this) ]);
simplified example: http://jsfiddle.net/Dr8k8/1/
EDIT: Just for an example, you could put the results in an array of all checked boxes and do somthing with that:
$('#subjects>input[type=checkbox]').on('change', function() {
var checklist = [];
$(this).parent().find('input[type=checkbox]').each(function() {
$(this).css('background-color', "lime");
var myindex = $(this).parent().find('input[type=checkbox]').index(this);
if ($(this).prop('checked') == true) {
checklist[myindex] = responseArray[myindex];
}
});
$('#currentlyChecked').text(checklist);
});
EDIT2:
I thought about this a bit and you can improve it by using .data() and query that or store it based on an event (my button called out by its id of "whatschecked")
var responseArray = ['math', 'science', 'technology', 'engineering'];// just for an example
var myList = '#subjects>input[type=checkbox]';//to reuse
for (var x = 0; x < responseArray.length; x++) {
// here we insert it all so we do not hit the DOM so many times
var iam = "<br />" + responseArray[x] + "<input type='checkbox' />";
$("#subjects").append(iam);
$(myList).last().data('subject', responseArray[x]);// add the data
}
var checklist = [];// holds most recent list set by change event
$(myList).on('change', function() {
checklist = [];
$(myList).each(function() {
var myindex = $(this).parent().find('input[type=checkbox]').index(this);
if ($(this).prop('checked') == true) {
checklist.push($(this).data('subject'));
alert('This one is checked:' + $(this).data('subject'));
}
});
});
// query the list we stored, but could query the checked list data() as well, see the .each() in the event handler for that example
$("#whatschecked").click(function() {
var numberChecked = checklist.length;
var x = 0;
for (x = 0; x < numberChecked; x++) {
alert("Number " + x + " is " + checklist[x] + " of " + numberChecked);
}
});
live example of last one: http://jsfiddle.net/Dr8k8/5/
The general pattern to do something when a checkbox input is clicked is:
$('input[type=checkbox]').click(function() {
// Do something
})
The general pattern to check whether a checkbox input is checked or not is:
var isItChecked = $('input[type=checkbox]').is(':checked');
In your particular case you'd probably want to do something like:
$('#subjects input[type=checkbox]').click(function() {
to limit the checkboxes involved to the ones inside your #subjects element.

multiple functions in the document.ready function

here's my code:
$(document).ready(function () {
$('.flip1').click(function () {
$('.panel1').slideToggle("slow");
});
$('.flip2').click(function () {
$('.panel2').slideToggle("slow");
});
$('.flip3').click(function () {
$('.panel3').slideToggle("slow");
});
$('.flip4').click(function () {
$('.panel4').slideToggle("slow");
});
});
I want to make a loop with .flip as the variable (flipVar) and .panel as (panelVar)
Well if it were my page I'd make sure that those elements all shared a class so that I wouldn't need to loop. However, you could do this:
for (var i = 1; i <= 4; ++i) $('.flip' + i).click((function(i) {
return function() { $('.panel' + i).slideToggle('slow'); };
})(i));
The loop variable has to be trapped in a closure so that each "click" handler references the proper value. Again, I really wouldn't do it this way. I'd make the "flip" elements share a class, and then keep that index (the implicit reference to a corresponding "panel") in a separate class element or in a "data-" attribute. Then the handler could find the panel using that value.
edit — as a hack, you could leverage the fact that the class names of the related elements are both of the form "somethingNN", where "NN" is the numeric part. You could strip off the number and then append it to "panel":
for (var i = 1; i <= 4; ++i) $('.flip' + i).click(function() {
var panelClass = this.className.replace(/.*\bflip(\d+).*/, "panel$1");
$(panelClass).slideToggle('slow');
});
Even though you want to run the selector in a loop, I wouldn't do it like that because you're doing multiple DOM selections. You can get it done with one DOM selection:
$(document).ready(function () {
$('div[class^=flip]').each(function ( idx ) {
$(this).click(function() {
$('.panel' + (idx + 1)).slideToggle("slow");
});
});
});
This will work assuming that the flip elements occur on the page in their numerical order.
This uses the attribute starts with selector to get all <div> elements that have a class name starting with "flip". Change the tag name if it is different, or remove it if they don't all have the same tag.
It uses the index that .each() makes available to you in order to toggle the correct .panel.
$(document).ready(function () {
for (var i=1; i<=4; i++) {
(function(i) {
$('.flip'+i).click(function () {
$('.panel'+i).slideToggle("slow");
});
})(i);
}
});
try this:
$(function(){
for(var i=1;i<5;i++){
$('.flip'+i).click(function () {
$('.panel'+i).slideToggle("slow");
});
}
});
PS:- don't use this it will not work as pointed out by #patrick

Categories

Resources