I have a table with live search on it. There is a link in this table that opens a modal where some changes can be made. The modal works when no search is made. But when searching, emptying the table contents, I print the data coming to ajax to the table. Unfortunately, the link that opens modal, does not open modal
This is the link I printed with jQuery:
<a class="show-modal btn btn-warning btn-sm interview-add" customer-id="'.$data->customer_id.'" href="javascript:void(0)"><i class="fas fa-plus text-white"></i></a>
This is the jQuery code:
$('.interview-add').click(function (e) {
e.preventDefault();
var customerId = $(this)[0].getAttribute('customer-id');
$('#interview-customer').val(customerId);
$('#interview-add').modal('show');
})
This is the code where I printed the incoming data:
$('#search-button').click(function (e) {
e.preventDefault();
var searching = $("#search").val();
if(searching === '') {
alert('');
}else{
$.ajax({
url: "{{route('customerSearch')}}",
type: "POST",
data: {
searching: searching
},
success: function (data) {
$("#customers-table tbody").empty();
$(".pagination").remove();
$("#customers-table tbody").html(data);
}
});
}
});
If I understand your question correctly, the problem is that $('.interview-add').click(...) only applies the click handler to elements with the interview-add class that already exist at the time that you do that. Any expression of the form $('<some CSS selector>') performs a search for matching elements at that time, and then anything you do with the result of the search is only applied to those elements. So that would explain why this stops working for you if you dynamically repopulate the table with new elements.
The way to make this work is to use on instead. This is a method that you call on the container element that will contain the elements you're looking for (which could be either your table, or just $(document) for the page in general), and you give it a selector, an event name, and an event handler. Then, whenever that event happens to any element within that container, it will check whether the element matches the selector and if so, it calls the handler.
So, try this:
$(document).on('click', '.interview-add', function (e) {
e.preventDefault();
var customerId = $(this)[0].getAttribute('customer-id');
$('#interview-customer').val(customerId);
$('#interview-add').modal('show');
});
I used $(document) there because in your original code, you weren't restricting your selector to just .interview-add things within a specific part of the page. If you're not going to use that class for anything outside of the table then that's fine, but if you want to make it more specific you could replace $(document) with for instance $('#id-of-my-table') if the table has a unique ID.
The .click() event doesn't work with dynamically added elements. For this you have to use .on('click', function(){}).
There is a really good answer on "Difference between .on('click') vs .click()", that points out some differences between those two.
Related
I'm creating a menu and submenu items all async.
It seems like everytime I create a button Element using AJAX, the Javascript created on $(document).ready isn't working on it, which makes sense because it was created after the document ready. But what do I use to catch newly created elements?
This is the function in question, for all the buttons with .additem on it when the page is loaded, it works perfectly, but when the new button is created with .additem it doesn't work at all.
So I believe the javascript isn't being called on the new element. I've done several tests and I'm confident that's the case, but of course I could be wrong.
$('document').ready(function(){
$('.additem').click( function(e) {
e.preventDefault();
console.log('test')
const category_id = $(this).attr('id');
const url = `/add_item/${category_id}/`;
const name = $(`.newitemname${category_id}`).val();
const price = $(`.newitemprice${category_id}`).val();
const description = $(`.newitemdescription${category_id}`).val();
$.ajax({
type: 'POST',
url: url,
data: {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
'name':name,
'price':price,
'description':description,
},
success:function(response) {
console.log('success', response);
$(`.itemlist${response['category_id']}`).append($(`
<li class="row">
<div class="fw-normal mb-0 col-8"> ${response['item_name']} </div>
<div class="col-3 text-muted pl-5" align="right">$ ${response['item_price']}</div>
<p class="fw-lighter lh-sm" style="font-size: 12px;"> ${response['item_description']} </p>
</li>
`));
},
error:function(response){
console.log('error', response)
},
});
})
I've tried $().click but it doesn't apply to the newly created buttons for some reason.
It works on the elements that are already on the page just fine though.
I've also tried $().change() but it creates multiple copies of the same script. So that when I click the button it does it +1 times everytime I click the button. Ending up creating like 5 of the same item everytime I click .additem.
In jQuery, if you want event handlers to fire on elements '.additem' that are added after the event handler is bound you need to use 'delegated' event handlers, see https://api.jquery.com/on/#direct-and-delegated-events
$(document).on('click', '.additem', function(e) { } );
Here you need to remember to attach that handler to a parent element of all target elements (I used document in this example).
Using AJAX, I am populating a container with the id of logos-page-main-content-wrapper (assigned to a variable called mainContent) on a WordPress page with several levels of descendants; the important (images) descendants have the class medallion-image.
The following jQuery function performs differently than I expect:
jQuery(document).ready(function($){
var mainContent = $('#logos-page-main-content-wrapper');
var medallionImage = $('.medallion-image');
var combinedMarkImage = $('.combined-mark-image');
var monogramImage = $('.monogram-image');
var wordmarkImage = $('wordmark-image');
mainContent.on('click', medallionImage,function(){
jQuery.ajax({
url: ajax_object.ajaxurl,
data: {
action: 'validateUser',
security: ajax_object.ajax_nonce,
current_post_id: ajax_object.current_post_id
},
method: "POST",
success: function(data){
console.log(data);
if(data != true){
window.location = window.location.hostname + '/login';
}
}
});
});
});
The idea is that when a user clicks on the image with the class of medallion-image they will be redirected to a login page if they aren't currently logged into WordPress. The AJAX call works properly, but the .on() function responds to a click on any descendant of mainContent instead of just clicks on the medallion-image images. As I understand it, this shouldn't be happening; only the medallion-image class should respond to clicks.
I've scoured the documentation for .on on the jQuery API site but haven't figured out why it's behaving this way. Any ideas?
This is actually the correct behaviour because jQuery will consider .medallion-image clicked even though you clicked on child elements. This works well because imagine if you have a table of content and you bind .on to the row. Instead building a bunch of child selectors of different elements in the row it triggers based on the fact that you interacted with the row. Here is the behaviour similar to the "issue" you're having:
https://jsfiddle.net/zLfqoj65/
A method to do it so it only executes the function on the parent and only the parent element is to do a check in your .on to ensure that this is the element you want with:
$('.outer').click(function(e) {
if ($(e.target).hasClass('outer')) {
// Execute code.
}
});
This will check to see if this element you clicked on has the exact class you want. Example here:
https://jsfiddle.net/zLfqoj65/2/
You can do prevent capturing the click on mainContent using CSS pointer-events property as:
pointer-events: none
and in the medallion-image turn it back on using:
pointer-events: auto
I've been searching for like 30 minutes already, so I apologize if I missed this answer already. I've seen a lot of CLOSE ones, but none quite like this.
I have an imported JavaScript function which is used in several files. It makes it so any table whose row has a clickable-row class will redirect to the href attribute, thereby making the whole row act like an anchor tag.
However, on some pages I'll have on td be populated with a checkbox, which I want to be able to click WITHOUT the page redirecting (so I can select multiple rows in the table).
Here is my current function:
jQuery(document).ready(function() {
jQuery('.clickable-row').click(function() {
window.document.location = jQuery(this).attr('href');
});
});
I want it to do something like the following, but this doesn't work:
jQuery(document).ready(function() {
jQuery('.clickable-row').click(function() {
if(!jQuery(this).closest('td').hasClass('skip-click')) {
window.document.location = jQuery(this).attr('href');
}
});
});
Any ideas on how to handle this?
You need to use e.target.
this inside the handler will refer to the .clickable-row element, not the element which actually triggered the click. The target property of the event object will return the element that triggered the event.
jQuery(document).ready(function ($) {
$('.clickable-row').click(function (e) {
if (!$(e.target).closest('td').hasClass('skip-click')) {
window.document.location = jQuery(this).attr('href');
}
});
});
I was running some test popups by putting them into the HTML file manually and the JS function that I had to close them worked fine. However, when I add the popups dynamically, the closing function breaks and they are unable to be removed.
Here is the JS function that tells all popups in the .popup class to close when the .close button is clicked. The code also contains a hover function to switch the images out for the close button when the user hovers over it, that is also broken.
$('.popup').on('click', '.close', function() {
$(this).closest('.popup').remove(); //or .hide() if you just want to hide the popup
});
$('img.close').hover(function () {
this.src = '/engine/themes/img/popup.close.hover.png';
}, function () {
this.src = '/engine/themes/img/popup.close.idle.png';
});
And here is my method of adding it to the DOM
var popupID = 'popup1';
// Create popup div
var popupHTML = '<div id="'+popupID+'" class="popup">'+
'<div class="toolbar"><div id="title">Please Wait</div>'+
'<img class="close" src="/engine/themes/img/popup.close.idle.png" alt="Close" title="Close" />'+
'</div><p class="text">Loading...<p></div>';
$('body').append(popupHTML);
$.ajax({
url: pageURL,
cache: false,
success: function(data) {
var matches, pageTitle;
matches = data.match(/<title>(.*?)<\/title>/);
pageTitle = 'MERKD.COM';
if ( typeof matches !== 'undefined' && matches != null ) {
pageTitle = matches[1];
}
$('#'+popupID).html(strReplace('Loading...', data, $('#'+popupID).html()));
$('#'+popupID).html(strReplace('Please Wait', pageTitle, $('#'+popupID).html()));
} // end success call
}); // end ajax function
Note at the bottom I use a manually-written replacing method instead of just using $('#popup1 p').html('some text'); because when I do it that, it shows the text retrieved in data twice, anyone know why that is?
I'm lost as to why this stopped working when I added the popups dynamically, but surely I'm just overlooking something, because I also can't figure out why the text retrieved in data is displayed twice when I do a regular .html() or .text() jQuery call.
Try this:
var hovered;
$(document).on('mouseenter','img.close',function () {
hovered = this;
this.src = '/engine/themes/img/popup.close.hover.png';
});
$(document).on('mouseleave','img.close',function () {
hovered.src = '/engine/themes/img/popup.close.idle.png';
});
Event handlers are bound only to the selected elements and they must exist already on the page at the time the code loads. Otherwise, to correct that, you can use event delegation and add the event handler to "something" that was already there, document is always a safe card.
Read more about .on()
EDIT:
I corrected my code, I actually realized that .on() and hover don't work together, so I adapted to a mouseenter & mouseleave instead. You can not use .hover() here anyway since you need to use delegation.
From jQuery's documentation:
Deprecated in jQuery 1.8, removed in 1.9: The name "hover" used as a shorthand for the string "mouseenter mouseleave". It attaches a single event handler for those two events, and the handler must examine event.type to determine whether the event is mouseenter or mouseleave. Do not confuse the "hover" pseudo-event-name with the .hover() method, which accepts one or two functions.
I want to develop dynamic presentation content in HTML5 presentation from
http://www.script-tutorials.com/creating-an-attractive-presentation-with-html5/
This tutorial is ok for static content . But I want to write dynamic content with jquery as the following:
$(document).ready(function(){
$.getJSON(url, function (data) {
for(var i in data)
{
output=" <button title='Next' id='nav-next' class='nav-next'>Click</button>";
}
$("#placeholder").append(output);
});
});
When click on button , I want to go next slide. But this event does not work. I want to call next function on javascript file. Please help.
You said "When click on button" and that is the answer use jQuery.on() method.
$('#nav-next').on('click',(function () {
// click code.
});
and then when you created DOM with id defined in .on will have click event dynamically attached.
You're not attaching an event to the new button, this can be done using the jQuery click method.
Also some other problems:
the loop seems to be redundant, you're not actually using anything in data.
output is being defined as a global variable in your example, use var to keep it in function scope.
Code:
$(document).ready(function() {
$.getJSON(url, function (data) {
// use var, your output was a global variable
var output = " <button title='Next' id='nav-next' class='nav-next'>Click</button>";
$("#placeholder").append(output);
// attach the click event to the new button
$('#nav-next').click(function () {
// TODO: Implement click method
});
});
});
Since you're not using data you can remove the call to getJSON safely currently. I assume you put it in for some reason though.