I have a form with multiple rows and each row has a delete button with a link. I want to progressively enhance the links to add a bootstrap modal to these buttons. So what I'm doing is:
Grab all the delete button elements on the page.
Loop through each button.
For each button and change some attributes on the modal based on what button is clicked, including the url that is called when "OK" is cicked.
Everything is working like I want, except that each time the modal is triggered and the "OK" button is clicked the url attached to that gets appended to the previous one.
http://jsfiddle.net/bittersweetryan/9TpX8/ (click the remove button then OK more than once, have your console open)
Here's the code
//anonymous function to grab all delete buttons and turn into a modal
(function(){
var delBtn = $(".delete"),
$modal = $("#modal-delete");
if(!$modal.size()){
$modal = $('<div id="modal-delete" class="modal hide fade"><div class="modal-header"> ×<h3>Confirm Delete</h3></div><div class="modal-body" id="modal-content"></div><div class="modal-footer"> OK Cancel </div></div>').appendTo("body");
}
delBtn.each(function(){
var $button = $(this),
clickHandler,
href= $button.attr("href");
if(href){
clickHandler = function(){
console.log(href);
//return window.location=href;
};
}
else{
clickHandler = $button.click;
}
$button.attr("data-toggle","modal").
attr("data-target","#modal-delete");
$button.on("click",function(){
$modal.find("#okButton").on("click",function(){
clickHandler();
$modal.modal('hide');
}).
end().
find("#cancelButton").on("click",function(){
$modal.modal('hide');
}).
end().
find("#modal-content").html($button.attr("title"));
});
});
})();
You attach another click handler to 'ok' every time you invoke a dialog. Quick fix:
$modal.find("#okButton").one("click",function(){
clickHandler();
$modal.modal('hide');
})
Your updated fiddle.
In general, binding handlers with jQuery sticks a new handler in the queue; it doesn't overwrite the existing handler with a new one.
After getting burned by this a number of times, mostly trying to properly bind to dynamically generated controls, I just started sticking
.unbind("click")
in the queue before setting up onclick bindings.
Some new fiddle.
Related
I have a page with a variable number of modals. When a modal is shown I add a click event to the button on the modal. When I click the button the event is fired and the next modal is shown. However, on the second modal, nothing is fired when I click the button.
Any thoughts as to why the event listener wouldn't fire on a second click.
This is the code to add the event listener to each modal. onSubmission is the function that does some ajax stuff and hides the current modal, then shows the next modal.
function addSubmitAction(formId) {
console.log(formId);
document.querySelector('#modal-submit').addEventListener('click', function _listener() {
onSubmission({ 'id': formId });
document.querySelector('#modal-submit').removeEventListener('click', _listener, true);
}, true);
}
may be u need get click event on root node?
document.addEventListener('click', ({target}) => {
if( target.id !== submitId ) return;
/// your logic
});
example
Hi I have a button that passes this to a function as below:
<div class="itemRow">
Delete
</div>
For the sake of keeping this simple, I have removed other elements within the itemRow div. Essentially this div contains information about an item as well as a button to delete that item. Every item will have a itemRow div so there are many on the page. I want to determine which row the button call came from so that when the item is actually deleted, the correct row is removed.
function deleteMessage(row, itemNum){
$('#deleteMsgModal').modal('show');
//Change the modal buttons's onclick handler
$("#deleteConfirmBtn").click(function(){ deleteRow(row, itemNum);});
}
So the above function will display a modal that asks for confirmation. The onclick handler of the button in the modal takes in the this object and the item number which then goes to a seperate function deleteRow that actually deletes the row and removes the row.
function deleteRow(contentRow, itemNo){
var item = itemNo;
//do some ajax code to remove the row from the database...
...
//then once it is removed then to remove the div that is showing the row...
$(contentRow).parent().remove();
}
The problem is that when the #deleteConfirmBtn button's click handler takes in this as an argument, it displays it as [Object object] which will not work. Is there a way I can get around this so that the final function can delete the correct div?
you need to wrap 'this' in $ sign. so in your case would be $(row)
Please clarify,
"The problem is that when the #deleteConfirmBtn button's click handler takes in this as an argument, it displays it as [Object object] which will not work."
Where is the html for this and how are you passing in 'this' value to this function.
My concern, Why is it required to pass this, when you are already binding click event to the button. this value should be already passed along in the function.
Thanks
Ashish
You may use the event handling that comes with jQuery. If you register the click handlers in Javascript, you don't need to pass this to the function. jQuery gives you that reference automatically.
I have done several changes to your code to make a running example without using bootstrap:
Each delete button now haves a data property data-row="x" where x is the number of the row. I have also added a tag class to retrieve all these buttons: .btn-delete.
As you can see, the click handler is registered on Javascript. Once you click a delete button, the row number is retrieved from the previously set data porperty.
Each time you process a Confirm delete event, you need to unbind the click handler. If you don't do it, you may end with unexpected behaviours where the previous delete actions are triggered again.
// Event delegated subscription for all the delete events
$(document).on('click', '.btn-delete', function(event) {
// Prevent navigation event of the anchor
event.preventDefault();
// Get the info of the clicked event
let rowElement = $(this);
let rowNumber = rowElement.data('row');
// Show the confirmation message
$('#deleteMsgModal').show();
//Change the modal buttons's onclick handler
$("#deleteConfirmBtn").click( function(ev) {
// Prevent event propagation
ev.preventDefault();
// Remove the 'modal' message and unbind this click event handler
$('#deleteMsgModal').hide()
$(this).unbind('click');
deleteRow(rowElement, rowNumber);
});
});
function deleteRow(contentRow, itemNo){
let item = itemNo;
alert('Item #' + itemNo + ' removed succesfully');
// do some ajax code to remove the row from the database...
// ...
// then once it is removed then to remove the div that is showing the row...
contentRow.parent().remove();
}
#deleteMsgModal {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="itemRow">
<span>Row 1</span>
Delete
</div>
<div class="itemRow">
<span>Row 2</span>
Delete
</div>
<div class="itemRow">
<span>Row 3</span>
Delete
</div>
<div id="deleteMsgModal">
You are about to delete a row. Are you sure?
Confirm delete
<div>
Let's say I have a collection containing 3 elements.
Each element has a corresponding remove button that I would like to initiate a POST to my server. Right now I have it setup so that when "Remove" button is pressed, a confirmation modal pops up with "yes" and "no" buttons. I am using the same modal for each element.
Problem is, when I click "yes" in modal, how can I have it know which remove button I clicked that launched the modal?
Here is a link to a gist containing the problematic code
https://gist.github.com/anonymous/85481507a1171467cae5
I have tried using a suggestion below that implements the following:
$('#hingle_dingle_0').on('click', function(e){
$('#confirmRemoveNetwork').modal('toggle', $(this));
});
$('#confirmRemoveNetwork').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
console.log(button);
});
However this returns an empty set. I can't for goodness sake figure out why it doesn't find the event.
Thanks for any help!
The modal is autoposting because you are opening it with a <button> inside a form with an input. Unless you tell it not to, this will cause a form submit. Simply set the type to button (instead of submit which is default): <button type="button">
You can capture the calling button by tapping into the event thrown when the modal is opened:
$('#confirmRemoveNetwork').on('shown.bs.modal', function (e) {
console.log(e.relatedTarget.id);
});
Finally, be sure your IDs are unique. You cannot have both "remove network" buttons using the same id of removenetworkbtn.
I'm updating the user posts via this code:
var auto_refresh = setInterval(function()
{
$('.contenido-publicaciones')
.load("refresh_p.php?search_user="+search_user).fadeIn();
}, 2500 ); //Which is working.
1: <div class="contenido-publicaciones">, all the <div class="this-is-a-post"> div's from refresh.p.php load here every 2,5 seconds.
2: I have a textarea tag inside for each <div class="this-is-a-post"> that refreshes from refresh_p.php.
3: When <div class="contenido-publicaciones"> refreshes, it also refresh the textarea and prevent the user for typing.
4: All of the textareas have the class b_green
I want to clearInterval(auto_refresh) when the user clicks a textarea with the class b_green so another user can send a comment to that post.
I've tried the following:
$(".b_green").click(function(){
clearInterval(auto_refresh);
}); // Didn't work, <div class="contenido-publicaciones"> keep refreshing.
$("textarea").click(function(){
clearInterval(auto_refresh);
}); // Works only when i click a textarea that i have on the top of the page to send posts, but doesn't work when i click a textarea with the class b_green.
$(this).click(function(){
clearInterval(auto_refresh);
}); //This works if i click on b_green textareas, but stop the Interval on every click that the user does on the page, I only want to stop on b_green textareas click.
Is there any error on my code? Any help would be appreciated.
The clicks do not fire because at the time you are binding them there are no textareas or the ones that there are are latter replaced with new ones. These new textareas do not have the onclick handler attached.
You could do either of these:
Add onclick="clearInterval(auto_refresh);" to the code of the textarea that backend sends and get something like:
<textarea onclick="clearInterval(auto_refresh);"></textarea>
Use on to bind the click handler to a higher element that remains on the page like so:
$(".contenido-publicaciones").on('click', 'textarea', function(){
clearInterval(auto_refresh);
});
As I understood your loaded content contains all nodes which you are trying to handle by click.
If so . There is an issue. Because each time you get update you loose click handlers, because DOM has changed. as + you probably have memory leak here from previous "unreachable" handlers
I have a button, "Add to Cart" which sends an ajax request when clicked. After the request returns successfully, the the button is replaced by "In Your Cart". "In Your Cart" has a mouseover state: "Remove From Cart".
The design requirement is that "Remove From Cart" only appear when the user physically moves the mouse over "In Your Cart". If they simply click "Add to Cart" and don't move the mouse, the button should say "In Your Cart" after the ajax call completes, even if the mouse is still over the element.
A simple mouseover event listener doesn't work, because it triggers when the element becomes visible. I'm considering counting mouseovers and mouseouts of a wrapper element, in order to determine if the mouseover event is "real", or just the result of the element becoming visible, but that's really ugly. Any other ideas for me?
You could do something like this (edit as appropriate for your AJAX call):
HTML:
<div class="cart">
<button class="add-cart">Add to Cart</button>
<button class="in-cart" style="display:none;">In Your Cart</button>
</div>
Javascript:
var $addCart = $('.add-cart');
var $inCart = $('.in-cart');
$addCart.click( function(e){
$addCart.hide();
$inCart.show().addClass( 'initial' );
});
$inCart.mouseover( function(){
if( ! $inCart.is( '.initial' ) ){
$inCart.text( 'Remove from Cart' );
}
});
$inCart.mouseout( function(){
$inCart.text( 'In Your Cart' ).removeClass( 'initial' );
});
jsFiddle
UPDATE
Based on OP's comment below, I've update the HTML and Javascript as follows:
<span class='cart'>
<button class="add-cart">Add to Cart</button>
<button class="in-cart" style="display:none;">In Your Cart</button>
</span>
Javascript:
var $cart = $('.cart');
var $addCart = $('.add-cart');
var $inCart = $('.in-cart');
$addCart.click( function(e){
$addCart.attr('disabled','disabled');
setTimeout(function(){
$addCart.hide();
$inCart.show();
}, 1000);
});
$cart.mouseenter( function(){
if( $inCart.is(':visible') ){
$inCart.text( 'Remove from Cart' );
}
});
$cart.mouseleave( function(){
if( $inCart.is(':visible') ){
$inCart.text( 'In Your Cart' );
}
});
The differences here are:
The add-cart button is disabled while AJAX is simulated and then hidden.
mouseover and mouseout have been replaced with mouseenter and mouseleave.
These events are now tied to the span wrapper so that the user mouse behavior can be tracked better since the span never hides itself.
Updated jsFiddle
You can prevent an event from firing by using jQuery's event.preventDefault();
I would write it this way:
$('#elementid').mouseover(function(){
event.preventDefault();
});
This will stop it from doing what it is supposed to do until you manually fire it later, or add code after the event.preventDefault(); to make it do what you want.
using jquery, mouseenter and mouseleave only fire when you enter or leave... so use a static sized wrapper for your image
onsuccess of the ajax, fade the image to what you want
mouseenter, check a flag you set when add to cart was clicked, if its set, you know the user clicked order, moved the mouse, then moved back in..