I'm trying to create a simple image swapper. So I have 20 images on the page, and 1 large one. I want the user to click one of the smaller images from the 20 and it be output into the place of the big image source.
I've only just started but even so my code doesn't seem to validate as the script fails before it even gets to the console.log. Also not sure if I'm using thisID correctly.
<img id='avatar-output' onclick='selectAvatar(thisID)' src='images/avatars/$number.png' />
<script>
function selectAvatar(thisID){
var imageSource = document.getElementById ("avatar-output").src;
console.log("Avatar source is " imageSource);
}
</script>
HTML:
<img id='avatar-output' src='images/avatars/$number.png' />
<img class='avatar-small' src='images/avatars/1.png' />
<img class='avatar-small' src='images/avatars/2.png' />
<img class='avatar-small' src='images/avatars/3.png' />
JS:
var els = document.getElementsByClassName('avatar-small'),
target = document.getElementById("avatar-output"),
handler = function() { target.src = this.src; };
for (var i=0; i<els.length; ++i) els[i].onclick = handler;
Demo
Or, if all small images are together, better use event delegation:
var target = document.getElementById("avatar-output");
document.getElementById("avatar-small-wrapper").onclick = function(e) {
if(e.target.tagName.toLowerCase() === 'img') target.src = e.target.src;
};
Demo
Notes
Better separation of content (html) and behavior (inline JS)
<script> element needs type="text/javascript" attribute
Avoid running JavaScript in global scope to avoid creating global variables, polluting window. Run in in a closure: (function(){ /* code here */ })()
You have a typo in it, change
var imageSource = document.getElementById ("avatar-output").src;
to
var imageSource = document.getElementById("avatar-output").src;
since there is a space where it shouldn't be.
Edit: oh and another one in the
console.log("Avatar source is " imageSource);
line. Add a + between your string and your variable like this:
console.log("Avatar source is " + imageSource);
Related
I have a gallery page that is updated often with new images. I use simple HTML to post the photos. My process currently is copy and paste the set of tags for a photo and change the number to correspond with the image file name. E.G. I change the number 047 to 048. Copy-Paste, change it to 049. This goes on until I have reached the number of additional photos. As you can see, this is very inefficient and there must be a better way of doing this. I was wondering if there is a simpler way to achieve this with Javascript? Perhaps generate additional tags by inputing a certain number or range?
Any ideas that would make this process efficient are welcomed please! Thank you!
<div class="cbp-item trim">
<a href="../assets/images/trim/img-trim-047.jpg" class="cbp-caption cbp-lightbox" data-title="">
<div class="cbp-caption-defaultWrap">
<img src="../assets/images/trim/img-trim-047.jpg" alt="">
</div>
</a>
</div>
You could use a templating solution. There are several libraries for that, but you can also implement it yourself.
Here is one way to do that:
Put the HTML for one image in a script tag that has a non-standard language property so the browser will just ignore it
Put some keywords in there that you'll want to replace, e.g. {url}. You can invent your own syntax.
Read that template into a variable
In the JS code, put all the images' URLs in an array of strings
For each element in that array, replace the keywords in the template string with that particular URL, and concatenate all these resulting HTML snippets.
Inject the resulting HTML into the appropriate place in the document.
Here is a snippet doing that:
// Add new images here:
var images = [
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/330px-SNice.svg.png",
"https://nettemarie357.files.wordpress.com/2014/09/smiley-face.jpg?w=74&h=74",
];
// Load the template HTML
var template = document.querySelector('script[language="text/template"]').innerHTML;
// Use template to insert all the images:
container.innerHTML = images.map(url => template.replace(/{url}/g, url)).join('');
img { max-width: 50px }
<div id="container"></div>
<script language="text/template">
<div class="cbp-item trim">
<a href="{url}" class="cbp-caption cbp-lightbox" data-title="">
<div class="cbp-caption-defaultWrap">
<img src="{url}" alt="">
</div>
</a>
</div>
</script>
This would help you creating it programatically:
var new_row = document.createElement('div');
new_row.className = "cbp-item trim";
var a = document.createElement('a');
a.href = "../assets/images/trim/img-trim-047.jpg";
a.className= "cbp-caption cbp-lightbox";
document.body.appendChild(a);
var div = document.createElement('div');
div.className = "cbp-caption-defaultWrap";
var img = document.createElement('img');
img.src= "../assets/images/trim/img-trim-047.jpg";
div.appendChild(img);
a.appendChild(div);
new_row.appendChild(a);
If it is just about printing HTML, I suggest you to use plugins like Emmet for Sublime Text editor.
When you install this plugin and see how it works, you can simple create a complex html in a way that 'for' loop would do this. This will help you to change only the image/link number of every item.
Check the demo in the link, that I added.
Here's an example in Java Script that will generate the html you will need. Set the total to whatever number you need to generate the number of images you want.
var total = 47;
var hook = document.getElementById('hook');
// Main Node for SlideShow
var node = document.createElement('div');
node.classList = "cbp-item trim";
// Work out the correct number
var n = function(int) {
var length = int.toString().length;
return length === 1
? '00' + int
: length === 2
? '0' + int
: length
}
// Create the item
var createItem = function(int){
// Create Anchor
var a = document.createElement('a');
a.href = '../assets/images/trim/img-trim-' + ( n(int) ) + '.jpg" class="cbp-caption cbp-lightbox';
a.classList = 'cbp-caption cbp-lightbox';
// Create Div
var div = document.createElement('div');
div.classList = 'cbp-caption-defaultWrap';
// Create Image
var img = document.createElement('img');
img.src = '../assets/images/trim/img-trim-' + ( n(int) ) + '.jpg';
img.alt = 'gallery image';
// Finalise Dom Node
var container = div.appendChild(img)
a.appendChild(div);
// Return Final Item
return a
}
// Create Items
for (var i = 1; i < total + 1; i++) {
node.appendChild(createItem(i));
}
// Append Main Node to Hook
hook.appendChild(node);
<div id="hook"></div>
Hi I have markup sent to me from a server and I set it as the innerHTML of a div element for the purpose of traversing the tree, finding image nodes, and changing their src values. Is there a way to prevent the original src value from being downloaded?
Here is what I am doing
function replaceImageSrcsInMarkup(markup) {
var div = document.createElement('div');
div.innerHTML = markup;
var images = div.getElementsByTagName('img');
images.forEach(replaceSrc);
return div.innerHTML;
}
The problem is that in browsers as soon as you do:
var img = document.createElement('img'); img.src = 'someurl.com' the browser fires off a request to someurl.com. Is there a way to prevent this without resorting to parsing the markup myself? If there is in no other way does anyone know a good way of parsing the markup with as little code as possible to accomplish my goal?
I know you are already happy with your solution, but I think it would be worth sharing a safe method for future users.
You can now simply use the DOMParser object to generate an external document from your HTML string, instead of using a div created by your current document as container.
DOMParser specifically avoids the pitfalls mentioned in the question and other threats: no img src download, no JavaScript execution, even in elements attributes.
So in your case you can safely do:
function replaceImageSrcsInMarkup(markup) {
var parser = new DOMParser(),
doc = parser.parseFromString(markup, "text/html");
// Manipulate `doc` as a regular document
var images = doc.getElementsByTagName('img');
for (var i = 0; i < images.length; i += 1) {
replaceSrc(images[i]);
}
return doc.body.innerHTML;
}
Demo: http://jsfiddle.net/94b7gyg9/1/
Note: with your current code, browsers will still try downloading the resource initially specified in your img nodes src attribute, even if you change it before the end of JS execution. Trace network transactions in this demo: http://jsfiddle.net/94b7gyg9/
Rather than append the new markup to the DOM before you change the img sources, create an element, set it's inner HTML, change the source of the images and then finally, append the changed markup to the page.
Here's a fully-worked sample.
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
//function allByClass(className,parent){return (parent == undefined ? document : parent).getElementsByClassName(className);}
function allByTag(tagName,parent){return (parent == undefined ? document : parent).getElementsByTagName(tagName);}
function newEl(tag){return document.createElement(tag);}
//function newTxt(txt){return document.createTextNode(txt);}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
byId('goBtn').addEventListener('click', onGoBtnClick, false);
}
var dummyString = "<img src='img/girl.png'/><img src='img/gfx07.jpg'/>";
function onGoBtnClick(evt)
{
var div = newEl('div');
div.innerHTML = dummyString;
var mImgs = allByTag('img', div);
for (var i=0, n=mImgs.length; i<n; i++)
{
mImgs[i].src = "img/murderface.jpg";
}
document.body.appendChild(div);
}
</script>
<style>
</style>
</head>
<body>
<button id='goBtn'>GO!</button>
</body>
</html>
You could directly parse the markup string using a regex to replace the img src. Searching for all the img src urls in the string and then replacing them with the new url.
var regex = /<img[^>]+src="?([^"\s]+)"?\s*\/>/g;
var imgUrls = [];
while ( m = regex.exec( markup ) ) {
imgUrls.push( m[1] );
}
imgUrls.forEach(function(url) {
markup = markup.replace(url,'new-url');
});
Another solution might be, if you have access to it, to set the all the img src to an empty string, and put the url in in a data-src attribute. Having your markup string look like something like this
markup = '
';
Then setting this markup to your div.innerHTML won't trigger any download from the browser. And you can still parse it using regular DOM selector.
div.innerHTML = markup;
var images = div.getElementsByTagName('img');
images.forEach(function(img){
var oldSrc = img.getAttribute('data-src');
img.setAttribute('src', 'new-url');
});
I'm looking for create a small javascript code to display images if their src is valid.
I have to separate the script to the html page for better organisation.
Here is what I did :
HTML
<img id="thmb" src= "http://blog.lefigaro.fr/bd/img-sanctuaire.png" width="50px" height="50px" alt="" ;>
JavaScript
var thumbnail = document.images.thmb;
if(thumbnail.src)
{
if(thumbnail.onerror)
{
thumbnail.src = "http://blog.lefigaro.fr/bd/img-sanctuaire.png";
}
}
else
{
thumbnail.style.display = "none";
}
Bu it doesn't work, when I empty the src code in HTML, the border of the image still in the page. And if I write a wrong URL, we can't see the image set in the JavaScript.
Here is the JSFiddle to experiment it.
http://jsfiddle.net/gUb8X/
I'm a beginner in JavaScript.
Thank you !
You are too late with the test.
Try this
Live Demo
window.onload=function() {
var thumbContainer = document.getElementById("thmbDiv");
var thumbnail = document.createElement("img");
thumbnail.onload=function() {
thumbContainer.appendChild(thumbnail);
}
thumbnail.src = "http://blog.lefigaro.fr/bd/img-sanctuaire.png";
}
Now replace your image with a div with id thmbDiv
if you put placeholders or hide all images you want to test, you can get the src from a data attribute.
Live Demo
window.onload=function() {
var imgs = document.images; // or document.getElementsByClassName("testImage");
for (var i=0, n=imgs.length;i<n;i++) {
var theImage = imgs[i];
var src = theImage.getAttribute("data-src");
if (src) {
theImage.onerror=function() {
this.style.display="none"; // or this.parentNode.removeChild(this);
}
}
theImage.src=src;
}
}
A neat inline solution would be this
DEMO http://jsfiddle.net/LstNS/25/
<img src="rando/path" id="image" onerror="this.style.display='none';"/>
jQuery:
You can use an ajax call to check if the image file exists
$.ajax({
url:'http://yourhost/someimage.ext',
type:'HEAD',
error: function()
{
//file does not exist
},
success: function()
{
//file exists do something here
}
});
DEMO http://jsfiddle.net/LstNS/24/
As you can see in the demo, the second image is not loaded and presented as a broken image as it does not exist.
A non jQuery version would be
var img = document.getElementById("myImg");
img.onerror = function () {
this.style.display = "none";
}
Your code now tests for thumbnail.src, which means that you are testing for the existence of an src propery, which always exists for a syntactically valid img element. Then you test for the existence of an onerror event handler, and since there is none, you take a branch that does nothing.
A way that works is to use an onerror attribute in the img element and make it remove the element (or remove it from rendering, but actually removing the element is more logical, and safer):
<img id="thmb" src= "http://blog.lefigaro.fr/bd/img-sanctuaire.png"
width="50" height="50" alt="" onerror="rm(this)">
<script>
function rm(elem) {
elem.parentNode.removeChild(elem); }
</script>
Unfortunately, you can’t do this so with a loop that traverses through all img elements. If you try that, your code will run only after the image loading has been performed, so it would be too late to try to set onerror handlers on them.
I just found a little trick to make it possible. That doesn't follow the convention but it works. I just use the "alt" image keyword as the "src" keyword, and the JavaScript gives the src equals to alt attribute found in the html.
<img id="thmb" width="50px" height="50px" alt="http://blog.lefigaro.fr/bd/img-sanctuaire.png" ;>
Javascript :
var img = document.getElementById("thmb");
img.src= img.alt;
img.onerror = function () {
img.style.display = "none";
}
http://jsfiddle.net/LstNS/28/
To more, because I have to use a function to return all the final html code, I did this :
display: function (data) {
var pid = data.record.project_id;
var thb = data.record.Thumbnail;
var base_url = "<?php echo base_url('project');?>/";
function checkImg(){
try
{
var thumbnail = document.createElement("img");
thumbnail.src = thb;
} catch(err) {
//
}
if(thumbnail.height > 0){
var result = 'src="' + thb + '"';
}
else
{
var result = 'style="display:none;"';
}
return result;
}
return '<img id="thumbnail" ' + checkImg() + '" width="50px" height="50px" >';
}
I have to thank you for all your answers which permit me to find a good way to do it !
If you have comments to do, don't hesitate ! ;)
I tested the following code in IE, Chrome, and Firefox and it does not work in any of them. I have read several questions about similar problems but they have not offered solutions that fix my example.
I am trying to create a pause/play button that interfaces with JWplayer (I also want it to interface with flowplayer, once I get the button working) and the image will change depending on which image is currently there. I also have a stop button that stops the player completely and changes the image of the pause/play button to pause.
Here is my current code:
<script type="text/javascript">
function changeimg()
{
var obj = document.getElementById('image1');
var imgtag1 = '<img src=\'PLAY.png\'>';
var imgtag2 = '<img src=\'PAUSE.png\'>';
if(obj.innerHTML == imgtag2)
{obj.innerHTML = imgtag1;}
else
{obj.innerHTML = imgtag2;}
return;
}
function playimg()
{
document.getElementById('image1').innerHTML = '<img src=\'PLAY.png\'>';
return;
}
</script>
<div id="image1" href="#" onclick="changeimg(); jwplayer('mediaspace1').play(); jwplayer('mediaspace2').play(); jwplayer('mediaspace3').play(); jwplayer('mediaspace4').play();"><img src='PLAY.png'></div>
<div href="#" onclick="playimg(); jwplayer('mediaspace1').stop(); jwplayer('mediaspace2').stop(); jwplayer('mediaspace3').stop(); jwplayer('mediaspace4').stop();"><img src='STOP.png'></div>
The play/pause function works, and the first div WILL change into the pause img (so the javascript is going through) and it WILL change back into play if I click on the second div (stop function - triggers playimg() ) but it will not change back into the play image if I click on the pause button again.
For security reasons I can't link the website, but any help would be appreciated
It looks like all you really want to change is the SRC of the IMG tag, not necessarily the entire innerHTML. As machineghost mentions in his comment, there may be whitespace added or other changes to the full HTML that may make your comparison come out as false.
However, you could check if obj.src == "PLAY.png" and set the SRC attribute directly. Something like this:
function changeimg()
{
var obj = document.getElementById('image1');
var img1 = 'PLAY.png';
var img2 = 'PAUSE.png';
if(obj.src == img2)
{obj.src = img1;}
else
{obj.src = img2;}
return;
}
I think the innerhtml you are replacing in changeimg() is affecting the whole obj element, which is a div. So, if(obj.innerHTML == imgtag2) will return false since the div innerhtml is not imgtag2, but the next time you are going to call changeimg(), "obj" will be undefined because you replaced its innerhtml with an HTML code that doesn't have an id: {obj.innerHTML = imgtag2;}
Check the console to see if there's any javascript error, which it should, at if(obj.innerHTML == imgtag2)
rgds.
Just check whether PLAY is present or not and then change innerHTML according to it
function changeimg()
{
var obj = document.getElementById('image1');
var imgtag1 = '<img src=\'PLAY.png\'>';
var imgtag2 = '<img src=\'PAUSE.png\'>';
if(obj.innerHTML.indexOf('PLAY') != -1)
{obj.innerHTML = imgtag2;}
else
{obj.innerHTML = imgtag1;}
return;
}
I'm trying to create a lightbox and I'm having trouble.
I think the problem is either because I have 2 window.onloads or because I'm trying to reference a newly created DOM element. I added some comments in the code below that explain what I'm trying to do.
//open lightbox
window.onload = showLargeImage;
function showLargeImage() {
var enlargeButton = document.getElementById("thumb1"); // thumb1 is a thumbnail you click to get the lightbox
enlargeButton.onclick = handleClick;
}
function handleClick() {
var lightboxContainerId = document.getElementById("lightboxContainer");
lightboxContainerId.innerHTML = '<div class="lightbox"><a class="reduceButton" href="#" ><img id="imageButton" class="largeImage" src="2012/images/web/web1.jpg" width="500" height="500" alt="Web Thumb 1"></a></div>';
} // the inner HTML creates the lightbox.
//close lightbox
window.onload = reduceImage; // i'm pretty sure that this windo.onload is the problem... or, that I'm referencing "imageButton" which is new to the DOM
function reduceImage() {
var reduceButton = document.getElementById("imageButton"); // you're supposed to click the big image in the lightbox to get close it.
reduceButton.onclick = handleReduceClick;
}
function handleReduceClick() {
var shadeId = document.getElementById("lightboxContainer");
shadeId.innerHTML = "say what"; // closing the lightbox simply strips everything out of the lightboxContainer
alert("oh yeah");
}
Here are a few reasons why your code is not working:
showLargeImage and reduceImage are missing invocation parentheses in the places where they are being assigned to window.onload. Without parentheses, window.onload is being assigned a function, but that function is not getting called. You should, for instance, have window.onload = showLargeImage();
As you suspected, the second window.onload is overwriting the first.
reduceButton is (as you also suspected) being assigned before it exists, causing an error.
Here is one solution that may work for you.
HTML:
<!DOCTYPE html>
<html><head><title></title>
</head><body>
View
<div id="lightboxcontainer"></div>
</body></html>
JavaScript:
window.onload = function() {
// click link to show
var enlargeButton = document.getElementById('thumb');
enlargeButton.onclick = function() {
var lightboxContainerId = document.getElementById('lightboxcontainer');
lightboxContainerId.innerHTML = '<img src="http://placehold.it/350x150"' +
'width="350" height="150 alt="Thumb 1">' +
'<p>Click image to hide.</p>';
};
// click image to hide
var reduceButton = document.getElementById('lightboxcontainer');
reduceButton.onclick = function() {
reduceButton.innerHTML = ''; // removes lightbox contents
};
};
Live demo: http://jsfiddle.net/ericmathison/BxwYY/7/
If the code is placed at the end of the <body> (or anywhere after your lightbox elements), just use this:
document.getElementById("thumb1").onclick = function () {
document.getElementById("lightboxContainer").innerHTML = '<div class="lightbox"><a class="reduceButton" href="#" ><img id="imageButton" class="largeImage" src="2012/images/web/web1.jpg" width="500" height="500" alt="Web Thumb 1"></a></div>';
document.getElementById("imageButton").onclick = function () {
document.getElementById("lightboxContainer").innerHTML = "say what";
alert("oh yeah");
};
}
This will do everything you want.