Very simple scenario here, I'm hoping there is a simple solution.... Jquery would handle this but for efficiency I want to use the knockout click binding.
<ul>
<li data-bind="click: ShowMyUser">
<span>My Email Address Or Username</span>
<i data-bind="click: DeleteMyUser">Delete Icon</i>
</li>
<ul>
In this example I have a list of Usernames or Email Addresses. What I would like to do, is on the click event of the ROW (e.g. li), show the user details. On the click event of the DELETE icon I would like to show a pop up.
I have both of those methods written and working. My problem is that on clicking the delete icon it ALSO fires the li event.
In order to get round this I have implemented the following:
<ul>
<li>
<span data-bind="click: ShowMyUser">My Email Address Or Username</span>
<i data-bind="click: DeleteMyUser">Delete Icon</i>
</li>
<ul>
However this means that the user must click on the text, I'm not a big fan of this, I think it's un-intuitive.
Any thoughts guys n gals?
KnockoutJS already supports stop bubbling, no need to write it from scratch: http://knockoutjs.com/documentation/click-binding.html (go to Note 4)
Just add clickBubble: false to the child click.
<ul>
<li data-bind="click: ShowMyUser">
<span>My Email Address Or Username</span>
<i data-bind="click: DeleteMyUser, clickBubble: false">Delete Icon</i>
</li>
<ul>
Thank you to Roy J for posting a very helpful link, from that page I found a solution. Firstly I created the following bindingHandler:
ko.bindingHandlers.stopBubble = {
init: function(element) {
ko.utils.registerEventHandler(element, "click", function(event) {
event.cancelBubble = true;
if (event.stopPropagation) {
event.stopPropagation();
}
});
}
};
I then added this to my delete icon so it would not propagate through and call the li click event:
<ul>
<li>
<span data-bind="click: ShowMyUser">My Email Address Or Username</span>
<i data-bind="click: DeleteMyUser, stopBubble: true">Delete Icon</i>
</li>
<ul>
Use binding clickBubble or return false from DeleteMyUser click handler
if you want to have dynamic logic to the bubble but seperated from the click handler you can do
https://jsfiddle.net/h1mrfLe6/
Related
I made the remove item button with the js code while doing the to-do list project.
removing items which are earlier made in Code editor works well.
*so in browser preview, I typed and added "new To-do" item to list.*
but removing "new To-do" item doesn't work. even chrome Devtool shows no error. new item's tag and className is all correct.
p.s : don't need to worry about 'X' or X icon. I skipped for uploading.
[HTML]
<ul id="listUl">
<li>Meet George <span class="remove"></span></li>
<li>Pay Bills <span class="remove"></span></li>
<li>new To-do <span class="remove"></span></li>
</ul>
[JS] - removing part.
var remove = document.getElementsByClassName('remove');
for (var i = 0; i < remove.length; i++) {
remove[i].onclick = function() {
var target = document.getElementById('listUl');
target.removeChild(this.parentElement);
}
}
That's because every new item you add does not have any listener on them (remove[i].onclick = function(){...}). So when you click on them, nothing happens. You need to add the onClick listener to every new items, like you are doing for the initial ones.
Add the onClick listener to ul tag. Check
if(e.target && e.target.nodeName == "LI") {
//Your code here
}
I rewrote your code:
There is only one (delegated) event assigned now to the <ul> parent element, it will trigger only, when the click happens on an element with class="remove". In that case it is the <span> element which I also made a bit more visible by adding an "X" inside. Right, when the action occurs I have to go up two levels until I reach the parent of the actual element I want to remove: the <li> element.
var i=3,UL=document.querySelector('#listUl');
UL.addEventListener('click',function(ev){
// ev.target - this element was clicked on
if (ev.target.classList.contains('remove'))
// ev.target.parentNode - this must be the <li> element
// ev.target.parentNode.parentNode - and this is the <ul> element
ev.target.parentNode.parentNode.removeChild(ev.target.parentNode);
})
document.querySelector('#addTask').addEventListener('click',
function(){UL.innerHTML+='<li>and task no. '+(++i)+'... <span class="remove">X</span></li>'})
<button id="addTask">add another task</button>
<ul id="listUl">
<li>Meet George <span class="remove">X</span></li>
<li>Pay Bills <span class="remove">X</span></li>
<li>new To-do <span class="remove">X</span></li>
</ul>
The "add" button demonstrates how newly created<li>s also respond to clicks on the "remove"-span.
It looks like that the JS code only adds delete function to these todos that already exists when the page loads. Newly added todos will not have onclick callback function attached if you only execute your js once when the pages loads.
The workaround here is to attach the callback function every time you create a TODO element.
Your newly (dynamically) added DOM elements don't have event listeners attached to them, because on page load, you only iterated (looped) only currently available elements, so You may try the following approach (Read About Event Delegation):
document.getElementById('listUl').addEventListener('click', function(e) {
if (e.target.nodeName == 'LI') {
e.target.parentNode.removeChild(e.target);
}
});
<ul id="listUl">
<li>Meet George <span class="remove">X</span></li>
<li>Pay Bills <span class="remove">X</span></li>
<li>new To-do <span class="remove">X</span></li>
</ul>
if you have jquery added to your page, you can do it like
$('#listUl').on('click', 'span.remove', function() {
$(this).parent().remove();
});
$('.add').click(function() {
$("#listUl").append("<li>Whatever Content <span class='remove'>x</span</li>");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="listUl">
<li>Meet George <span class="remove">x</span></li>
<li>Pay Bills <span class="remove">x</span></li>
<li>new To-do <span class="remove">x</span></li>
</ul>
<butoon class="add">Add</butoon>
I want to create dropdown with country->region->city selection.
The first ul opens from click on that span and the others set to show on hover (code at the bottom).
<input type="text" id="srch-area" alt="" class="c-textfield suggestionsInput " name="locationStr" maxlength="" size="" tabindex="3" title="" value="Deutschland" defaultvalue="" highlight="y" strict="y" autocomplete="off">
<span class="c-icon-arrow-green-down-left c-icon" id="loc-slctbx"></span>
<ul class="dropdown-location-ul" id="dropdown-country" style="display:none;">
<li class="dropdown-location-li">
<strong>Deutschland</strong>
<ul class="dropdown-location-ul" style="display:none;">
<li class="dropdown-location-li">
<strong>Brandenburg</strong>
<ul class="dropdown-location-ul" style="display:none;">
<li class="dropdown-location-li">
<strong>Oranienburg</strong>
</li>
<li class="dropdown-location-li">
<strong>Schwedt</strong>
</li>
...
</ul>
</li>
<li class="dropdown-location-li">
<strong>Berlin</strong>
</li>
...
</ul>
</li>
<li class="dropdown-location-li">
<strong>France</strong>
</li>
...
</ul>
$('.dropdown-location-li').hover(function(){
$(this).children('ul').css('left', $(this).parent('ul').width()+'px');
$(this).children('ul').show();
}, function(){
$(this).children('ul').hide();
});
This works just fine and now i need to make it on click to change value of near input to the name of location inside strong tag. I tried the code below but it appears that $(this) selecting the element and all his parents, but i need to get location from only the one i clicked. Please tell me how to do that correctly? Maybe i have completely wrong approach to do this and need to make all with id's and stuff, but i just wanted to minimise the amout of repeating js.
$('.dropdown-location-li').click(function(){
$('#srch-area').val($(this).children('strong').text());
$('#dropdown-country').hide();
});
This is how it shows in console. AS you can see when i click on Oranienburg it selects Brandenburg and Deutschland as well which are the parents of the element i clicked.
console screenshot
You have nested .dropdown-location-li elements, so the click keeps propagating up to the other LI elements, firing the event handler again etc.
You should stop the propagation the first time
$('.dropdown-location-li').click(function(e){
e.stopPropagation();
$('#srch-area').val($(this).children('strong').text());
$('#dropdown-country').hide();
});
try to use JQuery Find
$(this).find('strong').text()
<div class="filter-portfolio pull-right">
<ul>
<li class="always-visible">
****Categories <span class="icon-caret-down"></span>
</li>
<li>
All
</li>
<li>
Fashion
</li>
<li>
Nature
</li>
<li>
Animals
</li>
<li>
Architecture
</li>
</ul>
</div>`
Whenever I click on the **Categories link it is redirecting me to the index.php/#. Can anyone help me find out why it's happening ?
Prevent default click handler:
$('.filter-portfolio a[href="#"]').on('click', function(event) {
event.preventDefault();
});
The # sign scrolls the page to the top when the anchor is clicked, and adds the hash sign to the URL, if you don't want that, just prevent it
$('a[href="#"]').on('click', function(e) {
e.preventDefault()
});
You could also omit the href attribute like this and you would not need any javascript for it.
Like this:
<a data-filter=".all">All</a>
I have a list of links generated dynamically, where the elements look like this:
<li id="nod1">
<span>
<a onclick="javascript:getNodeProperties('1');">Element 1</a>
</span>
</li>
<li id="nod2">
<span>
<a onclick="javascript:getNodeProperties('2');">Element 2</a>
</span>
</li>
getNodeProperties() doesn't do anything currently.
I'm trying to make a jquery (or js function), so that when I click an element, a button will appear on it's right side and the button from the previously clicked element will disappear.
I made this jsfiddle to better explain. How can I do it?
Check this, if you want to display button in right side of <a> tag,and if you click on other <a> tag, the all other button should be hidden
window.getNodeProperties = function(nod_id){
$("li").find(".buttonClass").remove();
$("<input type='button'class='buttonClass'>").appendTo("#nod"+nod_id);
}
Since you have told elements are dynamically added you have to use .on(), I would recommend to give a class name to those anchor tags.
$(document).on("click","a",function(){
$("input.active").remove();
$(this).html($(this).html() + "<input class='active' type='button' value='Click me'/>");
});
js
window.getNodeProperties = function(nod_id){
$("#nod"+nod_id).find("span").remove();
$("<input type='button'>").appendTo("#nod"+nod_id);
}
fiddle
You should try and avoid setting the event handlers in your HTML. You can setup an event delegate for the <a> elements so that i will handle the event even if you add more elements, without attaching new event handlers.
DEMO
$(".tree.well").on("click", "li span", function() {
var but = $("<button>");
but.text("New button");
$(this).parent().append(but);
$(this).remove();
});
HTML
<div class="tree well">
<ul>
<li id="nod1">
<span>
<a>Element 1</a>
</span>
</li>
<li id="nod2">
<span>
<a>Element 2</a>
</span>
</li>
<li id="nod3">
<span>
<a>Element 3</a>
</span>
</li>
</ul>
</div>
Using Firebug I have found that the Dynatree plugin changes the following code:
<li id="id3.1" class="expanded">Menu 1
<ul>
<li id="id3.1.1">Sub-menu 1</li>
</ul>
</li>
To this:
<li class="">
<span class="dynatree-node dynatree-exp-c dynatree-ico-c">
<span class="dynatree-connector"></span>
<span class="dynatree-icon"></span>
<a class="dynatree-title" href="#">Sub-menu 1</a>
</span>
</li>
So when I try to make a click event on the id="id3.1.1" nothing happens because this id doesn't exist anymore.
I made a search here and found the onActivate option that will make my click happen on the menu:
$("#treeMenu").dynatree({
onActivate: function(node){
var menuTitle = node.data.title;
alert(menuTitle);
}
});
My question: Is this the only way to do the click event using Dynatree?
Well I think that is the best option, because it uses the API of the plugin, but of course you could still attach an event to the <a> like this:
$('a.dynatree-title').live('click', function(e){
//here e.target is the link you have clicked
});