jquery focus to sibling without focusing out from parent - javascript

I am try to iterate through all li elements in ul on keydown event by firing focus() event for next sibling li. In this process, I dont want to focus out from parent ul.
But its not happening. Even changing focus on siblings is causing focusout event on parent. I want that only when someone clicks somewhere else on the screen should focus out of parent be fired.
var KEY_DOWN=40;
$(document).on('keydown', 'li', function(e){
let keyCode = e.keyCode || e.which;
if(keyCode == KEY_DOWN)
{
if($(this).next().length != 0)
{
$(this).next().focus();
}
else
{
$(this).parent().children().first().focus();
}
return false;
}
});
$(document).on('focusout','ul', function(e)
{
console.log('focused')
});
li
{
border: 1px solid black;
}
li:focus
{
background: #999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul tabindex="-1">
<li tabindex="-1">First</li>
<li tabindex="-1">Second</li>
<li tabindex="-1">Third</li>
</ul>
In the snippet, focused in getting printed on every down key press. How to solve this situation.

Due to event bubbling, the focusout event is logging the message for you when you are focusing out of li too. You can use the event data to check from where you have focused out. (Read more here: jQuery figuring out if parent has lost 'focus')
But I would like to mention how I do it. I would rather like to detect click outside my ul.
var KEY_DOWN=40;
$(document).on('keydown', 'li', function(e){
let keyCode = e.keyCode || e.which;
if(keyCode == KEY_DOWN)
{
if($(this).next().length != 0)
{
$(this).next().focus();
}
else
{
$(this).parent().children().first().focus();
}
return false;
}
});
$(document).on('focusout','ul', function(e)
{
console.log('focused out of li');
});
$(document).click(function() {
console.log('focused out of ul');
});
$('ul').click(function(e) {
e.stopPropagation();
});
li
{
border: 1px solid black;
}
li:focus
{
background: #999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul tabindex="-1">
<li tabindex="-1">First</li>
<li tabindex="-1">Second</li>
<li tabindex="-1">Third</li>
</ul>

Only way I found was to disable focusout event on parent ul when I am trying to focus any li
var KEY_DOWN=40;
$(document).on('keydown', 'li', function(e){
let keyCode = e.keyCode || e.which;
if(keyCode == KEY_DOWN)
{
$(document).off('blur','ul', doWork);
if($(this).next().length != 0)
{
$(this).next().focus();
}
else
{
$(this).parent().children().first().focus();
}
$(document).on('blur','ul', doWork);
return false;
}
});
doWork = function(e)
{
console.log('focused')
};
$(document).on('blur','ul', doWork);
li
{
border: 1px solid black;
}
li:focus
{
background: #999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul tabindex="-1">
<li tabindex="-1">First</li>
<li tabindex="-1">Second</li>
<li tabindex="-1">Third</li>
</ul>

Related

Html 5 nested drag and drop using jQuery

Hello I've created some demo with html5 drag and drop. I have nested dragable containers. When I'm trying to drag an element on child container it appends element on both containers. How can I fix that part? Please Help me.
Here is my example`
html
<div id="div1">
container 1
<div id="div2">
container 2
</div>
</div>
<br>
<img id="drag1" src="http://www.w3schools.com/html/img_logo.gif" width="336" height="69">
jquery
$(document).ready(function() {
var drag1 = `<img src="http://www.w3schools.com/html/img_logo.gif" width="336" height="69">`
$("#div1").on("dragover", function(e) {
$(this).css('background', 'yellow');
e.preventDefault();
e.stopPropogation();
});
$("#div1").on("dragleave", function(e) {
$(this).css('background', 'none');
e.preventDefault();
e.stopPropogation();
});
$("#div2").on("dragover", function(e) {
$(this).css('background', 'yellow');
e.preventDefault();
e.stopPropogation();
});
$("#div2").on("dragleave", function(e) {
$(this).css('background', 'red');
e.preventDefault();
e.stopPropogation();
});
$("#drag1").on("dragstart", function(e) {
e.originalEvent.dataTransfer.setData("Text", e.target.id);
});
$("#div1").on("drop", function(e) {
e.preventDefault();
var data = e.originalEvent.dataTransfer.getData("Text");
data === 'drag1' && $(this).append(drag1);
});
$("#div2").on("drop", function(e) {
e.preventDefault();
var data = e.originalEvent.dataTransfer.getData("Text");
data === 'drag1' && $(this).append(drag1);
});
});
css
#div1 {
min-width: 350px;
min-height: 70px;
padding: 40px;
border: 1px solid #aaaaaa;
}
#div2 {
width: 350px;
min-height: 70px;
padding: 10px;
border: 1px solid #aaaaaa;
background: red;
}
jsfiddle Example
If I want to drag on child it should drop only on that container but on parent container I don't know how to stop the drag event.
Thanks for your help.
Here is your solution:
http://jsfiddle.net/43xky7ot/
1.) it's not propogation rather it is propagation e.stopPropagation()
2.) you need to stop bubbling when dropping in div2: $("#div2").on("drop", function(e) {e.stopPropagation();})
$(document).ready(function() {
var drag1 = `<img src="http://www.w3schools.com/html/img_logo.gif" width="336" height="69">`
$("#div1").on("dragover", function(e) {
$(this).css('background', 'yellow');
e.preventDefault();
e.stopPropagation();
});
$("#div1").on("dragleave", function(e) {
$(this).css('background', 'none');
e.preventDefault();
e.stopPropagation();
});
$("#div2").on("dragover", function(e) {
$(this).css('background', 'yellow');
e.preventDefault();
e.stopPropagation();
});
$("#div2").on("dragleave", function(e) {
$(this).css('background', 'red');
e.preventDefault();
e.stopPropagation();
});
$("#drag1").on("dragstart", function(e) {
e.originalEvent.dataTransfer.setData("Text", e.target.id);
});
$("#div1").on("drop", function(e) {
e.preventDefault();
var data = e.originalEvent.dataTransfer.getData("Text");
data === 'drag1' && $(this).append(drag1);
});
$("#div2").on("drop", function(e) {
e.preventDefault();
e.stopPropagation();
console.log('div2 dropped');
var data = e.originalEvent.dataTransfer.getData("Text");
data === 'drag1' && $(this).append(drag1);
});
});

Menu manage hover and click events

I have a menu that I want to add hover and click events to.
$('a').hover(function(){
$(this).css('background', 'red');
}, function(){
$(this).css('background', '');
});
$('a').click(function(){
$(this).css('background', 'green');
});
Here is the demo:
https://jsfiddle.net/u2dn68bg/18/
How can I stop my hover event from overriding the click event? i.e. if I have already clicked an element the hover event should not get triggered for that clicked element.
Use CSS rules and toggle a class.
$("a").on("click", function (e) {
e.preventDefault();
$(this).toggleClass("active");
})
a.active, a.active:hover {
background-color: green;
}
a:hover {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
One
Two
Three
Four
based on your comment to not use CSS which is a bad design pattern....
$("a").on("click", function (e) {
e.preventDefault();
let color = ''
if (!this.dataset.active) {
this.dataset.active = 1
color = 'green'
} else {
delete this.dataset.active
}
this.style.backgroundColor = color;
}).on("mouseenter mouseleave", function (e) {
if (this.dataset.active) return
const color = e.type === "mouseenter" ? "red" : ""
this.style.backgroundColor = color;
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
One
Two
Three
Four
Toggle a CSS class when the element is clicked. When you hover, only change the background if the element do not have that certain class.
$('a').hover(function(){
!$(this).hasClass('clicked') && $(this).css('background', 'red');
}, function(){
!$(this).hasClass('clicked') && $(this).css('background', '');
});
$('a').click(function(){
$(this).css('background', 'green').toggleClass('clicked');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="list-inline menu list-unstyled">
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>

Pagination : Remove element using jquery?

I have a section where i have to paginate records.
Now the issue is the number gets added but i want to remove the prev number
I have currently having something as below:
Prev 1 2 3 Next
When i click on next 4 gets added and it becomes
Prev 1 2 3 4 Next
When i click on next again 5 gets added and it becomes
Prev 1 2 3 4 5 Next
What i am trying to do and what should be having
Prev 1 2 3 Next
When i click on next 4 gets added and it should become
Prev 2 3 4 Next
When i click on next again 5 gets added and it becomes
Prev 3 4 5 Next
When i click on Previous Now it should be
Prev 2 3 4 Next
Please find my runnable code below:
$('ul.pagination').on('click', 'a', function() { // listen for click on pagination link
if($(this).hasClass('active')) return false;
var active_elm = $('ul.pagination a.active');
if(this.id == 'next'){
var _next = active_elm.parent().next().children('a');
if($(_next).attr('id') == 'next') {
// appending next button if reach end
var num = parseInt($('a.active').text())+1;
active_elm.removeClass('active');
$('<li><a class="active" href="#">'+num+'</a></li>').insertBefore($('#next').parent());
return;
}
_next.addClass('active');
}
else if(this.id == 'prev') {
var _prev = active_elm.parent().prev().children('a');
if($(_prev).attr('id') == 'prev') return false;
_prev.addClass('active');
} else {
$(this).addClass('active');
}
active_elm.removeClass('active');
});
ul.pagination {
display: inline-block;
padding: 0;
margin: 0;
}
ul.pagination li {display: inline;}
ul.pagination li a {
color: black;
float: left;
padding: 8px 16px;
text-decoration: none;
transition: background-color .3s;
border: 1px solid #ddd;
}
ul.pagination li a.active {
background-color: #4CAF50;
color: white;
border: 1px solid #4CAF50;
}
ul.pagination li a:hover:not(.active) {background-color: #ddd;}
div.center {text-align: center;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="center">
<ul class="pagination">
<li><a id="prev">«</a></li>
<li><a id="test1" href="#">1</a></li>
<li><a id="test2" class="active" href="#">2</a></li>
<li>3</li>
<li>»</li>
</ul>
</div>
Use this after adding next number
$('#prev').parent().next().remove();
Codepen http://codepen.io/mastersmind/pen/ZBJZjo
Here is how I would do it.
I would add a class to the 3 <li> tags with the numbers inside for easy access with the jQuery selector.
Inside the if-statement where you check weather the next button has the id next, remove the first child like so:
$('.three_links').first().remove();
and add the next number after the last child like so:
$('.three_links').last().after('<li class="three_links"><a class="active" href="#">'+num+'</a></li>');
and if the id is prev remove the last child and add the previous number before the first child but only if the previous number is greater than 1:
if(num > 0){
active_elm.removeClass('active');
$('.three_links').last().remove();
$('.three_links').first().before('<li class="three_links"><a class="active" href="#">'+num+'</a></li>');
}
Here is a working jsfiddle.
html:
<div class="center">
<ul class="pagination">
<li>«</li>
<li class="three_links"><a id="test1" href="#">1</a></li>
<li class="three_links"><a id="test2" class="active" href="#">2</a></li>
<li class="three_links"><a id="test3" href="#">3</a></li>
<li>»</li>
</ul>
</div>
js:
$('ul.pagination').on('click', 'a', function() { // listen for click on pagination link
if($(this).hasClass('active')) return false;
var active_elm = $('ul.pagination a.active');
if(this.id == 'next'){
var _next = active_elm.parent().next().children('a');
if($(_next).attr('id') == 'next') {
// appending next button if reach end
var num = parseInt($('a.active').text())+1;
active_elm.removeClass('active');
$('.three_links').first().remove();
$('.three_links').last().after('<li class="three_links"><a class="active" href="#">'+num+'</a></li>');
return;
}
_next.addClass('active');
}
else if(this.id == 'prev') {
var _prev = active_elm.parent().prev().children('a');
if($(_prev).attr('id') == 'prev'){
var num = parseInt($('a.active').text())-1;
if(num > 0){
active_elm.removeClass('active');
$('.three_links').last().remove();
$('.three_links').first().before('<li class="three_links"><a class="active" href="#">'+num+'</a></li>');
}
return;
}
_prev.addClass('active');
} else {
$(this).addClass('active');
}
active_elm.removeClass('active');
});
Use below script:
$('ul.pagination').on('click', 'a', function() { // listen for click on pagination link
if($(this).hasClass('active')) return false;
var active_elm = $('ul.pagination a.active');
if(this.id == 'next'){
var _next = active_elm.parent().next().children('a');
if($(_next).attr('id') == 'next') {
// appending next button if reach end
var num = parseInt($('a.active').text())+1;
active_elm.removeClass('active');
$('<li><a class="active" href="#">'+num+'</a></li>').insertBefore($('#next').parent());
var hidenum = parseInt($('a.active').text())-2;
if(hidenum > 0){
$('#next').parent().prev().prev().prev().prev().hide();
}
return;
}
_next.addClass('active');
}
else if(this.id == 'prev') {
var _prev = active_elm.parent().prev().children('a');
if($(_prev).attr('id') == 'prev') return false;
_prev.addClass('active');
} else {
$(this).addClass('active');
}
active_elm.removeClass('active');
});

How to open a box on screen by clicking a link and hide it when clicked outside in JS

My goal is to have #box2 appear when I click on #box1 but when you click on something other than #box2, it will display none and only #box1 will show.
Here are my 2 boxes, they are just 2 styled divs:
var condition;
$(document).click(function() {
if (condition === 'block') {
$(":not(#box2)").click(function() {
$("#box2").hide();
});
}
})
$('#box1').click(function(e) {
$('#box2').css('display', 'block');
condition = 'block';
});
$('#box2').click(function(e) {
$('#box2').css('display', 'none');
condition = 'none';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box1" style="width: 300px; height: 300px; background-color: red; margin-left: 100px; margin-bottom: 50px; position: absolute;">
</div>
<div id="box2" style="width: 300px; height: 300px; background-color: blue; margin-left: 150px; display: none; position: absolute;">
</div>
This current code works correctly the first time but after that, it wont run again. I am just wondering if there is a reset function or where I am going wrong?
Really what I want to do is make this work on an ipad so when the user clicks/taps away from the box, it will close. If there are better ways to do this on the Ipad tablet, please let me know!!
Any ideas?
Don't overcomplicate things. This is all the javascript you need, get rid of everything else:
$(document).click(function () {
$('#box2').hide();
});
$('#box1').click(function (e) {
e.stopPropagation();
$('#box2').show();
});
You could just filter event target at document level:
$(document).on('click', function(e) {
$('#box2').toggle(!!$(e.target).closest('#box1').length);
});
-jsFiddle-
You can listen to all click events of the document and then use the event.target to detect which element is being clicked. if the clicked element is box1 and box2 is not being shown then display it to the user. in any other condition we can hide the box2 if it's not the element being clicked. here is the vanilla JavaScript code to achieve this:
<html>
<body>
<div id='box1'>BOX ONE</div>
<div id='box2' style="display: none;">BOX TWO</div>
<script>
document.addEventListener('click', function(event) {
var secondBox = document.getElementById('box2')
if(event.target.id === 'box1' && secondBox.style.display === 'none'){
secondBox.style.display = 'block'
} else if (event.target.id !== 'box2') {
secondBox.style.display = 'none'
}
})
</script>
</body>
</html>
And if you are into DRY (Do not repeat yourself), you can define a function for this task. Take look at this modified version of the script:
function addOpenHandler(handler, target){
document.addEventListener('click', function(event) {
if(event.target === handler && target.style.display === 'none'){
target.style.display = 'block'
} else if (event.target !== target) {
target.style.display = 'none'
}
})
}
addOpenHandler( document.getElementById('box1'), document.getElementById('box2') )
$(document).click(function () {
if (condition === 'block')
{
$(":not(#box2)").click(function () {
$("#box2").hide();
});
}
})
The line $("#box2").hide(); is firing after every click

Making JavaScript menu close when clicking outside

I'm basically trying to make open menu close when user click anywhere. im new and i dont know what is problem. so far i am using this code, here is my html, css and javaScript. i think problem is in my JavaScript.
thanks for help.
HTML
<div class="menu-button" style="width:23px; cursor: pointer;" onClick="show_menu()"><span style="color:#b0acac;">▼</span></div>
<div id="dropdown_menu" class="hidden_menu">
<ul id="container">
<li>Settings<br></li>
<li>Log Out</li>
</ul>
</div>
CSS
.menu-button{
position: relative;
left:1556px;
top:-43px;
}
.hidden_menu{
display:none
}
#dropdown_menu ul li {
text-decoration:none;
display: inline;
cursor: pointer;
position: relative;
left:-20px;
top:2px;
}
#dropdown_menu ul{
width:80px;
height:90px;
background-color:#efefef;
position:relative;
top:-64px;
left:1460px;
border-color:#ff0000;
border-width:2px;
}
JavaScript
<script>
function show_menu(){
var menu = document.getElementById('dropdown_menu');
if(menu.style.display == 'block'){
menu.style.display = 'none';
}else {
menu.style.display = 'block';
}
}
function hide_menu(){
var menu = document.getElementById('dropdown_menu');
if(menu.style.display == 'none'){
menu.style.display = 'block';
}
}
var cl = document.getElementById("body");
cl.addEventListener("click", hide_menu);
</script>
This can help you.
HTML Code
<div class="menu-button" style="width:23px; cursor: pointer;" ><span id="button" style="color:#b0acac;">Show Menu</span></div>
<div id="dropdown_menu" class="hidden_menu">
<ul id="container">
<li>Settings<br></li>
<li>Log Out</li>
</ul>
</div>
Css
.hidden_menu { display:none;}
JavaScript Code
var dropMenu = document.getElementById('dropdown_menu'),
menuButton = document.getElementById('button'),
dropUL = document.getElementById('container').childNodes;
function hide_menu(evt){
evt = evt || window.event; // get window.event if evt is falsy (IE)
var targetElement = evt.target || evt.srcElement; // get srcElement if target is falsy (IE)
if(targetElement === menuButton || targetElement.nodeName.toLowerCase() === 'li' ){
dropMenu.style.display = 'block'
} else {
dropMenu.style.display = 'none'
}
}
// For legacy broser(IE8 and IE7) support
function addEvent(el, type, fn){
if(typeof addEventListener !== 'undefined'){
el.addEventListener(type, fn, false)
} else {
el.attachEvent('on'+type, fn);
}
}
addEvent(document, 'click', hide_menu);
Demo
If you want plain js:
document.addEventListener('click', function(e){
console.log(e.target.id)
if(e.target.id!=="dropdown_menu")
console.log("document Clicked");
});
It is same as above function but written in javascript
Try
function hide_menu(e){
var menu = document.getElementById('dropdown_menu');
if(e.target != menu) {
menu.style.display = 'none';
}
}
document.body.addEventListener("click", hide_menu);
$('body').click(function(){
if($(this).attr('id')!='dropdown_menu' && !$(this).hasClass('menu-button'))
// code to close the menu
});
Making sure that the click is not on the div for menu

Categories

Resources