Multiple fadeToggle()'s in a for loop? - javascript

I have a "projects" object. Each project has a div and another div inside it, which is hidden. I want to create multiple fadeToggle() effects, so that for each project - clicking the first div will make the one inside it show up.
I tried to do this with a simple for loop.
projects.display = function() {
for (var i = 0; i < projects.length; ++i) {
var projectID = "#projects-" + i;
var moreInfoID = "#projects-" + i + "-more";
// assign IDs for current project
$(projectID).click(function() {
$(moreInfoID).fadeToggle();
});
}};
The result of this code is that clicking any of the main div's triggers the hidden div of the LAST project to show up.
How can I make it so that clicking a main div will call fadeToggle() for the designated hidden div?

Do not believe for loop is necessary. You should be able to substitute attribute starts with and attribute ends with selectors, :has() or :not()
$("[id^=projects]:has([id$=more])").click(function() {
$("[id$=more]", this).fadeToggle()
})

Related

Adding 100 buttons in a div

I am following along a Javascript tutorial and I have to add in 100 buttons inside of a div using Javascript.
At first, I tried doing something like this:
const btn = document.createElement('button');
const div = document.querySelector('div');
btn.innerText = 'Hey!';
for (let i = 0; i < 100; i++) {
div.appendChild(btn);
}
And this ended up only making 1 button. However, if I repeat the same code it just appends buttons after the previous one. However, this approach:
for (let i = 0; i < 100; i++) {
const btn = document.createElement('button');
const div = document.querySelector('div');
btn.innerText = 'Hey!';
div.appendChild(btn);
}
does the job. I can't seem to understand why the 2nd one works and the 1st one doesn't.
From my understanding, the first approach seemed better because I wasn't making the same variables over and over again. However that only ends up in me making just one button instead of 100.
First example won't work, cause it is just how method appendChild works. According to MDN. It just moves the node/element from its current position to specified. So your first example is just renewing the position of only one node, cause you've created only one div
Second example creates div every time, so it is a new element, which is stored inside your parent element.
The code that creates element is document.createElement and You call it ones in first example, hence only one element is created.
appendChild does not creates an element, it appends already created element to some parent.
If it is already appended, then does nothing
because in the first case you are trying to append the same DOM object 100 times, but have to create a new one each time

Unable to change the class of a div using JavaScript

So I got into JavaScript and tried setting up the following scenario:
I have 2 Buttons on my Site (IDs are buttonWebdev and buttonUXUI), which should trigger an Action when they are hovered upon. If buttonWebdev is hovered upon, it should hide all p', h3's and imgs with the class "classWeb". I wrote this code to do it, but it doesn't work:
HTML:
<h3 class="classWeb">Editierbare Inhalte</h3>
<p class="classWeb">Test</p>
<button class="buttonImg" id="buttonWebdev"><img src="./img/buttonWebdev.png" /></button>
<script type="text/javascript">
var button = document.getElementById('buttonWebdev');
var classWeb = document.getElementsByClassName('classWeb');
button.onmouseover = function() {
classWeb.className = 'webdev';
}
CSS:
.classWeb.webdev {
display: none;
}
First, since there can be more than one element with a given class on a page, getElementsByClassName returns a list of elements instead of a single element. You’ll need to perform your action on every element of that list, with a for…of loop, for example:
for (let element of classWeb) {
element.className = 'webdev';
}
(for…of is relatively new, though, so you might have to use a regular for loop depending on your target browsers.)
After fixing this, you’ll run into another problem. When you assign to className like that, you’re setting the entire list of classes on an object. If the list of classes is 'webdev', it no longer includes 'classWeb'. Modern browsers support an API to add a class without affecting the rest:
for (let element of classWeb) {
element.classList.add('webdev');
}
The way to diagnose these sorts of problems is by opening up your browser’s developer tools, looking for JavaScript errors in the console, and looking at the state of the elements you’re trying to affect in the document tree.
document.getElementsByClassName('classWeb'); this gives collection & to add classes you need to iterate over them & then apply classes.
classWeb[0].className = 'webdev'; would reset class
either use classWeb[i].className += ' webdev'; or classWeb[i].classList.add('webdev');
See below working example
var button = document.getElementById('buttonWebdev');
var classWeb = document.getElementsByClassName('classWeb');
button.onmouseover = function() {
for (var i = 0; i < classWeb.length; i++)
classWeb[i].className += ' webdev';
}
.classWeb.webdev {
display: none;
}
<h3 class="classWeb">Editierbare Inhalte</h3>
<p class="classWeb">Test</p>
<button class="buttonImg" id="buttonWebdev">hover over me</button>
Firstly, the
document.getElementsByClassName('classWeb');
will give you a LIVE list of all the matched elements. That means that when you reassign the class like so:
classWeb[0].className = 'webdev';
the element will be removed from the list, as it no longer corresponds to the original command which was to find all elements with a specific class (which you overrode with 'webdev').
An easier and more friendly api is querySelectorAll which mimics the jQuery selector (which uses css selectors to find elements, thats why there is a # for an id and a . for a class name). The example below shows, how to use it.
var button = document.querySelector('#buttonWebdev');
var classWeb = document.querySelectorAll('.classWeb');
button.onmouseenter = function() {
for (var i = 0; i < classWeb.length; i++) {
classWeb[i].className = 'webdev';
}
}
ps. The querySelectorAll is not a live list, so items will not disappear after you change their class.
ps2. Use onmousenter instead of onmouseover as the onmouseenter is only called when the mouse starts hovering over an element, while onmouseover will be called on every mouse move over the element (even if already hovering).
Good luck!

Bring to front with appendChild - can't use text field (JavaScript)

I want to use appendChild to bring div elements to front in a simple web application. I listen for click or mousedown (I have tried both) and then reappend whatever has been clicked to the main div container. Like this:
JavaScript
document.querySelector("#container").addEventListener("click", function(event) {
for (var i = 0; i < this.children.length; i += 1) {
if (this.children[i].contains(event.target)) {
this.appendChild(this.children[i]);
}
}
});
However, when I try this in Firefox the text fields in the div elements becomes unselectable. You can't put the marker in the text fields. It works in Chrome but not in Firefox. What could be the cause of this and how can I fix it?
Currently, because of this problem, I am using a different method with z index. But I would prefer to use appendChild as it has other advantages.
Thanks in advance.
This is a direct consequence of the appendChild which temporarily removes from DOM the child that contains the clicked Element (including when clicking to select text or to put caret / focus in a text input field), to re-append it at the end of the div children (but the text selection is now gone).
A simple workaround would be to leave the clicked child in DOM, but move its below siblings up until the clicked one is the last child.
document.querySelector("#container").addEventListener("click", function(event) {
var found,
children = this.children;
for (var i = 0; i < children.length; i += 1) {
if (children[i].contains(event.target)) {
//this.appendChild(children[i]); // Do not detach from DOM.
found = children[i]; // Leave it in place.
} else if (found) {
this.insertBefore(children[i], found); // Swap with found sibling.
}
}
});
Demo: https://jsfiddle.net/x53eh5b3/1/

Jquery Mobile Filter system, can't hide multiple divs

I'm making a Jquery Mobile app and have a page with 15 or so divs with class', I'm trying to make a filtering system so that when you press a button some of these divs disappear depending on the class. There are 3 groups and they all have an "all" class to display everything making 4 classes total.
Unfortunately most of the js I use never works even if I set up a jsfiddle for jquery mobile when I put it into my app it doesn't seem to work.
I wanted to use
function show(target) {
document.getElementsByClassName(target).style.display = 'block';
}
function hide(target) {
document.getElementsByClassName(target).style.display = 'none';
}
But that doesn't work whereas document.getElementById seems to work fine. However obviously I can only hide/show 1 div per button..
I was wondering if there was a work around for this or something completely different I should try?
Here's a jsfiddle of what I have: http://jsfiddle.net/tzcx7gky/
It's completely broken in jsfiddle but it works fine in my code, which is odd..
You don't need seperate hide - show functions. The following would take care of all.
$('a').on("click",function()
{
$("#scroll_content div").hide(); // initially hide all divs inside the element with id = scroll_content
var target = $(this).text().toLowerCase(); // find the class you wish to show using the text of the a tag clicked ( I would prefer using data-attr in this case but I'll leave the choice upto you.
$("." + target).show(); // show the element with the class target.
});
Working example : http://jsfiddle.net/tzcx7gky/2/
getElementsByClassName returns an array of elements. So you would have to itterate over the array and then set the display property on each one. Since you are already using jQuery you can use it to do it for all the elements.
function show(target) {
/* jQuery uses CSS selectors to grab elements
so we have to prefix the target with "."
Alternativley we could pass in the whole selector in the
function so we don't have to prefix it e.g.
show('.all')
$(target).show();
*/
$("."+target).show();
}
function hide(target) {
$("."+target).hide();
}
Here is the same implementation in the vanilla js framework
function show(target) {
var elements = document.getElementsByClassName(target);
elements.forEach(function(element){element.style.display = 'block';});
}
function hide(target) {
var elements = document.getElementsByClassName(target);
elements.forEach(function(element){element.style.display = 'none';});
}
note that getElementById returns a single element since id's are unique and there should only be one element with one id on the page. That is why it was working for you.

Toggling elements with JavaScript

I want to toggle a div element (expand/collapse) when clicked.
I have many div elements, on click to new element, I want to collapse the previous one and expand the current clicked one.
I tried using static type variable to save the instance of previous div tag and compared with the current selection, but I don't know why is it not working.
Searching about this, I got similar code idea to collapse all div and then expand the current selected only, but I want to just toggle the previous one with new one, not collapse all div and expand the selected (though I would be using it if other way is not possible)
Can it be done using static variables of js?
At its simplest, you can simply do something like this:
var divs = document.getElementsByTagName('div'),
collapseClass = 'collapsed',
current = divs[0];
// Hide all elements except first, add click event hander
for(var i = 0, len = divs.length; i < len; i++){
divs[i].onclick = function(){
if(this !== current){
toggle(this, current);
current = this;
}
};
if(i > 0) toggle(divs[i]);
}
This will store the current element in a variable, then toggle it when another element is clicked. It also uses an if statement to check if the currently clicked element is the one currently visible element, and only toggles if its not.
See a working demo of this here: http://jsfiddle.net/GaxvM/
You can assign a unique ID to each of the elements and use document.getElementById to identify both elements, and then collapse one/expand the other.
If you number them sequentially (like div1, div2, div3, etc) you could do something like:
function colexp(div_id){
div_2_collapse = document.getElementById(div_id);
next_div = div_id.substr(0,3) + parseInt(div_id.substr(3))+1;
div_2_expand = document.getElementById(next_div);
hide(div_2_collapse);
show(div_2_expand);
}

Categories

Resources