Updating array length after removing element - javascript

Disclaimer: I'm a total noob. Please bear with me ;)
I am working on a little project using CSS animations and manipulating the DOM with JS. By clicking the animated elements, they are removed from the DOM.
When all items are removed, a video element will be added.
The latter is where I am struggling with. The elements are removed from the DOM but the length of the cat array won't get updated, so it's never reaching 0 (when the video would be added).
This is an excerpt of my project:
https://codepen.io/miliberlin/pen/BaawrKg
(PS: If anybody can also help me figure out why .cat:hover {transform: rotate(360deg);} isn't working in my CSS file, I would be forever grateful)
for (i = 0; i < cat.length; i++) {
cat[i].addEventListener('click', function() {
this.parentNode.removeChild(this);
});
}
if (cat.length === 0) {
const iframe = document.createElement("iframe");
iframe.src = "https://www.youtube.com/embed/SB-qEYVdvXA";
iframe.width = "560";
iframe.height = "315";
document.getElementById("wrapper").appendChild(iframe);
}

In this case, it's better to work with HTMLCollection that is a live view on DOM instead of NodeList returned from querySeletorAll that is static.
Also, javascript isn't reactive, so code in if (cat.length === 0) {...} won't magically run when cat is empty. You have to call it yourself when this happens:
const cat = document.getElementsByClassName("cat");
for (let i = 0; i < cat.length; i++) {
cat[i].addEventListener('click', function() {
this.parentNode.removeChild(this);
if (cat.length === 0) {
whenCatEmpty()
}
});
}
function whenCatEmpty() {
const iframe = document.createElement("iframe");
iframe.src = "https://www.youtube.com/embed/SB-qEYVdvXA";
iframe.width = "560";
iframe.height = "315";
document.getElementById("wrapper").appendChild(iframe);
}
If anybody can also help me figure out why .cat:hover {transform: rotate(360deg);} isn't working
You're using transform both in the animation and in .cat:hover. CSS declarations overwrite each other. You can move cats in the animation with top property (which is a less performant than transform: translate but I don't see any other way to make it work with transform: rotate
#keyframes motion{
to{ top: 1500px }
}

In this case you should use array.splice() method
It takes 2 arguments. First - start index (i, in your case) and number of elements to delete.
You can read about it here:
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
for (i = 0; i < cat.length; i++) {
cat[i].addEventListener('click', function() {
this.parentNode.removeChild(this);
cat.splice(i,1); // add this to your code
});
}
if (cat.length === 0) {
const iframe = document.createElement("iframe");
iframe.src = "https://www.youtube.com/embed/SB-qEYVdvXA";
iframe.width = "560";
iframe.height = "315";
document.getElementById("wrapper").appendChild(iframe);
}

With "i" you have the index of array that you want delete, so you can use method splice for array, for example:
var array= ["hi", "everything", "ok"];
array.splice(1,1) //the first parameter is the index and the second is the number of elements that you want delete.
EDIT:
for (i = 0; i < cat.length; i++) {
cat[i].addEventListener('click', function() {
this.parentNode.removeChild(this);
cat.splice(i,1);
});
}
if (cat.length === 0) {
const iframe = document.createElement("iframe");
iframe.src = "https://www.youtube.com/embed/SB-qEYVdvXA";
iframe.width = "560";
iframe.height = "315";
document.getElementById("wrapper").appendChild(iframe);
}

Related

Trying to automate a slideshow in javascript

Ive looked other questions similiar to my issue but ive been unable understand and resolve issue.
<script type="text/javascript">
var images = new Array();
images[0] = "http://ed-moore.net/html/assets/slideshow0.jpg";
images[1] = "http://ed-moore.net/html/assets/slideshow1.jpg";
images[2] = "http://ed-moore.net/html/assets/slideshow2.jpg";
images[3] = "http://ed-moore.net/html/assets/slideshow3.jpg";
var current = 0;
function changeImage(inc) {
current += inc;
document.getElementById("target").src = images[Math.abs(current)%images.length];
setTimeout("changeImage()",1000);
}
Either you haven't posted all of the relevant code, or you're missing something like:
changeImage(1);
To kick off your slideshow and get it started.
I would definitely not just use purely JavaScript for this. Try and make sure your html is where the content is housed, your CSS is where majority of styling is, and then use you JS to make the interactivity and movement. All that to say, kick the actual images out of there, leave them in html. Then create a class in CSS for showing the image, then a class for hiding. Then use you JavaScript to add/remove the classes.
Answer by Héctor Manuel Martinez Durán will solve the issue,
But if you still want to use pure Javascript, you can read my answer
1) Instead of using setTimeout, try to use setInterval (setTimeout will execute only once, but setInterval will execute until the page is closed)
2) You did not execute the function, you need to run the function with an argument inc
so the code will be:
var images = new Array();
images[0] = "http://ed-moore.net/html/assets/slideshow0.jpg";
images[1] = "http://ed-moore.net/html/assets/slideshow1.jpg";
images[2] = "http://ed-moore.net/html/assets/slideshow2.jpg";
images[3] = "http://ed-moore.net/html/assets/slideshow3.jpg";
var current = 0;
function changeImage(inc) {
current += inc;
document.getElementById("target").src = images[Math.abs(current)%images.length];
}
setInterval(function() {
changeImage(1);
}, 1000);
HTML Slideshow?
Well, look this https://www.w3schools.com/w3js/w3js_slideshow.asp
Use the Javascript library W3.JS
https://www.w3schools.com/w3js/default.asp
Or use pure JS
var slideIndex = 0;
carousel();
function carousel() {
var i;
var x = document.getElementsByClassName("mySlides");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
slideIndex++;
if (slideIndex > x.length) {slideIndex = 1}
x[slideIndex-1].style.display = "block";
setTimeout(carousel, 2000); // Change image every 2 seconds
}

element.style.display is not what rendered in the browser

Probably a duplicate question but can not find the answer.
element.style.display is not what rendered in the browser.
Instead of returning the actual value (ie. block or inline etc), it returns empty. Tested in Chrome 56.0.2924.87 (64-bit).
How do I get the actual rendered value?
function displayStyle(aEvent) {
aEvent.target.textContent=aEvent.target.style.display;
}
window.onload = function() {
var top_array = document.getElementsByClassName("top");
for(var i = 0; i < top_array.length; i++)
{
top_array[i].addEventListener("click", displayStyle, false);
}
}
.top{
background-color:#FFF8DC;
}
<div class="top">top (click it and it will disappear because its style.display is empty)</div>
CSS styles are not available to JavaScript unless they have been formerly set in JavaScript or they have been hardcoded as inline styles.
Use getComputedStyle() instead:
function displayStyle(aEvent) {
var target = aEvent.target;
target.textContent = window.getComputedStyle(target).getPropertyValue('display');
}
window.onload = function() {
var top_array = document.getElementsByClassName("top");
for (var i = 0; i < top_array.length; i++) {
top_array[i].addEventListener("click", displayStyle, false);
}
}
.top {
background-color: #FFF8DC;
}
<div class="top">top (click it and it will now show "block" since we're getting its computed style.)</div>
Works if you set it directly in style attribute:
function displayStyle(aEvent) {
aEvent.target.textContent=aEvent.target.style.display;
}
window.onload = function() {
var top_array = document.getElementsByClassName("top");
for(var i = 0; i < top_array.length; i++)
{
top_array[i].addEventListener("click", displayStyle, false);
}
}
.top{
background-color:#FFF8DC;
}
<div class="top" style="display: block;">top (click it and it will disappear because its style.display is empty)</div>
Obs.: setting it on CSS also doesn't work.
I still don't know why, anyway.
Now I know, thanks to Rick Hitchcock's answer.

How to change the opacity on an element dynamically using javascript

i made a function that change the opacity of an element, but you know it is not working, Following is my code:
function _opacity(ele, opacity,addOpac , delay ){
ele = document.getElementById(ele);
var CurrentOpacity = ele.style.opacity,
ChangeInOpacity = setInterval(function(){
if (CurrentOpacity > opacity ) { decrease();};
if (CurrentOpacity < opacity) { increase();};
if (CurrentOpacity == opacity) { stopInc();};
}, delay),
increase = function(){
ele.style.opacity = CurrentOpacity;
CurrentOpacity = CurrentOpacity+addOpac;
},
decrease =function(){
ele.style.opacity = CurrentOpacity;
CurrentOpacity = CurrentOpacity-addOpac;
},
stopInc = function(){
clearInterval(ChangeInOpacity);
};
}
one of the foremost feature of this function is that is doesn't uses any loop.
this ideology of using setInterval works perfectly in changing the width and height of element. But here this function is not functioning.
What i know is that it is not adding any style attribute to the element which is passed to the above function
what is the mistake here because of which this is not working?
thanks in advance.
There are a few problems there:
To get the current opacity of the element, you need to use the getComputedStyle function (or currentStyle property on oldIE), not .style.opacity. The latter only has a value if it's been assigned explicitly, rather than implicitly through style sheets.
The value will be a string, so you need to convert it to a number.
It's unlikely that you'll exactly match the target opaccity, so you need to just stop when you cross the target.
You don't put ; at the end of if statements, so remove those.
You assign the opacity, but then increment it, and then later the incremented value is what you check to see if you're done, so even if it weren't for #3, you'd stop early.
In JavaScript, the overwhelming convention is to start local variable names with a lower-case letter. I changed the name of your timer handle to timer.
Your best bet is to figure out what direction you're going, then stop when you pass the target:
// Polyfill getComputedStyle for old IE
if (!window.getComputedStyle) {
window.getComputedStyle = function(element) {
return element.currentStyle;
}
}
// Your _opacity function
function _opacity(ele, opacity, addOpac, delay) {
var direction;
ele = document.getElementById(ele);
// Determine direction
direction = +getComputedStyle(ele).opacity < opacity ? 1 : -1;
var timer = setInterval(function() {
// Get the *computed* opacity
var current = +getComputedStyle(ele).opacity;
if (direction > 0) {
if (current < opacity) {
increase(current);
} else {
stopInc();
}
}
else {
if (current > opacity) {
decrease(current);
} else {
stopInc();
}
}
}, delay),
increase = function(current) {
// Increase, but don't go past target
ele.style.opacity = Math.min(current + addOpac, opacity);
},
decrease = function(current) {
// Decrease, but don't go past target
ele.style.opacity = Math.max(current - addOpac, opacity);
},
stopInc = function() {
clearInterval(timer);
};
};
// Run
_opacity("target", 0.3, 0.05, 50);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<div id="target">this is the element</div>
you can do this:
ele.style.opacity = "0.2";// some desired value but string if for all browsers.
for more info see this post:Setting opacity of html elements in different browsers

Multiple Image fadeIn onLoad (at the same time)

I want to fade in multiple images at the same time as the page loads. Just like this website does it: http://www.struckaxiom.com/work. I have the script to do it only on one image, but I want to have more images included.
This is the single photo script. Please help.
document.write("<style type='text/css'>#thephoto {visibility:hidden;}</style>");
function initImage() {
imageId = 'thephoto'
image = document.getElementById(imageId);
setOpacity(image, 0);
image.style.visibility = "visible";
fadeIn(imageId,ImageId2,0);
}
function fadeIn(objId, opacity) {
if (document.getElementById) {
obj = document.getElementById(objId);
if (opacity <= 100) {
setOpacity(obj, opacity);
opacity += 10;
window.setTimeout("fadeIn('"+objId+"',"+opacity+")", 100);
}
}
}
function setOpacity(obj, opacity) {
opacity = (opacity == 100)?99.999:opacity;
// IE/Win
obj.style.filter = "alpha(opacity:"+opacity+")";
// Safari<1.2, Konqueror
obj.style.KHTMLOpacity = opacity/100;
// Older Mozilla and Firefox
obj.style.MozOpacity = opacity/100;
// Safari 1.2, newer Firefox and Mozilla, CSS3
obj.style.opacity = opacity/100;
}
window.onload = function() {initImage()}
// -->
</script>
Thanks!
Simple array and loop are all you need.
First, add such array on top of the code:
var images = [ "thephoto1", "thephoto2", "thephoto3" ];
(With the ID of all desired images)
Next change the function name to initImages to reflect the fact it will initialize more than one image and finally add that loop:
function initImages() {
for (var i = 0; i < images.length; i++) {
imageId = images[i];
image = document.getElementById(imageId);
setOpacity(image, 0);
image.style.visibility = "visible";
fadeIn(imageId, 0);
}
}
That's it, no need to touch the other functions.
Live test case with cute cats: http://jsfiddle.net/yahavbr/e863X/ :-)
You could just wrap all of your images in a single container like this:
<div id="imageContainer">
<img src="img1.jpg">
<img src="img2.jpg">
<img src="img2.jpg">
</div>
Change your CSS to this:
<style type='text/css'>#imageContainer {visibility:hidden;}</style>
Change your first function to this:
function initImage() {
containerId = 'imageContainer'
container = document.getElementById(containerId);
setOpacity(container, 0);
container.style.visibility = "visible";
fadeIn(containerId,0);
}
By running the fading effect on the container you can then add as much content to the container and it will all fade in together and you never have to update your code.
The way they are doing is using jQuery (an excellent implementation). All of the images are in the same container and are selected using the jQuery class selector. Then they fade in all elements that fit within the viewable area. Their js file is not minimized so you could reverse engineer most of that functionality. The important thing to note is not that it is showing each row at a time but every element that fits in the viewing area. Their key function looks like this:
var elTop = $(el).offset().top - $(window).scrollTop();
var elHeight = $(el).height();
// if between top of footer and top of window
if (elTop + elHeight > 40 && elTop < $(window).height()) {
if ($.inArray($(el).attr("data-unique-id"), elementsInView) < 0) {
addToView(el);
}
} else {
if ($.inArray($(el).attr("data-unique-id"), elementsInView) >= 0) {
removeFromView(el);
}
}
addToView and removeFromView add and remove the element from an array, then fade is executed on the array.

fadeIn fadeOut effect with Raw javascript

I am currently working on a experiment with RAW Javascript. I was wondering why it is not working. In fact I have scratched my head until there is no hair left... :P.
I am making a table with TR elements to be hovered over with some Javascript event. I think you will know exactly what I mean if you look at the code. The point is to get stuff to fade out first and then fade in afterwards when it reaches zero.
I am a beginner and maybe this can be done with the existing code. But of course if it is possible in another way of programming, I am open for suggestions.
THE CODE:
window.onload = changeColor;
var tableCells = document.getElementsByTagName("td");
function changeColor() {
for(var i = 0; i < tableCells.length; i++) {
var tableCell = tableCells[i];
createMouseOutFunction(tableCell, i);
createMouseOverFunction(tableCell, i);
}
}
function createMouseOverFunction(tableCell, i) {
tableCell.onmouseover = function() {
tableCell.style.opacity = 1;
createMouseOutFunction(tableCell, i);
}
}
function createMouseOutFunction(tableCell, i) {
var OpacitySpeed = .03;
var intervalSpeed = 10;
tableCell.onmouseout = function() {
tableCell.style.opacity = 1;
var fadeOut = setInterval(function() {
if(tableCell.style.opacity > 0) {
tableCell.style.opacity -= OpacitySpeed;
} else if (tableCell.style.opacity <= 0) {
clearInterval(fadeOut);
}
}, intervalSpeed);
var fadeIn = setInterval(function(){
if(tableCell.style.opacity <= 0){
tableCell.style.opacity += OpacitySpeed;
} else if(tableCell.style.opacity == 1){
clearInterval(fadeIn);
}
}, intervalSpeed);
}
}
Here is working example of your code (with some corrections)
http://www.jsfiddle.net/gaby/yVKud/
corrections include
Start the fadein once the fadeout is completed (right after you clear the fadeout)
ues the parseFloat() method, because the code failed when it reached negative values.
remove the createMouseOutFunction(tableCell, i); from the createMouseOverFunction because you assign it in the initial loop.
I think you'll probably need to use the this keyword in some of your event binding functions. However I haven't myself got your code to work.
I would recommend using a library such as jQuery. In particular .animate will probably be of use here.

Categories