The following happens to me:
I have made a slider with the next and previous arrows that works correctly. The case is that I have a button called "see all" in which when I press it, it puts a display none to the previous and next arrows and shows everything that is in the slider (that is to say, when I press the button, it shows everything and "deactivates" the slider).
The problem is that when you press the button again to stop displaying everything and return to "slider mode", the previous and next buttons do not go through the slider.
The slider is putting the active class and removing it to show what is inside. But once I have used the button of "see all" it is added in line a "display: none" and although I give to the arrows of previous or following and the class active is put correctly it remains the style="display:none;" inline in the html and it stops working.
The code of the button that shows everything:
var btnMore = document.querySelector(".btn-panes");
var boxes = document.querySelectorAll("#slider .box-panes");
var aLeft = document.querySelector("#slider .left");
var aRight = document.querySelector("#slider .right");
var btnMoreActivated = false;
btnMore.addEventListener("click", function(){
if(!btnMoreActivated){
for(var i=0; i<boxes.length; i++ ){
document.querySelector("#slider").style.flexWrap = "wrap";
boxes[i].style.display = "flex";
aLeft.classList.add("ocultar");
aRight.classList.add("ocultar");
}
btnMoreActivated = true;
} else {
for(var i=1; i<boxes.length; i++ ){
boxes[i].style.display = "none";
document.querySelector("#slider").style.flexFlow = "nowrap";
aLeft.classList.remove("ocultar");
aRight.classList.remove("ocultar");
}
btnMoreActivated = false;
}
});
The slider code (it works) but just to show you what it does in case you need to add something to fix the problem:
const items = document.querySelectorAll('#slider .box-panes');
const itemCount = items.length;
const nextItem = document.querySelectorAll('.right img');
const previousItem = document.querySelectorAll('.left img');
var count = 0;
function shorHide(){
switch (key) {
case value:
break;
default:
break;
}
}
function showNextItem() {
items[count].classList.remove('active');
if(count < itemCount - 1) {
count++;
} else {
count = 0;
}
items[count].classList.add('active');
}
function showPreviousItem() {
items[count].classList.remove('active');
if(count > 0) {
count--;
} else {
count = itemCount - 1;
}
items[count].classList.add('active');
}
function keyPress(e) {
e = e || window.event;
if (e.keyCode == '37') {
showPreviousItem();
} else if (e.keyCode == '39') {
showNextItem();
}
}
nextItem[0].addEventListener('click', showNextItem);
previousItem[0].addEventListener('click', showPreviousItem);
document.addEventListener('keydown', keyPress);
This is because inline styles are the most specific type of style to add and therefore the most difficult to override. The simplest solution is to not use inline styles and instead use a class that can be added or removed as needed.
Here's a simple example that you can use to replace: boxes[i].style.display = "none";
// Get the elements that need to be hidden/shown into a collection
let btns = document.querySelectorAll(".nav");
document.getElementById("hide").addEventListener("click", function(e){
// Loop over the collection
btns.forEach(function(el){
el.classList.add("hidden"); // Apply the hidden class
});
});
document.getElementById("show").addEventListener("click", function(e){
btns.forEach(function(el){
el.classList.remove("hidden"); // Remove the class
});
});
.hidden { display:none; }
<button id="hide">Hide Buttons</button>
<button id="show">Show Buttons</button>
<button class="nav"><<</button> <button class="nav">>></button>
Related
I created a click event that opens a previously 'hidden' div and closes it again once you click the same button.
However, it only runs once (one open and one close) - I'm at a loss to explain why it doesn't work if I click it again.
let readMore = document.getElementById('clickAbout');
let moreInfo = document.getElementById('about');
let changeSepa = document.getElementById('sepChange');
readMore.addEventListener('click', function(){
changeSepa.style.height = '2rem';
if (moreInfo.className == "") {
moreInfo.className = "open";
moreInfo.style.display = 'block';
} else {
moreInfo.style.display = 'none';
}
});
this happens because you're checking if className == "", but you are modifying the className to be "open". On the second click it checks the className which is now "open" and goes to the else block. On the third click you expect for it to go into the first block but the className is still "open".
For an easy fix just change the className in the else block
else {
moreInfo.className = "";
moreInfo.style.display = 'none';
}
Also i suggest you make use of the classList property on elements
https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
using the class list it could look like this:
readMore.addEventListener("click", function () {
changeSepa.style.height = "2rem";
if (moreInfo.className == "") {
moreInfo.classList.add("open");
moreInfo.style.display = "block";
} else {
moreInfo.classList.remove("open");
moreInfo.style.display = "none";
}
});
Or even
readMore.addEventListener("click", function () {
changeSepa.style.height = "2rem";
moreInfo.classList.toggle("open");
if (moreInfo.className == "") {
moreInfo.style.display = "block";
} else {
moreInfo.style.display = "none";
}
});
A basic question by a newbie…
I always encounter the same problem :
I often want an element "A" to show an element "B" on click when "B" is hidden, but to hide it when it is visible. Here are two different try that doesn't work :
let ref = document.getElementsByTagName('sup');
let refContent = document.getElementsByTagName('i');
for(let i = 0; i < ref.length ; i++) {
ref[i].addEventListener('click', function() {
if (refContent[i].style.display == "inline") {
refContent[i].style.display = "none";
} else {
refContent[i].style.display = "none";
};
});
}
let ref = document.getElementsByTagName('sup');
let refContent = document.getElementsByTagName('i');
for(let i = 0; i < ref.length ; i++) {
if (refContent[i].style.display == "") {
ref[i].addEventListener('click', function() {
refContent[i].style.display = "inline";
});
} else {
ref[i].addEventListener('click', function() {
refContent[i].style.display = "none";
});
}
}
Hi
I'm gonna change some variable names to make this easier to talk about. So, you start off strong
// get all elements with tag sup
let buttons = document.getElementsByTagName('sup');
//get all elements with tag i
let showables = document.getElementsByTagName('i');
For each element buttons we want to bind an onclick event listener. showables should respond to those clicks. You write
//for every `button` bind this `event listener`
buttons[i].addEventListener('click', function() {
if (showable[i].style.display == "inline") {
showable[i].style.display = "none";
} else {
showable[i].style.display = "none";
};
});
}
To make this a little more clear lets take out the function and give it a name
let show_hide = function(i) {
if (showable[i].style.display == "inline") {
showable[i].style.display = "none";
} else {
showable[i].style.display = "none";
};
});
//for each button, bind show_hide
for(let i = 0; i < buttons.length ; i++) {
buttons[i].addEventListener('click', show_hide(i))
}
The loop there does exactly what you'd expect; it binds show_hide to each button.
What does show_hide do?
//if the element is shown, hide it
if (showable[i].style.display == "inline") {
showable[i].style.display = "none";
//if the element is not shown, hide it
} else {
showable[i].style.display = "none";
};
as you can see that no matter what, show_hide hides the element!
so a quick change will fix this for you.
if (showable[i].style.display == "inline") {
showable[i].style.display = "none";
//if not shown, show
else {
**** showable[i].style.display = "inline";
};
putting it all together, this should work
let show_hide = function(i) {
if (showable[i].style.display == "inline") {
showable[i].style.display = "none";
} else {
showable[i].style.display = "inline";
};
});
//for each button, bind show_hide
for(let i = 0; i < buttons.length ; i++) {
buttons[i].addEventListener('click', show_hide(i))
}
If you want my solution to this problem I'd be more than willing to solve this problem in my own way. Comment and let me know! I hope this helps
fin
I will interpret what you have written but I do not have the complete code I will fix some issues and update if/when you update your code by adding the markup (html).
You should put your selected elements in an array because some browsers will not let you loop over a NodeLists. You can change a NodeLists into an array in a few ways I like the Array.From() way. After changing the NodeLists into an array you can safely loop over the elements in the array using a forEach() loop.
let ref = Array.from(document.getElementsByTagName('sup'));
let refContent = Array.from(document.getElementsByTagName('i'));
ref.forEach(el => {
el.addEventListener('click', e => {
e.target.getElementsByTagName('i').style.display = '' // do something
});
});
This snippet will most likely not work as-is, I'm missing information to finish this script, but perhaps this is a good starting point for further exploration. (Search for stuff and add 'mdn', to get good results).
In stead of directly changing the style of an element it is better to either add or remove a css class which contains the css properties you desire. You can also toggle a class: element.toggle('className).
So I have a few div tags that I have currently hidden, and I want to display them one after the other by hitting the enter key.
What I want to happen: I hit enter and the first div tag is revealed, and then I hit enter a second time to see the second div tag.
What is happening instead: I hit enter once and both div tags show up.
In this case, the first div tag I want to reveal is "intro", and the second is "body". I am running this website on jsbin, and I am using chrome, if that helps.
This is my JavaScript:
//***********************************************************
// BODY MODULE
var bodyController = (function(){
var enterBool;
var reveal = function(){
if(enterBool){
document.getElementById("evidence").style.display = "block";
enterBool = false;
}
};
var enterListen = function(){
document.addEventListener("keydown", function(event){
if(event.keyCode === 13){
document.addEventListener("keyup", function(event){
if(event.keyCode === 13){
enterBool = true;
reveal();
}
});
}
});
};
return{
enterBoolBody: enterBool,
enterListenBody: function(){
enterListen();
}
}
})();
//***********************************************************
// INTRO MODULE
var introController = (function(){
var enterBool;
var reveal = function(){
if(enterBool){
document.getElementById("body").style.display = "block";
enterBool = false;
}
};
var enterListen = function(){
document.addEventListener("keydown", function(event){
if(event.keyCode === 13){
document.addEventListener("keyup", function(event){
if(event.keyCode === 13){
enterBool = true;
reveal();
}
});
}
});
};
return{
enterBoolIntro: enterBool,
enterListenIntro: function(){
enterListen();
}
}
})();
//***********************************************************
// CONTROL MODULE
var controller = (function(introCtrl, bodyCtrl, evidenceCtrl, infoCtrl,
conclusionCtrl){
var eventListeners = function(){
introCtrl.enterListenIntro();
bodyCtrl.enterListenBody();
};
return{
init: function(){
eventListeners();
}
}
})(introController, bodyController, evidenceController,
infoController, conclusionController);
//***********************************************************
controller.init();
I think you might be over engineering this a bit. All you need is an event listener to check for enter. Then you check if the first div is shown, if not show it. If the first div is shown check if the second div is shown and show it.
Quick note, no IE9 support for classList if that's important to you.
https://caniuse.com/#feat=classlist
(function(window, document, undefined)
{
document.addEventListener('keyup', showDivs, false);
})(window, window.document);
function showDivs(event)
{
event = event || window.event;
var divsToShow = document.getElementsByClassName("Display-Div");
for (var i = 0; i < divsToShow.length; i++) {
if (!divsToShow[i].classList.contains("Block")) {
divsToShow[i].classList.add("Block");
break;
}
}
}
.Hidden {
display: none;
}
.Block {
display: block;
}
<div class="Hidden Display-Div">This</div>
<div class="Hidden Display-Div">Now</div>
<div class="Hidden Display-Div">Works</div>
<div class="Hidden Display-Div">With</div>
<div class="Hidden Display-Div">Any</div>
<div class="Hidden Display-Div">Div</div>
<div class="Hidden Display-Div">With</div>
<div class="Hidden Display-Div">Class</div>
<div class="Hidden Display-Div">Display-Div</div>
You can put the ids of your divs in an array, or you could assign a common class to all divs that you want to appear one by one. Assuming the first, this code simply grabs the id of the next div to display from the array and increments the counter. You could add more divs to the array and it would work.
var divs = ["evidence", "body"];
var counter = 0;
document.addEventListener("keyup", function(event){
if(counter < divs.length && event.keyCode == 13){
document.getElementById(divs[counter]).style.display = 'block';
counter++;
}
});
I've got a page wich is, basically, a list of divs; it doesn't matter how they're structured, suffice it to say that they're all visible by default. There are buttons on the page that lets you sort through them thanks to a java script. For example, if you click on the button "complete", the page shows only the divs containing the code
<div class="ended">complete</div>
while if you push on the "show all" button, it returns to show them all. (The structure is something like
<div class="entry">
<p>something</p>
<div class="ended">complete</div>
et cetera </div>
I've recently decided to add a new button, that picks a random div through them all. It all works well, except that when you try to show them all again after picking a random one, it doesn't work.
I'm not really all that familiar with JavaScript and JQuery (the random script I adapted from a script I found here), so I dont' understand what's wrong.
This is the code for (one of) the sorting script:
$('#completed').click(function() {
featureList.filter(function(item) {
if (item.values().ended == "complete") {
return true;
} else {
return false;
}
});
return false;
});
And this is the code for the "show all" button:
$('#filter-none').click(function() {
featureList.filter();
return false;
});
Finally, this is the code for the "random" button:
$(document).ready(function () {
$('#random').click(function () {
var E = document.getElementsByClassName("entry");
var m = E.length;
var n = parseInt(Math.random() * m);
for (var i = m - 1; i >= 0; i--) {
var e = E[i];
e.style.display = 'none';
}
E[n].style.display = '';
});
});
Hard to give an answer without knowing what's going on inside the .filter-function but based on what you've provided this could work:
$('#random').click(function () {
var entries = document.getElementsByClassName("entry");
var numEntries = entries.length;
var random = Math.floor(Math.random() * numEntries);
var counter = numEntries;
featureList.filter(function(item) {
counter--;
if (counter === random) {
return true;
} else {
return false;
}
});
return false;
}
I'm assuming the elements for which false is returned inside .filter are hidden somehow.
Since 'Show all' and 'Show only completed' is working, using the 'Show only completed'-way of hiding the wrong elements in 'Show random' should work.
I have created a form with malsup's Form Plugin wherein it submits on change of the inputs. I have set up my jQuery script to index drop down menus and visible inputs, and uses that index to determine whether keydown of tab should move focus to the next element or the first element, and likewise with shift+tab keydown. However, instead of moving focus to the first element from the last element on tab keydown like I would like it to, it moves focus to the second element. How can I change it to cycle focus to the actual first and last elements? Here is a live link to my form: http://www.presspound.org/calculator/ajax/sample.php. Thanks to anyone that tries to help. Here is my script:
$(document).ready(function() {
var options = {
target: '#c_main',
success: setFocus
};
$('#calculator').live('submit', function() {
$(this).ajaxSubmit(options);
return false;
});
$(this).focusin(function(event) {
var shiftDown = false;
$('input, select').each(function (i) {
$(this).data('initial', $(this).val());
});
$('input, select').keyup(function(event) {
if (event.keyCode==16) {
shiftDown = false;
$('#shiftCatch').val(shiftDown);
}
});
$('input, select').keydown(function(event) {
if (event.keyCode==16) {
shiftDown = true;
$('#shiftCatch').val(shiftDown);
}
if (event.keyCode==13) {
$('#captured').val(event.target.id);
} else if (event.keyCode==9 && shiftDown==false) {
return $(event.target).each(function() {
var fields = $(this).parents('form:eq(0),calculator').find('select, input:visible');
var index = fields.index(this);
var nextEl = fields.eq(index+1).attr('id');
var firstEl = fields.eq(0).attr('id');
var focusEl = '#'+firstEl;
if (index>-1 && (index+1)<fields.length) {
$('#captured').val(nextEl);
} else if(index+1>=fields.length) {
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(firstEl);
} else {
event.preventDefault();
$(focusEl).focus();
}
}
return false;
});
} else if (event.keyCode==9 && shiftDown==true) {
return $(event.target).each(function() {
var fields = $(this).parents('form:eq(0),calculator').find('select, input:visible');
var index = fields.index(this);
var prevEl = fields.eq(index-1).attr('id');
var lastEl = fields.eq(fields.length-1).attr('id');
var focusEl = '#'+lastEl;
if (index<fields.length && (index-1)>-1) {
$('#captured').val(prevEl);
} else if (index==0) {
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(lastEl);
} else {
event.preventDefault();
$(focusEl).select();
}
}
return false;
});
}
});
});
});
function setFocus() {
with (document.calculator)
var recap = document.getElementById(recaptured.value);
if (recap!=null) {
setTimeout(function() {
if (recap.getAttribute('type')=='text') {
recap.select();
} else {
recap.focus();
}
}, 100 );
}
}
Edit #1: I made a few minor changes to the code, which has brought me a little closer to my intended functionality of the script. However, I only made one change to the code pertaining to the focus: I tried to to disable the tab keydown when pressed on the last element (and also the shift+tab keydown on the first element) in an attempt to force the focus on the element I want without skipping over it like it has been doing. This is the code I added:
$(this).one('keydown', function (event) {
return !(event.keyCode==9 && shiftDown==true);
});
This kind of works. After the page loads, If the user presses tab on the last element without making a change to its value, the focus will be set to the second element. However, the second time the user presses tab on the last element without making a change to its value, and every subsequent time thereafter, the focus will be set to the first element, just as I would like it to.
Edit #2: I replaced the code in Edit #1, with code utilizing event.preventDefault(), which works better. While if a user does a shift+tab keydown when in the first element, the focus moves to the last element as it should. However, if the user continues to hold down the shift key and presses tab again, focus will be set back to the first element. And if the user continues to hold the shift key down still yet and hits tab, the focus will move back to the last element. The focus will shift back and forth between the first and last element until the user lifts the shift key. This problem does not occur when only pressing tab. Here is the new code snippet:
event.preventDefault();
$(focusEl).focus();
You have a lot of code I didn't get full overview over, so I don't know if I missed some functionality you wanted integrated, but for the tabbing/shift-tabbing through form elements, this should do the work:
var elements = $("#container :input:visible");
var n = elements.length;
elements
.keydown(function(event){
if (event.keyCode == 9) { //if tab
var currentIndex = elements.index(this);
var newIndex = event.shiftKey ? (currentIndex - 1) % n : (currentIndex + 1) % n;
var el = elements.eq(newIndex);
if (el.attr("type") == "text")
elements.eq(newIndex).select();
else
elements.eq(newIndex).focus();
event.preventDefault();
}
});
elements will be the jQuery object containing all the input fields, in my example it's all the input fields inside the div #container
Here's a demo: http://jsfiddle.net/rA3L9/
Here is the solution, which I couldn't have reached it without Simen's help. Thanks again, Simen.
$(document).ready(function() {
var options = {
target: '#c_main',
success: setFocus
};
$('#calculator').live('submit', function() {
$(this).ajaxSubmit(options);
return false;
});
$(this).focusin(function(event) {
$('#calculator :input:visible').each(function (i) {
$(this).data('initial', $(this).val());
});
return $(event.target).each(function() {
$('#c_main :input:visible').live(($.browser.opera ? 'keypress' : 'keydown'), function(event){
var elements = $("#calculator :input:visible");
var n = elements.length;
var currentIndex = elements.index(this);
if (event.keyCode == 13) { //if enter
var focusElement = elements.eq(currentIndex).attr('id');
$('#captured').val(focusElement);
} else if (event.keyCode == 9) { //if tab
var newIndex = event.shiftKey ? (currentIndex - 1) % n : (currentIndex + 1) % n;
var el = elements.eq(newIndex);
var focusElement = el.attr('id');
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(focusElement);
} else if ((currentIndex==0 && event.shiftKey) || (currentIndex==n-1 && !event.shiftKey)) {
event.preventDefault();
if (el.attr('type')=='text') {
$.browser.msie ? "" : $(window).scrollTop(5000);
el.select().delay(800);
} else {
$.browser.msie ? "" : $(window).scrollTop(-5000);
el.focus().delay(800);
}
} else if (el.is('select')) {
event.preventDefault();
if (el.attr('type')=='text') {
el.select();
} else {
el.focus();
}
}
}
});
});
});
});
function setFocus() {
with (document.calculator)
var recap = document.getElementById(recaptured.value);
if (recap!=null) {
setTimeout(function() {
if (recap.getAttribute('type')=='text') {
recap.select();
} else {
recap.focus();
}
}, 1 );
}
}
I put my files available to download in my live link: http://www.presspound.org/calculator/ajax/sample.php