This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 4 years ago.
I'm trying to use jQuery to add a click function to a list item. I had this method working using JS and onClick(), however I am trying to bring the code up to date with using jQuery. So my list has the following structure:
<ul id="paginationList" class="pagination">
<li id="1" class="page-item disabled">
<a class="page-link" href="#">Previous</a>
</li>
<li class="page-item">
<a class="page-link" href="#">1</a>
</li>
<li id="2" class="page-item">
<a class="page-link" href="#">Next</a>
</li>
</ul>
The jQuery function is on the document.read function:
$(function () {
$('ul.pagination li.page-item').click(function () {
var $li = $(this);
$.ajax({
type: 'GET',
url: '/Projects/ProjectTable/CountProjects',
data: { searchString: $('#searchBox').val() },
success: function(result) {
$('#table-container').load('/Projects/ProjectTable/TestPartialView',
{
searchString: $('#searchBox').val(),
currentPage: page,
projectCount: result
}, function() {
$li.addClass('active');
});
}
});
});
getTable();
});
getTable() is being executed, however when I click on any <li> the method is not called. I have tried removing ul.pagination from the .click call but again that has had no impact.
What do I need to change so that the <li> have a .click method on each of them?
I have checked the console and there are no errors being reported at all.
There are a few problems with your code.
it seems you never remove the "disabled" class, even when you add the "active" one (but maybe that is what you want), and you are not using event delegation so maybe your even was binding before the <li> elements were created.
Try this:
$('.pagination').on("click", ".page-item", function(){
console.log(this);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="paginationList" class="pagination">
<li id="1" class="page-item disabled">
<a class="page-link">Previous</a>
</li>
<li class="page-item">
<a class="page-link">1</a>
</li>
<li id="2" class="page-item">
<a class="page-link">Next</a>
</li>
</ul>
Here is the same code, written in a more understandable way (IMHO)
$(()=>{
$('.pagination').on("click", ".page-item", onPaginationItemClick);
function onPaginationItemClick(){
var listItem = this,
// it's nicer to assign jQuery ajax calls to a variable, so it could be aborted if needed
CountProjects_REQ = $.ajax({
type : 'GET',
url : '/Projects/ProjectTable/CountProjects',
data : { searchString: $('#searchBox').val() }
});
// using the "done()" method on the jQuery XHR object. do not use "success", it is the old and aweful way
CountProjects_REQ.done(RES => {
$('#table-container').load('/Projects/ProjectTable/TestPartialView', {
searchString : $('#searchBox').val(),
currentPage : page,
projectCount : RES
}, ()=>{
listItem.classList.add('active');
});
})
};
// I have no idea what this part is for...I'll just leave it here
getTable();
});
$('ul.pagination li.page-item') works for the click event:
$('ul.pagination li.page-item').click(function () {
console.log('clicked');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="paginationList" class="pagination">
<li id="1" class="page-item disabled">
<a class="page-link" href="#">Previous</a>
</li>
<li class="page-item">
<a class="page-link" href="#">1</a>
</li>
<li id="2" class="page-item">
<a class="page-link" href="#">Next</a>
</li>
</ul>
If you are adding the li dynamically then you can better use,
$(document).on('click', 'ul.pagination li.page-item', function () {
console.log('clicked');
});
Related
I need to loop through the DOM with JQuery, and add a click handler to multiple parent elements that contain a child that will also be given a slideToggle(). I have the logic working fine when I add the click handlers manually, but now I need to be able to dynamically do this to multiple parent elements.
Here is my HTML:
<div class="map-poi-nav">
<ul class="map-poi-nav-dropdown">
//Parent #1
<li class="sub-menu-link" id="sub-menu-link-1">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Activities
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-1">
<li><a><span>•</span>Golden State Park</a></li>
<li><a><span>•</span>Sunrise Oaks City Park</a></li>
</ul>
</li>
</ul>
<ul class="map-poi-nav-dropdown">
//Parent #2
<li class="sub-menu-link" id="sub-menu-link-2">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Dining
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-2">
<li><a><span>•</span>The Loft Grill</a></li>
<li><a><span>•</span>Fish Grill & Bar</a></li>
</ul>
</li>
</ul>
</div>
Basically, you click on .sub-menu-link to slideToggle() .sub-menu-list.
Here is the JS that I have working so far. It targets the id's manually currently, which feels gross:
$('#sub-menu-link-1').click(function() {
$('#sub-menu-list-1').slideToggle(100);
$(this).toggleClass('active-menu-link');
});
$('#sub-menu-link-2').click(function() {
$('#sub-menu-list-2').slideToggle(100);
$(this).toggleClass('active-menu-link');
});
My apologies if this is something very apparent to do in JQuery. I am not at all familiar with it, and it just so happens to be a requirement of this project.
you could simply use below code.
select all list items with class name and add listener. click will be attached to all elements
$('.sub-menu-link').click(function() {
$(this).slideToggle(100);
$(this).toggleClass('active-menu-link');
});
You already have classes, so just use them instead of the ids: use this to refer to the clicked element, .next() to get the next sibling (the li.sub-menu), and .find('.sub-menu-list') to get to the ul you want to toggle:
$('.sub-menu-link').click(function() {
const $subMenuList = $(this).next().find('.sub-menu-list');
console.log($subMenuList.text().trim());
$subMenuList.slideToggle(100);
$(this).toggleClass('active-menu-link');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="map-poi-nav">
<ul class="map-poi-nav-dropdown">
//Parent #1
<li class="sub-menu-link" id="sub-menu-link-1">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Activities
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-1">
<li><a><span>•</span>Golden State Park</a></li>
<li><a><span>•</span>Sunrise Oaks City Park</a></li>
</ul>
</li>
</ul>
<ul class="map-poi-nav-dropdown">
//Parent #2
<li class="sub-menu-link" id="sub-menu-link-2">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Dining
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-2">
<li><a><span>•</span>The Loft Grill</a></li>
<li><a><span>•</span>Fish Grill & Bar</a></li>
</ul>
</li>
</ul>
</div>
You can use jQuery's .next() like so:
$(".sub-menu-link").click(function() {
$(this).next(".sub-menu-link").slideToggle(100);
$(this).toggleClass("active-menu-link");
})
Or you can chain them and use ES6 arrow syntax to make it more concise:
$(".sub-menu-link").click(() => $(this).toggleClass("active-menu-link").next(".sub-menu-link").slideToggle(100));
You should try this if your list and link ids have similiar pattern as in the code you have shown
$('#sub-menu-link').click(function() {
var id = $(this).attr("id").replace("sub-menu-link", "")
$('#sub-menu-list-'+ id).slideToggle(100);
$(this).toggleClass('active-menu-link');
});
I have this script that replaces content in a div using a menu structure.
This works fine, except it runs multiple times when clicking the various menu items. This makes the page load really slow.
Here is my structure:
$(document).ready(function() {
$('a.nav-link').click(function(e) {
var datalist = $(this).data('value');
var dataname = $(this).data('name');
console.log(datalist, dataname);
$(".content_div").hide().delay(500).fadeIn(500);
$(".content_div").load(dataname + ".php");
return false;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<ul class="nav nav-tabs" id="top-nav" role="tablist">
<li class="nav-item"><a class="nav-link active home" href="#" data-value="home" data-name="home">Aanwezig</a></li>
<li class="nav-item"><a class="nav-link" href="#" data-value="vervoer" data-name="vervoer">Vervoer</a></li>
<li class="nav-item"><a class="nav-link" href="#" data-value="extra" data-name="extra">Overige</a></li>
</ul>
</nav>
<div class="content_div">
</div>
And a screenshot of the console where you can see the script is multiplying...
I have no idea why this is happening. Any help would be really great...
It looks like your js code with the eventhandler is loaded more than once. You better figure out why.
Anyway, you can overcome this by using .off('click').on('click') (every time the code runs you cancel the existing eventhandler (off()) and set a new one (on()).
$('a.nav-link').off('click').on('click', function(e){ ...});
Like other already said, the script itself work fine, maybe because your script it's included more than once in your page.
$(document).ready(function() {
$('a.nav-link').on('click', function(e) {
e.preventDefault();
var datalist = $(this).data('value');
var dataname = $(this).data('name');
console.log('datalist : ', datalist);
console.log('dataname : ', dataname);
$(".content_div").hide().delay(500).fadeIn(500);
$(".content_div").load(dataname + ".php");
});
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<nav>
<ul class="nav nav-tabs" id="top-nav" role="tablist">
<li class="nav-item"><a class="nav-link active home" href="#" data-value="home" data-name="home">Aanwezig</a></li>
<li class="nav-item"><a class="nav-link" href="#" data-value="vervoer" data-name="vervoer">Vervoer</a></li>
<li class="nav-item"><a class="nav-link" href="#" data-value="extra" data-name="extra">Overige</a></li>
</ul>
</nav>
<div class="content_div">
</div>
</body>
</html>
Put a log statement in your $(document).ready
$(document).ready(function() {
console.log('Ready');
$('a.nav-link').click(function(e) {});
});
To trace how many the document.ready is called.
To make sure the 'click' event on your link item to be call only once, you can change the code a little bit
$(document).ready(function() {
console.log('Ready');
$('a.nav-link').unbind('click').bind('click', function(e) {});
});
It is because of calling .click on an item means adding a new event handler on that item, not replacing.
If the #action dropdown element is clicked, a confirm dialog is presented, and if cancelled, the dropdown is closed using .dropdown('toggle').
Not as desired, however, the dropdown cannot be reopened without reloading the page.
What is the proper way to close an opened twitter-bootstrap-3 dropdown?
EDIT. I found I can replace $("#action").dropdown('toggle'); with $("#action").removeClass('open');, however, this does not seem like the "right" way to do it.
$("#netstart").click(function(){
if(confirm('Are you sure?')) {
$.ajax({
type:'post',
url:'netstart',
success: function (rsp){
location.reload();
},
error: function (xhr) {
alert.log(xhr.error);
}
});
location.reload();
}
else {
$("#action").dropdown('toggle');
}
});
<div class="masthead">
<nav class="navbar navbar-default">
<ul class="nav nav-justified">
<li class='first active'><a href='/settings'>Configuration Settings</a></li>
<li id='default'><a href='javascript:void(0)'>Default Settings</a></li>
<li id='testRemote'><a href='javascript:void(0)'>Test Server</a></li>
<li><a href='/logs'>System Logs</a></li>
<li><a href='/backup'>Backup Database</a></li>
<li id='action' class='dropdown'>
<a href='javascript:void(0)' data-toggle='dropdown' class='dropdown-toggle'>Action <b class='caret'></b></a>
<ul class='dropdown-menu'>
<li id='reboot'><a href='javascript:void(0)'>Reboot</a></li>
<li id='halt'><a href='javascript:void(0)'>Shutdown</a></li>
<li id='netstart'><a href='javascript:void(0)'>Restart Network</a></li>
</ul>
</li><li id='logoff' class='last'><a href='javascript:void(0)'>Logoff</a></li>
</ul>
</nav>
</div>
<ul class="nav nav-pills nav-stacked" id="moduleList">
<li class="">
User</li>
<li>
Blog
</li>
</ul>
I have the above bootstrap pill in my website. The active item changes and the script execute to load the active item in the page. In some condition I don't want to change the active item and the decision will be made inside the onclick function loadModule(). How can I do that?
Remove data-toggle="pill" from your markup, then change the class of the selected 'li' to active or empty within 'loadModule'. Here's an example:
function loadModule(a) {
//your logic/////
$('#liUser').attr('class', '');
$('#liBlog').attr('class', 'active');
}
<ul class="nav nav-pills nav-stacked" id="moduleList">
<li id="liUser" class="">
User
</li>
<li id="liBlog">
Blog
</li>
</ul>
I don't know if is useful for you. Try this using jQuery:
$(document).delegate('.nav-pills li a', 'click', function () {
$('.nav-pills li').removeClass('active');
this.parent().addClass('active');
});
Then remove click and data-toggle attributes. You can add some logic inside of delegate callback.
In HTML, I have a button list. If user clicks a button,
doCommand function will be called.
The code is following,
<ul>
<li class="button1" onclick="doCommand('bold');" id="bold-button" title="bold">B</li>
<li class="button2" onclick="doCommand('bold');" id="italic-button" title="bold">I</li>
<li class="button3" onclick="doCommand('bold');" id="underline-button" title="bold">U</li>
<li class="button4" onclick="doCommand('bold');" id="strikethrough-button" title="bold">S</li>
</ul>
This is plain expression, normal web programmer will code like that.
But, I want to hide onclick event and its function for security reason.
So the HTML code will be like this,
<ul>
<li class="button1" id="bold-button" title="bold">B</li>
<li class="button2" id="italic-button" title="bold">I</li>
<li class="button3" id="underline-button" title="bold">U</li>
<li class="button4" id="strikethrough-button" title="bold">S</li>
</ul>
Is there any efficient way to do this?
Hiding onclick property but do the same work.
I am using jQuery.
if you set the same class for the btns, you could easily do:
markup:
<ul>
<li class="button1 clickable" id="bold-button" title="bold">B</li>
<li class="button2 clickable" id="italic-button" title="bold">I</li>
<li class="button3 clickable" id="underline-button" title="bold">U</li>
<li class="button4 clickable" id="strikethrough-button" title="bold">S</li>
</ul>
js:
$('.clickable').click(function(){/* doCommand('bold') or whatever */})
Edit: if you want on click to directly transform the text to bold, you could use the this (that refers to the element you clicked, and you need to wrap it inside jQuery $) keyword inside the function i.e.
$('.clickable').click(function(){$(this).css('font-weight','bold')})
The class should be the same at all buttons, like this:
<li class="button button1"...
<li class="button button2"...
Then, you can do like this in javascript.
$("li.button").click(function() {
doCommand('bold');
});
Without changing your markup and using vanilla JS you can do it the following way.
const list = document.querySelector('ul');
list.addEventListener('click', e => {
if (e.target.classList.contains('button1')) {
console.log('bold');
};
if (e.target.classList.contains('button2')) {
console.log('italics');
};
if (e.target.classList.contains('button3')) {
console.log('underline');
};
if (e.target.classList.contains('button4')) {
console.log('strikethrough');
};
})
<ul>
<li class="button1" id="bold-button" title="bold">B</li>
<li class="button2" id="italic-button" title="bold">I</li>
<li class="button3" id="underline-button" title="bold">U</li>
<li class="button4" id="strikethrough-button" title="bold">S</li>
</ul>
I assign the event to the parent list, and check the class of the target allowing to do whatever action needed.
You can use jquery's document ready event to wire up the events:
$(function()
{
$("#bold-button").click(function(){doCommand('bold');});
}
);