I'm using bootstrap to create the stacked pills nav control. Each entry in the control is a link, and that link element also contains a button. The button may be clicked to delete the list entry, or the list entry itself may be clicked to perform some action on it.
The html for each list entry looks like this:
<li>
<a href="#" id="launch_me">Some title
<button class="my-class" id="remove_me">
<i class="icon-remove"></i>
</button>
</a>
</li>
These items are added dynamically based on a response from a server. The jquery then adds the click handler via:
$("#launch_me").click((function (info) {
return function () {
launch(info);
};
})(myInfo));
$("#remove_me").click((function (info) {
return function () {
remove(info);
};
})(myInfo));
When I click on the button to delete the entry, the 'remove' click routine is triggered, followed by the launch routine.
How can I make it so clicking the remove button only results in the remove click handler being run?
Thanks!
Try this:
$("#remove_me").click((function (info) {
return function (e) {
e.stopPropagation();
remove(info);
};
})(myInfo));
http://api.jquery.com/event.stopPropagation/
This will prevent the click event of the "Remove Me" button from bubbling up to its parent "Launch Me" container and executing its click handler.
Your before: http://jsfiddle.net/HVExt/
Mine after: http://jsfiddle.net/HVExt/1/
MyInfo looks dodgy to me. I wiuld skip that and add ; instead. But then i don't know the rest of your code...
Related
Basically I have a list with members of your team. For every member there is an individual div, to select a member you click on the div. I have added an on click event handler on the div so that on click it selects that specific member and highlights it. I also have an edit button and a remove button inside the div for each member. However what is happening right now is that when you want to edit or remove a team member it also triggers the div onClick. I understand that this is expectd behaviour however I'm not sure how I can prevent the div onClick from firing when the buttons are clicked or how I can achieve the same 'look and feel' without putting the buttons in the div.
I want to keep the same look (a section for every teammember which can be clicked to select a team member) but I don't mind changing the structure of the div. I'm working in React if that matters.
Here's a simple example of how you stop the clicks bubbling up to the parent:
const Button = () => (
<div
onClick={() => {
console.log("I won't trigger if you click the inside div");
}}
>
<div
onClick={event => {
event.stopPropagation(); // <-- this stops the click going through to the parent div
console.log('Thank you for clicking the inside div');
}}
>
I'm Inside
</div>
</div>
);
Change the onClick to:
onClick = (event) => {
//event.target includes the specific element which was clicked.
if(event.target.id == '<YOUR-DIV-ID>'){
//handler
}
}
I have a link which calls an action on click like below. I haven't populated the href because I want this handled in the action and I don't want to trigger a page reload.
HBS
<a class="cursor-pointer" {{on "click" (fn this.goToPage this.nextPageNumber)}}>Next</a>
JS
#action
goToPage(pageName) {
this.args.pageUpdated('page', pageName.toString());
// scroll to top of search results
document.querySelector('.search-summary-title').scrollIntoView();
}
Is there a way to direct the user to the right page if they right-click and choose "open in new tab"?
what you should do is set the href:
<a href={{this.nextPageNumber}} {{on "click" (fn this.goToPage this.nextPageNumber)}}>Next</a>
and then prevent the default action in your click handler:
#action
goToPage(pageName, event) {
event.preventDefault();
this.args.pageUpdated('page', pageName.toString());
// scroll to top of search results
document.querySelector('.search-summary-title').scrollIntoView();
}
this is also much better for accessibility!
Upon further research I don't think this is possible to do within an action but I have a workaround if anyone is interested.
I don't want the href to interfere with my action so I don't want to populate it until I need it. So I've modified my template below, you'll see I've added another action which runs oncontextmenu. For those who don't know this event happens when the right click menu pops up.
HBS
<a href="#/" {{on "contextmenu" (fn this.setHref this.nextPageNumber)}}
{{on "click" (fn this.goToPage this.nextPageNumber)}}>Next</a>
What I do now in the setHref action is just populate the href. Now when the user chooses New Window or New Tab it will go to the right place.
JS
#action
setHref(pageName, event) {
event.target.setAttribute('href', `${window.location.pathname}?page=${pageName}`);
}
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 have a button like the below
If a user clicks on the phone number portion, I'd like one action to be called.
If a user clicks on any other part of the rest of the Anchor, they should navigate to a different page.
I've nested everything into an anchor element like so
<a id = "contact_button_outer" href = "http://example.com/linkedtopage">
<button id = "contact_button">
Get Started Now.
<span id = "call_sales_button" onclick = "call();">
Call 111-111-1111
</span>
</button>
</a>
The call function is defined as
function call(){
/*what it do*/
return false
}
I've also added z-indexes to both the anchor and the span, with the span having a higher index than the anchor.
If the user clicks on the phone number span, the default anchor action is still redirecting the browser to the linked page.
How would you prevent the default action from occurring in this instance?
Never use two or more nested Action Elements (a > button or vice-versa)
Use Event.preventDefault() to prevent the default browser action of following a href if some condition is met
Your condition should be "if a clicked element triggers a function, but has an Anchor parent - preventDefault()!"
const fn = {
call(evt) {
// Check if there's an Anchor element as parent
if (evt.target.closest("a")) evt.preventDefault(); // Do not follow parent link
// Call instead!
console.log("calling 111-111-1111")
}
};
document.querySelectorAll("[data-click]").forEach(EL => {
EL.addEventListener("click", (evt) => {
const fnName = evt.currentTarget.dataset.click; // "call"
if (fn[fnName]) fn[fnName](evt);
});
});
<a href="http://example.com/linkedtopage">
Get Started Now.
<b data-click="call">Call 111-111-1111</b>
</a>
PS: Preferably don't do that, wrap into links only the portions you want to be links, and the other ones create click handlers for JS.
Additional read:
Element.closest
Event.target
HTMLElement.dataset
return false inside call() will prevent default browser behaviour on span, but the event will still bubble to parent elements and actions on them is not cancelled. What you need to do is prevent the event from propagating to parent elements. You do this by doing something like this below
function call(event) {
event.stopPropagation(); // modern browsers (IE9 and above)
event.cancelBubble = true; // IE8
//do something
}
if nothing work, try
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();