I am trying to exit a for loop on a click function in javascript. But somewhere I am not getting the correct way to do so. Please take a look to my code and help me to get out of this problem.
What I am trying to do is want to show different div elements inside the li element with a click on li and want to hide the same with a click on div.
here is the link for jsfiddle
Here is the code below :: (html)
<ul>
<li>
<div style="position: fixed; width: 400px; height: 400px; background-color: #0c6; display: none;"></div>
</li>
<li></li>
<li></li>
</ul>
Style
ul {
width: 100%;
height: 100%;
}
ul li {
list-style: none;
float: left;
width: 100px;
height: 100px;
background-color: green;
border: 1px solid;
}
javascript
var a = document.getElementsByTagName('li');
for (i = 0; i < a.length; i++) {
a[i].onclick = function () {
var b = this.getElementsByTagName('div')[0];
setTimeout(function () {
b.style.display = 'block';
}, 1000);
b.onclick = function () {
this.style.display = 'none';
};
};
}
Related
I am currently trying to create a Character Selection for Airconsole.
I thought I could create this using a Jquery method like a Gallery.
So I need a previous button, a next button and the character display.
It seems that I am making a mistake that I can't figure out, because I am not used to working with Javascript.
var speed = 100;
$(".prev").click(function() {
var now = $(this).parent().next("ul.char_display").children(":visible"),
last = $(this).parent().next("ul.char_display").children(":last"),
prev = now.prev();
prev = prev.index() == -1 ? last : prev;
now.fadeOut(speed, function() {
prev.fadeIn(speed);
});
});
$(".next").click(function() {
var now = $(this).parent().next("ul.char_display").children(':visible'),
first = $(this).parent().next("ul.char_display").children(':first'),
next = now.next();
next = next.index() == -1 ? first : next;
now.fadeOut(speed, function() {
next.fadeIn(speed);
});
});
$(".char_display li").click(function() {
var first = $(this).parent().children(':first'),
next = $(this).next();
next = next.index() == -1 ? first : next;
$(this).fadeOut(speed, function() {
next.fadeIn(speed);
});
});
.prev {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.next {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.char_display li {
display: none;
list-style: none;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.char_display li:first-child {
display: block;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.char_display {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.char {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#char1 {
background: blue;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#char2 {
background: red;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="characterScreen_characterBlock">
<div id="characterScreen_leftArrow" class="characterScreen_left" ontouchend="otherChar(true);" ontouchend="otherChar(true);">
<div class="prev"></div>
</div>
<div id="characterScreen_characterDisplay" class="characterScreen_center">
<ul class="char_display">
<li>
<div class="char" id="char1"></div>
</li>
<li>
<div class="char" id="char2"></div>
</li>
</ul>
</div>
<div id="characterScreen_rightArrow" class="characterScreen_right" ontouchend="otherChar(false);" ontouchend="otherChar(false);">
<div class="next"></div>
</div>
</div>
I haven't look through all of your code, but I am pretty sure
$(this).parent().next("ul.char_display").children("...")
doesn't do what you want it to. Especially since it always returns an error for pushing the next-button.
$.next() returns the next DOM-element. characterScreen_rightArrow however doesn't have a next element (in this snippet)
What you were searching for is probably $.siblings(). Personally I would however use the qualifier #characterScreen_characterDisplay ul instead of searching for it relatively.
I have a draggable floating icon that you can drag in front of these big square list items. I put the list behind the icon in css with
li{
position: absolute;
z-index: -1;
}
Is there any way that the floating icon, made with anime-js, can figure out which list item it is in front of?
You can do it by finding positions with getBoundingClientRect. This is by using collision detection. If you instead want to do something on drag & drop of cursor, use the drag and drop API instead.
function findElementBehindCursor(cursor, elements) {
var cursorBoundingBox = cursor.getBoundingClientRect(),
overlapped;
overlapped = [...elements].filter(e => isInside(e.getBoundingClientRect(), cursorBoundingBox));
return overlapped;
}
function isInside(eBounds, cBounds) {
return eBounds.top < cBounds.top && eBounds.right > cBounds.right && eBounds.bottom > cBounds.bottom && eBounds.left < cBounds.left;
}
function runExample() {
var cursorEle = document.getElementById('draghandle');
var liElements = document.getElementById('boxlist').children;
var results = findElementBehindCursor(cursorEle, liElements);
results.forEach(e => e.style.backgroundColor = 'green');
}
#wrapper {
position: relative;
}
#boxlist li {
width: 200px;
height: 200px;
background: red;
list-style: none;
margin: 2px;
}
#draghandle {
width: 10px;
height: 10px;
position: absolute;
top: 100px;
left: 100px;
background: yellow;
border: 1px solid white;
}
button {
background: blue;
color: #fff;
}
<button onclick="runExample()">Click to find element behind yellow cursor</button>
<div id="wrapper">
<ul id="boxlist">
<li></li>
<li></li>
<li></li>
</ul>
<div id="draghandle">
</div>
</div>
I am learning javascript these days and I have a little problem with my code.
I have three elements on page wrapper1, wrapper2 and wrapper3 and every of these has its triggerand redbox element.
My goal is when the trigger is hit, it will show the redbox element corresponding to number.
Examples:
clicking trigger1 inside wrapper1 element shows up redbox1 element,
trigger2 inside wrapper2 element shows up redbox2 element etc.
The problem is, when I click on trigger3 for example it always shows redbox1 element. (as example shows).
What I am doing wrong? I am just a begginer.
function showTheRedBox() {
var theRedBox = document.getElementsByClassName('redbox');
theRedBox[0].style.display = 'block';
}
body {background: #222;}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox();">trigger1</div>
<div class="redbox">hurrah1</div>
wrapper1</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox();">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox();">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
You can use a for loop and a closure to access the .wrapper information for each onclick event. This method will work whether there are the same amount of children or not, and will always show the correct child.
Also, it is best to not use inline JavaScript attributes (e.g. onclick="showTheRedBox();") you should always assign your event handlers in your script for readability and maintainability.
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
(function(wrapper){
wrapper.querySelector('.trigger').onclick = function() {
hideAll();
wrapper.querySelector('.redbox').style.display = 'block';
}
})(wrappers[i]);
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
(function(wrapper){
wrapper.querySelector('.trigger').onclick = function() {
hideAll();
wrapper.querySelector('.redbox').style.display = 'block';
}
})(wrappers[i]);
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
body {background: #222;}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
<div class="wrapper">
<div class="trigger">trigger1</div>
<div class="redbox">hurrah1</div>
wrapper1</div>
<div class="wrapper">
<div class="trigger">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2</div>
<div class="wrapper">
<div class="trigger">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
This method will also work, but it will use more memory as it queries the DOM once more than the above solution.
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
wrappers[i].querySelector('.trigger').onclick = function() {
hideAll();
this.parentNode.querySelector('.redbox').style.display = 'block';
}
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
wrappers[i].querySelector('.trigger').onclick = function() {
hideAll();
this.parentNode.querySelector('.redbox').style.display = 'block';
}
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
body {background: #222;}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
<div class="wrapper">
<div class="trigger">trigger1</div>
<div class="redbox">hurrah1</div>
wrapper1</div>
<div class="wrapper">
<div class="trigger">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2</div>
<div class="wrapper">
<div class="trigger">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
The problem you have was that the method "getElementsByClassName", returns you an Array that contains all the elements of that class. So, when you where doing this:
theRedBox[0].style.display = 'block'
You were changing the display style of the First element of the Array, in this case "wrapper1".
Here's a modify version that functions whit the others wrappers:
<!DOCTYPE html>
<html lang = 'es'>
<head>
<title> MY TEST </title>
<style>
body {
background: #222;
}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox(0)">trigger1</div> <!-- When the onClick event is trigered the function "showTheRedBox receives a parameter , that parameter is the position of the element in the Array "theRedBox"-->
<div class="redbox">hurrah1</div>
wrapper1
</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox(1)">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2
</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox(2)">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
<script>
function showTheRedBox(wrapperNumber) {
var theRedBox = document.getElementsByClassName('redbox');
theRedBox[wrapperNumber].style.display = 'block';
}
</script>
</body>
</html>
I've got some kind of drop down menu dynamically appending to differents divs. Problem is, when someone click on "close", then style.display = "none" wont work. I can change background, opacity, size but i cant hide it.
Code looks like this:
<style>
html, body{
height: 98%;
}
#editorViewport{
width: 90%;
height: 100%;
min-width: 400px;
min-height: 300px;
position: relative;
margin: 0 auto;
border: 1px solid red;
}
#movingElementsContainer{
display: none;
top: 0px;
left: 0px;
}
#addStartingElementBtn{
width: 60px;
height: 60px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
#addStartingElementBtn:hover{
background-color: #c9eac6;
border: 1px solid grey;
cursor: pointer;
}
#elementsMenuContainer{
width: 150px;
border: 1px solid grey;
background-color: white;
min-height: 100px;
padding: 5px;
position: absolute;
z-index: 2;
display: none;
}
.elementOption{
width: 90%;
padding: 5px;
border: 1px solid grey;
}
.elementOption:hover{
border: 1px solid red;
cursor: pointer;
}
</style>
<body>
<div id="editorViewport">
<div id="addStartingElementBtn" data-Owner="starting" data-Side="starting" class="openElementsMenu">
Click!
</div>
</div>
<div id="movingElementsContainer">
<div id="elementsMenuContainer" data-Open="false" data-Owner="" data-Side="">
<div data-Kind="1" class="elementOption">
One
</div>
<div data-Kind="2" class="elementOption">
Two
</div>
<div data-Kind="3" class="elementOption">
Three
</div>
<div data-Kind="99" class="elementOption">
Close
</div>
</div>
</div>
</body>
<script type="text/javascript">
function prepareEventHandlers(){
var openElementsMenu = document.getElementsByClassName("openElementsMenu");
var event = window.attachEvent ? 'onclick' : 'click';
for(var i = 0; i < openElementsMenu.length; i++){
if(openElementsMenu[i].addEventListener){
openElementsMenu[i].addEventListener('click', elementsMenu, false);
}else{
openElementsMenu[i].attachEvent('onclick', elementsMenu);
}
}
var elementOption = document.getElementsByClassName("elementOption");
for(var i = 0; i < elementOption.length; i++){
if(elementOption[i].addEventListener){
elementOption[i].addEventListener('click', selectElementToCreate, false);
}else{
elementOption[i].attachEvent('onclick', selectElementToCreate);
}
}
}
window.onload = function(){
prepareEventHandlers();
}
var totalElements = 0;
var editorViewport = "editorViewport";
var selectedElementId = "";
var elementsMenu = function(){
var elementsMenu = document.getElementById("elementsMenuContainer")
this.appendChild(elementsMenu);
elementsMenu.style.display = "block";
elementsMenu.style.left = 61 + "px";
elementsMenu.style.top = "0px";
elementsMenu.setAttribute("data-Open", "true");
elementsMenu.setAttribute("data-Owner", this.getAttribute("data-Owner"));
elementsMenu.setAttribute("data-Side", this.getAttribute("data-Side"));
}
var selectElementToCreate = function(){
var dataKind = this.getAttribute('data-Kind');
var parentNode = document.getElementById(this.parentNode.id);
alert(dataKind)
if(dataKind == "99"){
parentNode.style.display = "none"
parentNode.setAttribute("data-Open", "false");
parentNode.setAttribute("data-Owner", "");
parentNode.setAttribute("data-Side", "");
}
}
</script>
Here is a JSFiddle
Many thanks for any advise!
var selectElementToCreate = function(e){
var dataKind = this.getAttribute('data-Kind');
var parentNode = document.getElementById(this.parentNode.id);
alert(dataKind)
if(dataKind == "99"){
console.log(parentNode);
parentNode.style.display = "none"
parentNode.setAttribute("data-Open", "false");
parentNode.setAttribute("data-Owner", "");
parentNode.setAttribute("data-Side", "");
alert("Wont Close :");
}
e.stopPropagation();
}
You are moving the element into the clicked element.
var elementsMenu = document.getElementById("elementsMenuContainer")
this.appendChild(elementsMenu);
At first the menu item's click handler is executed which sets the display property to none and as the click event bubbles then the event handler of the wrapper element is executed and sets the display property to block.
You should stop the propagation of the event using stopPropagation method of the event object.
var selectElementToCreate = function (event) {
event.stopPropagation();
var dataKind = this.getAttribute('data-Kind');
var parentNode = this.parentNode;
if (dataKind == "99") {
parentNode.style.display = "none";
// ...
}
}
So I have this drop down menu that is supposed to have slightly delayed drop on hover, but it doesn't drop at all.
My HTML:
<div class="container">
<ul class="menu">
<li class="overflow-hidden">one
<div class="submenu">test</div>
</li>
<li class="overflow-hidden">two</li>
<li class="overflow-hidden">three</li>
</ul>
</div>
CSS
.menu {
display: block;
width: 100%;
margin: 0;
padding: 0;
}
.overflow-hidden {
display: inline-block;
width: 33%;
height: 20px;
text-align: center;
overflow: hidden;
cursor: pointer;
}
.submenu {
display: block;
height: 200px;
background-color: #999;
}
.container {
width: 100%;
}
What have I missed?
There are a few things you can do to improve your code and make it work:
Document Ready event. you should initialize your code after the DOM has rendered, otherwise your code may be trying to attach events to things that aren't there yet!
$(document).ready(function(){
menuHover();
$('.submenu').width(menuWidth);
});
Scope. Referring to $(this) inside the timer object will not be referring to what you think! Define the element you want to refer to at the top of your function, and you can then safely use this explicit definition in any functions defined within the same scope, and you won't have to worry about their own 'this' being something different.
function () {
var $listItem = $(this);
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function () {
$listItem.css('overflow', 'visible');
}, 200);
}
Semantics. Naming your list items overflow-hidden is semantically bad practice (that is a style not a name!) ... especially when the item is in the overflow-visible state!. It would be advisable to probably remove this altogether and target your list items by something like .menu li or giving them their own class eg. menu-item.
var menuWidth = $('.container').width();
var menuHover = function () {
var timer;
$(".menu li").hover(
function () {
var $listItem = $(this);
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function () {
$listItem.css('overflow', 'visible');
}, 200);
},
function () {
var $listItem = $(this);
clearTimeout(timer);
timer = null;
$listItem.css('overflow', 'hidden');
});};
$(document).ready(function(){
menuHover();
$('.submenu').width(menuWidth);
});
You got two things totally wrong.
First: You're missing the jQuery ready event1.
Second: You didn't think about the scope2. $(this) is not available in setTimeout();
$(function(){ // (1a) jQuery ready start
var menuWidth = $('.container').width();
var menuHover = function(){
var timer;
$(".overflow-hidden").hover(
function(){
if(timer){
clearTimeout(timer);
timer = null;
}
var temporary_element = $(this); // (2a) Store element in temporary variable
timer = setTimeout(function(){
temporary_element.css('overflow', 'visible'); // (2b) Get the stored element from the parent scope
}, 200);
},
function(){
clearTimeout(timer);
timer = null;
$(this).css('overflow', 'hidden');
}
);
};
menuHover();
$('.submenu').width(menuWidth);
}); // (1b) jQuery ready end
CSS3 Transitions
With the use of transition (-webkit,-moz,-ms) you don't even need javascript.
You can use the class or id to control sub elements.
CSS
#menu{
}
#menu>div{
width:33%;
float:left;
height:20px;
background-color:grey;
}
#menu>div>div:nth-child(1){
line-height:20px;
text-align:center;
}
#menu>div>div:nth-child(2){
overflow:hidden;
height:0px;
transition:height 700ms ease 500ms;
/*
the duration is 700milliseconds and the delay is 500milliseconds
*/
background-color:#cc2;
padding:0 16px;
}
#menu>div:hover>div:nth-child(2){
height:20px;
}
HTML
<div id="menu">
<div><div>one</div><div>1</div></div>
<div><div>two</div><div>2</div></div>
<div><div>three</div><div>3</div></div>
</div>
DEMO
http://jsfiddle.net/95wM2/
.menu {
display: block;
width: 100%;
margin: 0;
padding: 0;
background-color: green;
}
.overflow-hidden {
display: inline-block;
width: 33%;
height: 20px;
text-align: center;
position: relative;
cursor: pointer;
}
.submenu {
display: none;
}
.overflow-hidden:hover .submenu {
display: inline-block;
height: 200px;
background-color: #999;
z-index: 1;
width: 100%;
position: absolute;
left: 0;
top: 20px;
}
.container {
width: 100%;
}
you do not need jquery for this, you can use the pseudo class :hover
See this fiddle: http://jsfiddle.net/yA6Lx/14/
.overflow:hover .submenu{
visibility: visible;
opacity: 1;
}