How could I optimise this js event? - javascript

I am trying to change the img src based on what button I have clicked.
My current approach is to add event listeners to each img id and change then change the image of the top img tag. The issue with this apporach is that I will have a lot of repetetive code especially when im adding more buttons.
So i would like someone to give advice or show me a different and better approach to do this. Im requesting help in only native javascript. Thanks.
document.getElementById("human").addEventListener("click", e => {
document.getElementById('imageChange').src = "dir/images/human.png";
})
document.getElementById("dwarf").addEventListener("click", e => {
document.getElementById('imageChange').src = "dir/images/dwarf.png";
})
document.getElementById("elf").addEventListener("click", e => {
document.getElementById('imageChange').src = "dir/images/elf.png";
})
<img id="imageChange" src="dir/images/human.png" alt="">
<div class="buttonContainer">
<img src="../dir/images/race/human_male.png" id="human" class="race human_container"></img>
<img src="../dir/images/race/dwarf_male.png" id="dwarf" class="race dwarf_container"></img>
<img src="../dir/images/race/elf_male.png" id="elf" class="race elf_container"></img>
</div>

You are right, that having multiple event handler is not a good solution. You can have single one attached to the common container. Something like this:
document.querySelector(".buttonContainer").addEventListener("click", e => {
if (e.target.tagName === 'IMG') {
document.getElementById('imageChange').src = e.target.src
}
})
.buttonContainer img {
height: 30px;
width: 30px;
}
<img id="imageChange" src="https://cdn2.iconfinder.com/data/icons/oxygen/64x64/mimetypes/unknown.png" alt="">
<div class="buttonContainer">
<img src="https://cdn0.iconfinder.com/data/icons/social-network-7/50/4-64.png" id="human" class="race human_container" />
<img src="https://cdn0.iconfinder.com/data/icons/social-network-7/50/6-64.png" id="dwarf" class="race dwarf_container" />
<img src="https://cdn0.iconfinder.com/data/icons/social-network-7/50/29-64.png" id="elf" class="race elf_container" />
</div>
It is necessary to check event target e.target.tagName === 'IMG' because click event bound like this might get triggered by clicking on elements other than images (so with no src).

Since you already know what you want to change the image to why not add it in the html as a data- attribute then just replace the current src with the data- value?

var clickables = document.querySelectorAll('.race');
function showImage(e) {
var src = e.target.src;
document.getElementById('imageChange').src = src;
}
for (var i = clickables.length - 1; i >= 0; i--) {
clickables[i].addEventListener('click', showImage);
}
.buttonContainer img {max-width: 100px}
<img id="imageChange" src="https://upload.wikimedia.org/wikipedia/en/e/ed/Nyan_cat_250px_frame.PNG" alt=""/>
<div class="buttonContainer">
<img src="https://vignette.wikia.nocookie.net/nyancat/images/f/ff/Mexinyan.gif/revision/latest?cb=20150409011153" id="human" class="race human_container"/>
<img src="http://www.nyan.cat/cats/original.gif" id="dwarf" class="race dwarf_container"/>
<img src="https://upload.wikimedia.org/wikipedia/en/e/ed/Nyan_cat_250px_frame.PNG" id="elf" class="race elf_container"/>
</div>

var imageNodes = document.getElementsByClassName("race");
for(var i = 0; i < imageNodes.length; i++){
imageNodes[i].addEventListener('click', (e) =>{
const imageId = e.target.id;
document.getElementById('imageChange').src = 'dir/images/' + imageId + '.png';
})
}

Related

Switch Image By Adding Text Before File Extension

I Hope you can help me.
When I click button it adds night before file extension ex.(interior-1.jpg to interior-1-night) but it only affects the first image which is interior-1.jpg.
What I want is to add "night" text before the file extension of all images under the "image" ID.
Here is my html code
<button onclick="changeMode()">switch</button>
<img id="image" src="interior-1.jpg"/>
<img id="image" src="interior-2.jpg"/>
<img id="image" src="interior-3.jpg"/>
<img id="image" src="interior-4.jpg"/>
<img id="image" src="interior-5.jpg"/>
Here is my javascript code
<script>
function changeMode() {
var filename = document.getElementById("image").src;
var modfilename = filename.replace(/(\.[\w\d_-]+)$/i, '-night$1');
document.getElementById("image").src = modfilename;
</script>
}
You should never use same id name on elements in the dom. Instead use same class name. To apply the src on all the img tag get all the tags using document.getElementsByClassName. Iterate over each element and change the src using a forEach loop
function changeMode() {
var filename = document.getElementsByClassName("image");
var a = '';
Object.values(filename).forEach((e) => {
a = e.src;
var modfilename = a.replace(/(\.[\w\d_-]+)$/i, '-night$1');
e.src = modfilename;
})
}
<button onclick="changeMode()">switch</button>
<img class="image" src="interior-1.jpg" />
<img class="image" src="interior-2.jpg" />
<img class="image" src="interior-3.jpg" />
<img class="image" src="interior-4.jpg" />
<img class="image" src="interior-5.jpg" />
The problem is that you are getting your element by GetElementById which only returns one element. You should change the id tag to name like this:
<img name="image" src="interior-1.jpg"/>
Then you should be able to retrieve all the elements using var els = document.getElementsByName('image');
now you need to change their file names, so
for (let i = 0; i<els.length; i++){
els[i].src = els[i].src.replace(/(\.[\w\d_-]+)$/i, '-night$1');
}
Here is my two cents. Use classes. This way you can query multiple elements instead of just one. Then apply your changes to each element using, in this case, a forEach.
The elements returend from document.querySelectorAll is a nodeList. That's why I use Array.prototype.forEach.call.
function changeMode() {
const imageNodes = document.querySelectorAll(".image");
Array.prototype.forEach.call(imageNodes, (node) => {
let modfilename = node.src.replace(/(\.[\w\d_-]+)$/i, '-night$1');
node.src = modfilename
})
}
<button onclick="changeMode()">switch</button>
<img class="image" src="interior-1.jpg"/>
<img class="image" src="interior-2.jpg"/>
<img class="image" src="interior-3.jpg"/>
<img class="image" src="interior-4.jpg"/>
<img class="image" src="interior-5.jpg"/>

Show img ALT text inside a div

I'm using this code to show img alt inside show div. The problem is that it doesn't update at every img change.
Is there any different addEventListener that I can use so that it will change the alt at every visible image on the screen and without the need to click?
var myImage = document.getElementsByTagName("img");
var text = document.getElementById("show");
for (var i = 0; i < myImage.length; i++) {
myImage[i].addEventListener('click',show);
}
function show(){
var myAlt = this.alt;
text.innerHTML = myAlt;
}
Thanks in advance.
Why not simply iterate over the images as soon as the HTML is ready? Simply attach a single listener to the DOMContentLoaded event:
document.addEventListener('DOMContentLoaded', () => {
let images = [...document.querySelectorAll('img[alt]')]
for (const image of images) {
const altDiv = document.createElement('div')
altDiv.textContent = image.getAttribute('alt')
image.parentNode.appendChild(altDiv)
}
})
<div>
<img src="http://lorempixel.com/200/200/" alt="my beautiful alt text" />
</div>
<div>
<img src="http://lorempixel.com/200/100/" alt="my beautiful alt text 2" />
</div>
If you want to make sure the images are loaded before showing the alt text, do the showText magic on the load event of each image:
document.addEventListener('DOMContentLoaded', () => {
let images = [...document.querySelectorAll('img[alt]')]
for (const image of images) {
image.addEventListener('load', (e) => {
const altDiv = document.createElement('div')
altDiv.textContent = image.getAttribute('alt')
image.parentNode.appendChild(altDiv)
})
}
})
<div>
<img src="http://lorempixel.com/200/200/" alt="my beautiful alt text" />
</div>
<div>
<img src="http://lorempixel.com/100/200/" alt="my beautiful alt text 2" />
</div>
<div>
<img src="http://lorempixel.com/200/100/" alt="my beautiful alt text 3" />
</div>

How to add css code in onmouseover="hover('')" [JS]

I can't adjust my text to be center aligned. I tried to put css code in onmouseover="hover('')" but it doesn't work. What is the get around for this?
Middle circle with id="content" that changes the tag on hover
<div id="circle">
<p id="content">
<b><span>Services</span></b>
</p>
</div>
JS Code that I included in the html tag to change content on hover
<a href="">
<div onmouseover="hover('<b>BPO</b>')" onmouseout="hover('<b>Services</b>')" class="scaling" id="circle-2">
<img src="/static/img/2.png" onmouseover="this.src='/static/img/2b.png'" onmouseout="this.src='/static/img/2.png'" style="margin-top:5px;" width=100px/>
</div>
</a>
<a href="">
<div onmouseover="hover('<b>Web Development</b>')" onmouseout="hover('<b>Services</b>')" class="scaling" id="circle-3">
<img src="/static/img/4.png" onmouseover="this.src='/static/img/4b.png'" onmouseout="this.src='/static/img/4.png'" style="margin-top:5px;" width=100px/>
</div>
</a>
JS Code that changes the content of the <p> tag
function hover(description) {
console.log(description);
document.getElementById('content').innerHTML = description;
}
everything is working properly but I can't adjust the text to be in the center regard less of the <p> tag length .
The main question is how do i add css code in onmouseover="hover('')"
What i want it to look like
what it looks like
Your code really needed a lot of cleaning up.
You should separate the HTML, CSS and JavaScript. After doing this, debugging is SO much easier and the code is much simpler to follow.
In addition, you had a great deal of duplication in your code. Again, using CSS and JavaScript can remove that redundancy. For example, styling is done with CSS, not HTML. Tags like <b> are deprecated and should no longer be used. By creating CSS styles that incorporate font-weight:bold and applying those styles properly, we can get rid of all the <b> and </b> tags.
// Get all DOM references:
var content = document.getElementById('content');
var cir2 = document.getElementById("circle-2");
var cir3 = document.getElementById("circle-3");
var img1 = document.getElementById("img1");
var img2 = document.getElementById("img2");
// Attach event handlers:
cir2.addEventListener("mouseover", function(){ hover('BPO') });
cir2.addEventListener("mouseout", function(){ hover('Services') });
cir3.addEventListener("mouseover", function(){ hover('Web Development') });
cir3.addEventListener("mouseout", function(){ hover('Services') });
img1.addEventListener("mouseover", function(e){ changeSource(e,'http://plumseattle.com/wp-content/uploads/2016/01/linkedin-logo.jpg') });
img1.addEventListener("mouseout", function(e){ changeSource(e, 'https://cdn3.iconfinder.com/data/icons/free-social-icons/67/facebook_circle_color-256.png') });
img2.addEventListener("mouseover", function(e){ changeSource(e, 'http://seeklogo.com/images/S/snapchat-logo-2D9C3E7ADA-seeklogo.com.png') });
img2.addEventListener("mouseout", function(e){ changeSource(e, 'https://www.seeklogo.net/wp-content/uploads/2011/06/Twitter-icon-vector-400x400.png') });
function hover(description) {
//console.log(description);
content.textContent = description;
}
function changeSource(evt, source){
evt.target.src = source;
}
content > span { font-weight: bold;}
.scaling { font-weight:bold; }
.img { margin-top:5px;width:100px; }
<div id="circle">
<p id="content">
<span>Services</span>
</p>
</div>
<a href="">
<div class="scaling" id="circle-2">
<img id="img1"
src="https://cdn3.iconfinder.com/data/icons/free-social-icons/67/facebook_circle_color-256.png"
class="img">
</div>
</a>
<a href="">
<div class="scaling" id="circle-3">
<img id="img2"
src="https://www.seeklogo.net/wp-content/uploads/2011/06/Twitter-icon-vector-400x400.png"
class="img">
</div>
</a>
Typically, if you want some element to listen to "mouseover" event, the best way to go is to use EventTarget#addEventListener. Just like this:
const node = document.getElementById('hover');
node.addEventListener('mouseover', () => {
node.innerText = `Last time mouseover'd at ${new Date()}.`;
});
So, now, you need to update children of #content and src attribute of an image under mouse cursor.
The HTML would look like this:
<p id="content">
Services
</p>
<a href="">
<div class="scaling" id="circle-2">
<img src="/static/img/2.png" />
</div>
</a>
<a href="">
<div class="scaling" id="circle-3">
<img src="/static/img/2.png" />
</div>
</a>
while JS code would look like this:
const content = document.getElementById('content');
const circle2 = document.getElementById('circle-2');
const circle3 = document.getElementById('circle-3');
circle2.addEventListener('mouseover', () => {
circle2.children[0].src = '/static/img/2b.png';
content.innerText = 'BPO';
});
circle2.addEventListener('mouseout', () => {
circle2.children[0].src = '/static/img/2.png';
content.innerText = 'Services';
});
circle3.addEventListener('mouseover', () => {
circle3.children[0].src = '/static/img/4b.png'
content.innerText = 'Web Development';
});
circle3.addEventListener('mouseout', () => {
circle3.children[0].src = '/static/img/4.png'
content.innerText = 'Services';
});
(check out this fiddle).

JavaScript - user selection function

I am new to JavaScript and I'm working on something. This is what I've reached so far and here is my code:
<!DOCTYPE html>
<html>
<head>
<title>Image Editor V 1.0</title>
<script>
function changeOpacity(newValue) {
document.getElementById("span").innerHTML = newValue*100 +'%';
document.getElementById("image1").style.opacity = newValue;
}
var color = true;
function imgColor() {
if (color) {
document.getElementById("image1").style.WebkitFilter = "grayscale(100%)";
color = false;
} else {
document.getElementById("image1").style.WebkitFilter = "none";
color = true;
}
}
function colorImg() {
document.getElementById("image1").style.WebkitFilter = "none";
}
function greyImg() {
document.getElementById("image1").style.WebkitFilter = "grayscale(100%)";
}
function userImage() {
var link = document.getElementById("userImg").value;
document.getElementById("image1").src = link;
}
</script>
</head>
<body>
<button onclick="colorImg()">Colored</button>
<button onclick="greyImg()">Greyscale</button>
<button onclick="imgColor()" >Alternate</button><br><br>
Opacity :<input type="range" min="0" max="1" value="1" step="0.2" onchange="changeOpacity(this.value)"/>
<span id="span">100%</span> <br><br>
Try your own image! <input id="userImg" type="text" placeholder="Enter url here">
<button onclick="userImage()">Go!</button>
<br><br>
<img class="myImages" id="image1" src="image4.jpg">
<img class="myImages" id="image2" src="image2.jpg">
<img class="myImages" id="image3" src="image3.jpg">
</body>
</html>
So far, the "Colored", "Greyscale", and "Alternate" buttons along with the opacity slider work as intended only on the first image (image1.jpg). Also, when the user inputs his own image, it replaces the first image and the functions work on it as intended. Here is what am trying to do:
1 - Let the user select which of the three images he wants to edit by clicking on it, then apply a border around it and use it in the other functions (greyscale and opacity). Here's what I tried (but didn't work):
<img class="myImages" id="image1" src="image4.jpg" onclick="selectImg(this.id)">
<img class="myImages" id="image2" src="image2.jpg" onclick="selectImg(this.id)">
<img class="myImages" id="image3" src="image3.jpg" onclick="selectImg(this.id)">
function selectImg(imgID) {
document.getElementById("imgID").style.border = 50px;
}
2 - When the user inputs his own image, I want it to replace all the 3 images I have displayed by default.
Your help is greatly appreciated. Thanks in advance!
You are missing quotes both on the id and the 50px. But it is better to define a style for the selection.
Then let a click handler first remove that style from all the images, except the clicked image, where it should set that style. The functions .classList.add and .classList.remove can be used for that.
Where you currently have document.getElementById('image1'), you would do instead:
document.querySelector('.selected')
Then you should also make sure that the page loads with one image selected, i.e. with the selected class.
Some other improvements make sure that when changing the selection, the opacity slider is also brought in line with that image's current opacity setting.
Here is a snippet that does all that:
function changeOpacity(newValue) {
document.getElementById("span").textContent = newValue*100 +'%';
document.querySelector(".selected").style.opacity = newValue;
document.querySelector('input[type=range]').value = newValue;
}
function getOpacity() {
return parseFloat(document.querySelector(".selected").style.opacity || '1');
}
function isColor() {
return document.querySelector(".selected").style.WebkitFilter !== "grayscale(100%)";
}
function imgColor() {
document.querySelector(".selected").style.filter =
document.querySelector(".selected").style.WebkitFilter =
isColor() ? "grayscale(100%)" : "none";
}
function colorImg() {
if (!isColor()) imgColor()
}
function greyImg() {
if (isColor()) imgColor()
}
function userImage() {
document.querySelector(".selected").src = document.getElementById("userImg").value;
}
// Add this function, and call it on click on an image
function select(img) {
Array.from(document.querySelectorAll('.myImages')).forEach(
myImg => myImg === img ? myImg.classList.add('selected')
: myImg.classList.remove('selected')
);
// bring opacity slider in line with selected image
changeOpacity(getOpacity());
}
.selected {
border: 1px solid;
}
<button onclick="colorImg()">Colored</button>
<button onclick="greyImg()">Greyscale</button>
<button onclick="imgColor()">Alternate</button><br><br>
Opacity :<input type="range" min="0" max="1" value="1" step="0.2" onchange="changeOpacity(this.value)"/>
<span id="span">100%</span> <br><br>
Try your own image! <input id="userImg" type="text" placeholder="Enter url here">
<button onclick="userImage()">Go!</button>
<br><br>
<img class="myImages selected" id="image1" onclick="select(this)"
src="//cdn.sstatic.net/Sites/stackoverflow/company/img/logos/se/se-icon.png?v=93426798a1d4">
<img class="myImages" id="image2" onclick="select(this)"
src="http://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png?v=c78bd457575a">
<img class="myImages" id="image3" onclick="select(this)"
src="http://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/sf/sf-icon.png?v=6c3100d858bb">
First - you are not using that imgID, but String like that variable. Change to:
function selectImg(imgID) {
document.getElementById(imgID).style.border = 50px; //notice no quotes for imgID
activeImage = imgID; //set activeImage ID
}
And then when you are doing something to an image, don't use "image1", but activeImage that is global variable (defined outside and before functions).
And as for new uploaded image:
Put it into another div and work with such algorithm -
when (uploaded_new)
hide default pics
show DIV with new image
activeImage = uploadedPic

Insert <div> for every 5 elements using Javascript

I have a simple list of images that is being controlled via a CMS (ExpressionEngine). Like this:
<div class="wrapper">
<img src="#" />
<img src="#" />
<img src="#" />
<img src="#" />
<img src="#" />
<img src="#" />
<img src="#" />
<img src="#" />
</div>
What I want to do is for every 5 images, wrap them in a div with a class of "slide." To look like this:
<div class="wrapper">
<div class="slide">
<img src="#" />
<img src="#" />
<img src="#" />
<img src="#" />
<img src="#" />
</div>
<div class="slide">
<img src="#" />
<img src="#" />
<img src="#" />
</div>
</div>
The reason I am not manually coding the "" in is because of a jQuery content slider that I am using which requires every 5 images to be wrapped inside a slide div.
I'm not sure how what the code in ExpressionEngine would be to do this, but I figure it might just be easier to use Javascript to wrap every 5 images with the div. And to just have ExpressionEngine output the different images all at once.
Any help?
Here's one way:
Example: http://jsfiddle.net/T6tu4/
$('div.wrapper > a').each(function(i) {
if( i % 5 == 0 ) {
$(this).nextAll().andSelf().slice(0,5).wrapAll('<div class="slide"></div>');
}
});
Here's another way:
Example: http://jsfiddle.net/T6tu4/1/
var a = $('div.wrapper > a');
for( var i = 0; i < a.length; i+=5 ) {
a.slice(i, i+5).wrapAll('<div class="slide"></div>');
}
You can just create a div for every fith element and move the links into them using the append method:
var wrapper = $('.wrapper');
var div;
$('a', wrapper).each(function(i,e){
if (i % 5 == 0) div = $('<div/>').addClass('slide').appendTo(wrapper);
div.append(e);
});
Demo: http://jsfiddle.net/Guffa/ybrxu/
I think this would do that:
var links = $('.wrapper').children();
for (var i = 0, len = links.length; i < len; i += 5) {
links.slice(i, i + 5).wrapAll('<div class="slide"/>');
}
Try this:
$(function(){
var curDiv = null;
var mainDiv = $("div.wrapper");
$("span", mainDiv).each(function(i, b){
if(i%5 == 0) {
curDiv = $("<div class='slide'/>").appendTo(mainDiv);
}
curDiv.append(b);
});
});
You need to use jQuery slice with wrap
Check this question
Use slice() to select the element subset then wrapAll() to wrap the div around them. Here's a function that does that.
var wrapEveryN = function(n, elements, wrapper) {
for (var i=0; i< elements.length; i+=n) {
elements.slice(i,i+n).wrapAll(wrapper);
}
}
wrapEveryN( 5, $(".wrapper a"), '<div class="slide"></div>' );
Demo: http://jsfiddle.net/C5cHC/
Note that the second parameter of slice may go out of bounds, but jQuery seems to handle this automatically.

Categories

Resources