How i can switch between icons with javascript when clicked? - javascript

How can I switch between icons with javascript when clicked?
function mode() {
var moon = document.getElementById("mode");
moon.src = "https://img.icons8.com/sf-black-filled/35/fffffe/moon-symbol.png";
moon.id = "lightmode";
moon.onclick = lightmode();
}
function lightmode() {
var sun = document.getElementById("lightmode");
sun.src = "https://img.icons8.com/sf-black-filled/34/000000/sun.png";
sun.onclick = mode();
}
body { background-color:grey }
<div class="nav-icons">
<img id="mode" class="moon" onclick="mode()" src="https://img.icons8.com/sf-black-filled/35/fffffe/moon-symbol.png">
<img id="notification" src="https://img.icons8.com/ios-glyphs/34/fffffe/notification-center.png" alt="" srcset="">
</div>

You are setting up event listeners in an incorrect manner
Here is a toggle using classes and data attributes
const srcs = {
"dark": "https://img.icons8.com/sf-black-filled/35/fffffe/moon-symbol.png",
"light": "https://img.icons8.com/sf-black-filled/34/000000/sun.png"
};
const modeToggle = document.getElementById("modeToggle");
modeToggle.addEventListener("click", function() {
let mode = this.dataset.mode;
mode = mode === "dark" ? "light" : "dark"; // toggle
this.src = srcs[mode]; // image
this.dataset.mode = mode; // save in element
document.body.classList.toggle("dark",mode==="dark"); // toggle page too
})
document.body.classList.toggle("dark",modeToggle.dataset.mode==="dark"); // initialise the page, possibly from localStorage
body {
background-color: grey
}
body.dark {
background-color: black;
}
<div class="nav-icons">
<img id="modeToggle" data-mode="light" src="https://img.icons8.com/sf-black-filled/34/000000/sun.png">
<img id="notification" src="https://img.icons8.com/ios-glyphs/34/fffffe/notification-center.png" alt="" srcset="">
</div>

this may solve your problem, please use proper names for your functions, e.g instead of mode() use changeMode() as a name
javascript:
let isChanged = false;
let mode = document.querySelector('#mode');
function changeMode(){
isChanged = !isChanged;
if(isChanged) {
mode.src = "https://img.icon8.com/sf-black-filled/35/ffffffe/moon-symbol.png"
} else {
mode.src = "https://img.icon8.com/sf-black-filled/34/000000/sun.png"
}
}

Toggling between two different images/icons/styles is very simple in Javascript. You could, for instance, create a simple Object literal with name/value pairs for both icons as per the following. A simple ternary operator determines what the src should be based upon the current src
document.querySelector('.nav-icons > img.sunmoon').addEventListener('click',function(e){
let icons={
sun:'https://img.icons8.com/sf-black-filled/34/000000/sun.png',
moon:'https://img.icons8.com/sf-black-filled/35/fffffe/moon-symbol.png'
};
this.src = this.src==icons.moon ? icons.sun : icons.moon;
});
body {
background-color: grey
}
<div class="nav-icons">
<img class="sunmoon" src="https://img.icons8.com/sf-black-filled/35/fffffe/moon-symbol.png" />
<img id="notification" src="https://img.icons8.com/ios-glyphs/34/fffffe/notification-center.png" alt="" srcset="" />
</div>

Related

Changing image onclick then changing it back in js

fiddle:
https://jsfiddle.net/0r7v923u/2/
<img src="https://dirask.com/static/bucket/1631898942509-VMYrnXyYZv--image.png" class="logo" alt="Banner" onclick="ratesD(this)" />
JS:
function ratesD(image) {
if (img.attr('src') == "https://dirask.com/static/bucket/1631898942509-VMYrnXyYZv--image.png") {
image.src = "https://dirask.com/static/bucket/1633375165831-yjQ7G6WQeL--image.png";
} else {
image.src = "https://dirask.com/static/bucket/1631898942509-VMYrnXyYZv--image.png"
}
}
I am simply trying to change the image back and forth on click. The function below changes it but it does not return to the previous image:
function ratesD(image) {
image.src = 'https://dirask.com/static/bucket/1633375165831-yjQ7G6WQeL--image.png';
}
I thought it only needs to change using img.attr('src') == what do I need to change for the if condition?
First you are trying to access the wrong property of the image object (attr instead of src) and the second function is not checking the current image source before changing it. To fix this, the function should check the current src of the image and change it to the other URL depending on its value. Try this.
function ratesD(image) {
if (image.src == "https://dirask.com/static/bucket/1631898942509-VMYrnXyYZv--image.png") {
image.src = "https://dirask.com/static/bucket/1633375165831-yjQ7G6WQeL--image.png";
} else {
image.src = "https://dirask.com/static/bucket/1631898942509-VMYrnXyYZv--image.png"
}
}
<img src="https://dirask.com/static/bucket/1631898942509-VMYrnXyYZv--image.png" class="logo" alt="Banner" onclick="ratesD(this)" />
It's a bad idea to force load/unload your images (even if they are in the system cache) every time you click on them.
Load them only once, and switch their display at each click.
const bannerImgs = document.querySelector('#banner-images');
bannerImgs.onclick =_=> bannerImgs.classList.toggle('seeOther');
#banner-images > img {
width : 100px;
height : 100px;
}
#banner-images.seeOther > img:first-of-type,
#banner-images:not(.seeOther) > img:last-of-type {
display : none;
}
<div id="banner-images" >
<img src="https://dirask.com/static/bucket/1631898942509-VMYrnXyYZv--image.png" alt="Banner" >
<img src="https://dirask.com/static/bucket/1633375165831-yjQ7G6WQeL--image.png" alt="Banner" >
</div>

Adding an eventlistener on not yet generated DOM

I have a bunch of
<div class="location-box" data-location-id="123">
<img src="img_url" />
</div>
Loaded into my .locations div.
I want that whenever you click on a .location-box that the clicked div gets a highlighted class on it. And the attribute value gets added to a hidden input. When you click on another one, the class from the previous one gets removed. And so on and so on.
I've tried it before when those divs where static, and it worked fine. But now I'm appending these divs out of pure Javascript from an api call.
I also know that not yet generated DOM can't be manupilated by event listeners etc.
I've looked into mutation observers, and tried some simple stuff from the docs. But I could make this code work with it
let locations = document.querySelectorAll(".location-box");
locations.forEach( el =>
el.addEventListener('click', function() {
locations.forEach( els => els.classList.remove('active-location'));
document.getElementById('location_id').value = this.getAttribute('data-location-id');
this.classList.add("active-location");
})
);
Does anyone know how to make this work? Maybe not only this time, but in multiple cases. Cause in the near future I'd probably have more not yet generated DOM.
From my above comment ...
"#Coolguy31 ... A MutationObserver based approach most likely is overkill. Event Delegation might be the technique of choice. But in order to implement it somehow correctly it was nice to know whether all the later rendered stuff is always inserted/appended below a common and also known root node, cause document.body as event listening root is not the most elegant/performant choice either."
function uuid(a) {
// [https://gist.github.com/jed/982883] - Jed Schmidt
return a
? (a^Math.random()*16>>a/4).toString(16)
: ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,uuid);
}
function addLocations(evt) {
evt.preventDefault();
const allLocationsRoot =
document.querySelector('.locations');
allLocationsRoot.innerHTML = `
<div class="location-box">
<img src="https://picsum.photos/133/100?grayscale" />
</div>
<div class="location-box">
<img src="https://picsum.photos/100/75?grayscale" />
</div>
<div class="location-box">
<img src="https://picsum.photos/120/90?grayscale" />
</div>
`;
allLocationsRoot
.querySelectorAll('.location-box')
.forEach(locationNode => locationNode.dataset.locationId = uuid());
allLocationsRoot
.closest('form[name="location-data"]')
.elements['location']
.value = '';
}
function initializeAddLocations() {
document
.querySelector('button')
.addEventListener('click', addLocations);
}
function handleLocationSelect(evt) {
const locationItemRoot = evt
.target
.closest('.location-box');
if (locationItemRoot) {
const allLocationsRoot = locationItemRoot
.closest('.locations');
const locationControl = allLocationsRoot
.closest('form[name="location-data"]')
.elements['location'];
// console.log({
// target: evt.target,
// locationItemRoot,
// allLocationsRoot,
// locationControl,
// });
allLocationsRoot
.querySelectorAll('.location-box')
.forEach(locationNode => locationNode.classList.remove('selected'));
locationItemRoot.classList.add('selected');
locationControl.value = locationItemRoot.dataset.locationId;
}
}
function initializeLocationHandling() {
document
.querySelector('.locations')
.addEventListener('click', handleLocationSelect)
}
function main() {
initializeLocationHandling();
initializeAddLocations();
}
main();
body { margin: 0; }
[type="text"][name="location"] { width: 23em; }
.locations:after { display: block; content: ''; clear: both; }
.location-box { float: left; margin: 4px; padding: 10px; min-height: 104px; background-color: #eee; }
.location-box.selected { outline: 2px solid #fc0; }
<form name="location-data">
<div class="locations">
</div>
<button>update locations</button>
<!--
<input type="hidden" name="location" />
//-->
<input type="text" name="location" disabled />
</form>
You can do that with MutationObserver, the code it's something like below, it doesn't have the piece to get the attribute, but you can add that, another way of doing it would be like #scara9 is saying, on the code you use to render each .location-box you can assign the click handler.
in the code below i used jquery to "add" new location-box, you don't need jquery for this
// select the parent node: .locations, i switched to ID for test
var target = document.getElementById("locations");
// create an observer instance
var observer = new MutationObserver(function (mutations) {
//loop through the detected mutations(added controls)
mutations.forEach(function (mutation) {
//addedNodes contains all detected new controls
if (mutation && mutation.addedNodes) {
mutation.addedNodes.forEach(function (elm) {
if (elm && elm.className=="location-box") {
elm.addEventListener("click", function () {
elm.classList.add("active-location");
var locations = document.querySelectorAll(".location-box");
locations.forEach((e) => {
if (e != elm) {
//ignore clicked element
e.classList.remove("active-location");
}
});
});
}
});
}
});
});
// pass in the target node, as well as the observer options
observer.observe(target, {
childList: true
});
//you don't need this, it's only to simulate dynamic location-box
$(function () {$("button").on("click", function () {var count = $(".location-box").length + 1;$(".locations").append($("<div class='location-box' data-attribute-id='" +count +"'>location box:" +count +"</div>"));});});
.active-location{
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="locations" id="locations">
</div>
<!-- This button it's only to add the controls, not needed in your case-->
<button type="button" id="add">
Add
</button>

Trying to switch images using a toggle button in vanilla JS

I'm not quite sure why my code isn't working at this point. I am trying to make an Instagram like button. I have an image of a black heart and when double clicked on I want to switch it to another image of a red heart. I've dug around here and there but couldn't quite pin point the problem. The code snippet works but it does not work when I run it in my project.
const button = document.querySelector('#like');
document.querySelector('button').addEventListener('dblclick', (e) => {
if (button.src == "https://www.w3schools.com/html/img_chania.jpg") {
button.src = "https://www.w3schools.com/html/pic_trulli.jpg";
} else {
button.src = "https://www.w3schools.com/html/img_chania.jpg";
}
});
.under-image-nav button {
border: none;
width: 30px;
}
<nav class="under-image-nav">
<button><img id="like" src="https://www.w3schools.com/html/img_chania.jpg" alt="like button"> </button>
</nav>
I got rid of the button and simply allowed javascript to control the source of the image.
To shorten the code, I used a ternary operator
let heartEl = document.querySelector(".heart");
const fullHeart = 'https://external-content.duckduckgo.com/iu/?u=http%3A%2F%2Ffrogermcs.github.io%2Fimages%2F6%2Fheart_red.png&f=1&nofb=1"'
const emptyHeart = 'https://freeiconshop.com/wp-content/uploads/edd/heart-outline.png'
heartEl.addEventListener("dblclick", () => {
heartEl.src == emptyHeart ? heartEl.src = fullHeart : heartEl.src = emptyHeart
});
<img class='heart' src='https://freeiconshop.com/wp-content/uploads/edd/heart-outline.png'>
You should attach the event listener to the button instead.
const img = document.querySelector('#like');
document.querySelector('button').addEventListener('dblclick', (e) => {
if (img.src == "https://www.w3schools.com/html/pic_trulli.jpg") {
img.src = "https://www.w3schools.com/html/img_chania.jpg";
} else {
img.src = "https://www.w3schools.com/html/pic_trulli.jpg";
}
});
<button><img id="like" src="https://www.w3schools.com/html/pic_trulli.jpg" alt="like button" width="100" height="100"></button>

Vue js - Set alt image when image source not found

I am working on a site which has a list of products. Each product has a corresponding image. I am binding the image url to the source attribute like below.
<img :src="product.ImageUrl"/>
If the image is not found, I want to show a default image.
I do as below in cshtml razor syntax (for reference only)
onerror='this.onerror = null;this.src = "#Url.Content("~/images/photo-not-available.jpg")";'
How do I achieve the same in Vue?
You can set an onerror handler function with #error in Vue:
<img :src="" #error="aVueFunctionThatChangesTheSrc">
Since in pure js put onerror inline like this
<img :src="ImgUrl" onerror="this.src='http://example.com/default.jpg'"/>
for vue.js we can replace it
<img :src="ImgUrl" #error="$event.target.src='http://example.com/default.jpg'"/>
I found that changing the src in the #error function kicked off a horrible endless loop of updates, causing a flickering screen etc. My solution so far is:
<span v-if="props.column.field === 'avatar'">
<span v-if="props.row.avatar">
<img alt="avatar" class="round-32" :src="`${props.row.avatar}`" #error="(() => props.row.avatar = null)"/>
</span>
<span v-else>
<img alt="avatar" class="round-32" src="../../../assets/images/avatar-2.jpg"/>
</span>
</span>
I have try to using #error but it doesn't work because in my case, the image was not found, so I try this one, and its work.
<img :src="getImgUrl(filename)">
methods: {
getImgUrl(filename){
try{
return require(`#/assets/${filename}`)
}catch(_){
return require(`#/assets/default.png`)
}
},
}
I ended up with a directive to set a fallback image and prevent the loop:
image-src-fallback.js
const setSrc = (evt) => {
const el = evt.currentTarget;
el.setAttribute("src", el.fallback);
el.fallback = "";
el.removeEventListener("error", _listener);
};
const _listener = (evt) => setSrc(evt);
export default {
bind(el, binding) {
el.fallback = binding.value;
el.addEventListener("error", _listener);
},
unbind(el) {
el.removeEventListener("error", _listener);
},
};
Global import
import imageSrcFallback from "./directives/image-src-fallback.js";
Vue.directive("src-fallback", imageSrcFallback);
Use
<img
v-src-fallback="user.avatar_fallback_url"
:src="user.avatar_url"
/>
Sometimes you can create a method, for example in my case some images are not found because clients have not uploaded images, then you can create a method for it: you can return any value as an image or simple '' for any image.
<div class="flex-shrink-0">
<img
class="h-72 w-full object-cover"
:src="showFirstImageGallery(p.project_images)"
/>
</div>
methods: {
showFirstImageGallery(v){
if (v.length > 1) {
return v[1].img_url
} else {
return ''
}
}
},

javascript onclick function not working?

I am trying to do an onclick event where when a light bulb image is clicked it goes from a light bulb off to a light bulb on image and vice versa.
I am using an external javascript file. when I click on the image nothing happens.
I cant figure out whats wrong,
my html portion:
<head>
<link rel="stylesheet" href="css/program-01.css" />
<script type="text/javascript" src="javascript/program-01.js"></script>
<title>
<h1>Program-01</h1>
</title>
</head>
<body>
<div id="LightOff">
<img src="images/light_off.png" id="light_off" alt="" onclick="LightBulbFunction()" />
</div>
</body>
my js file function:
function LightBulb() {
var image_change = document.getElementById("light_off");
if (image_change.src == "images/light_off.png") {
image_change = "images/light_on.png";
} else {
image_change = "images/light_off.png";
}
}
Suggestions/Problems:
You function names are different.
You're using the function LightBulbFunction on the onclick event. But, you don't have the function of that name in your script. You'll get
ReferenceError: LightBulbFunction() is not defined.
To change the image src attribute value, use image_change.src inside the event handler.
To solve the problem change the name of onclick attribute value to LightBulb.
function LightBulb() {
var image_change = document.getElementById("light_off");
if (image_change.src == "images/light_off.png") {
image_change.src = "images/light_on.png";
// ^^^^
} else {
image_change.src = "images/light_off.png";
// ^^^^
}
}
<div id="LightOff">
<img src="images/light_off.png" id="light_off" alt="" onclick="LightBulb()" />
<!-- ^^^^^^^^^^^ -->
</div>
Better approach will be to use addEventListener to bind events on the elements.
document.getElementById('light_off').addEventListener('click', function() {
var image_change = document.getElementById("light_off");
if (image_change.src == "images/light_off.png") {
image_change.src = "images/light_on.png";
} else {
image_change.src = "images/light_off.png";
}
}, false);
<div id="LightOff">
<img src="images/light_off.png" id="light_off" alt="" onclick="LightBulb()" />
<!-- ^^^^^^^^^^^ -->
</div>
Well in your html, the code is onclick="LightBulbFunction()" while in javascript it is LightBulb. Change either of them and make them match
You are not redefining the .src. Change
image_change =
to
image_change.src =
And your function needs to have the same LightBulb function name.

Categories

Resources