Simpel image toggle function won't work (no jQuery) - javascript

I have been trying to make this simpel image toggle on click function work but I am not sure what is wrong. I have to use querySelector and addEventListener, also jquery is not allowed. Could anyone please help me figure this out?
document.querySelector(".imageClass").addEventListener("click", function () {
var img = this.src;
if(img.src == "/image/location1.png") {
img.src = "/image/location2.png";
} else {
img.src = "/image/location2.png";
}
});
I'm getting this error:
document.querySelector(...).addEventlistener is not a function(...)

Getting a property would most likely return an absolute URL, and you really want to make sure you check the attribute, not the property.
Also, you're accesing src twice, first by doing var img = this.src then by doing img.src
And your condition does the same thing in both cases
document.querySelector(".imageClass").addEventListener("click", function () {
var img = this;
var src = img.getAttribute('src');
if( src == "/image/location1.png" ) {
img.src = "/image/location2.png";
} else {
img.src = "/image/location1.png";
}
});

Recieve your event by passing it with your parameters. From there you can access the target element of the event and get its src attribute.
document.querySelector(".imageClass").addEventListener("click", function (e) {
var img = e.target;
if(img.src == "/image/location1.png") {
img.src = "/image/location2.png";
} else {
img.src = "/image/location2.png";
}
});

Related

form keep on submitting onchange

I am using this code to auto submit the form
document.getElementById("file").onchange = function() {
document.getElementById("form").submit();
};
the form contain an image file input, once the image is selected the function is called, and this function creates an image that is inserted to display as follow:
document.getElementById("uploadImage").onchange = function() {
var oFile = document.getElementById("uploadImage").files[0];
if (document.getElementById("uploadImage").files.length === 0) {
return;
}
var img = document.createElement("img");
img.width = 200;
img.height = 200;
img.id = randomid;
img.src = "./upload/Images/" + oFile.name;//i want to point to the file uploaded
img.onload = function() {
document.getElementById(container).appendChild(img);
}
document.getElementById("form").submit();
};
the above code is working but it is continuously updating the image. Is there another way to approach this issue?
I believe you should you promise or something like that. once you get the response from
the below function then only you should call the submit ().
img.onload = function() {
document.getElementById(container).appendChild(img);
}
May be this link will help you to understand event life cycle hook

Getting null value on the querySelector

I try to copy paste the code from Mozilla's getting started with Javascript tutorial
var myImage = document.querySelector('img');
myImage.onclick = function() {
var mySrc = myImage.getAttribute('src');
if(mySrc === 'images/firefox-icon.png') {
myImage.setAttribute ('src','images/firefox2.png');
} else {
myImage.setAttribute ('src','images/firefox-icon.png');
}
}
I am getting an error "Cannot set property 'onclick' of null". How can correct the code?
I am just getting started with javascript. please forgive me if it is a silly mistake from my part.
You might be trying to assign the click handler before the element has been rendered so the query selector will not find the img tag. Try executing your script after the page has rendered like so
window.onload = function () {
var myImage = document.querySelector('img');
myImage.onclick = function() {
var mySrc = myImage.getAttribute('src');
if(mySrc === 'images/firefox-icon.png') {
myImage.setAttribute ('src','images/firefox2.png');
} else {
myImage.setAttribute ('src','images/firefox-icon.png');
}
}
}

Function returns the value before Jquery Image load is executed

if (DataService.Validation(file)) {
//angularjs call to api controller
};
//DataService
Validation: function (file) {
var Url = URL.createObjectURL(file);
var img = new Image();
$(img).load(function () {
var imgwidth = this.width;
var imgheight = this.height;
if (imgheight > 400) {
viewModel.ErrorMessage = 'The Image height cannot be more then 400 px.';
return false;
}
});
img.src = Url;
if (file == null) {
viewModel.ErrorMessage = 'Please select a file to upload.';
return false;
}
if (viewModel.Name == null) {
viewModel.ErrorMessage = 'Name is a required field.';
return false;
}
return true;
}
The above validation function is completing the execution and returning true without the code inside img load function is checked..It means tht even if the image is greater then 400px the validation returns true as the code inside load runs after a long time once the whole Jquery ajax call is sent to api controller..
What I am trying to achieve is that the Validation should not return the value until the code inside the image load is executed.
I had same issue while checking dimension of image as image loading is asynchronous . Also as said by #Abhinandan
"IMG load function will execute only after your image is completely loaded by the browser and since its asynchronous your function will not wait for it to execute"
I used following approach. Hope it will help.
Set one extra attribute in image tag while on change of file like below
$('input[type=file]').on('change',function(){
element = $(this);
var files = this.files;
var _URL = window.URL || window.webkitURL;
var image, file;
image = new Image();
image.src = _URL.createObjectURL(files[0]);
image.onload = function() {
element.attr('uploadWidth',this.width);
element.attr('uploadHeigth',this.width);
}
});
and now you can modify your function to below
$.validator.addMethod('checkDim', function (value, element, param) {
var image = new Image();
var file = element.files[0];
var _URL = window.URL || window.webkitURL;
image.src = _URL.createObjectURL(file);
if(element.uploadWidth== param[0] element.uploadHeigth== param[1]){
return true;
}
else{
return false;
}
}, 'Image dimension must be as specified');
It work for me
The behaviour is correct as your function will return with 'true' value always.
IMG load function will execute only after your image is completely loaded by the browser and since its asynchronous your function will not wait for it to execute.
Also if you want to check the width/height of image being loaded, use naturalWidth/naturalHeight as this will give the right values and not the one assigned to the image by css.
What you can do is inside image-load function,you can call your function with true/false value as parameter.

Detecting an image 404 in Javascript

After a user uploads a file we have to do some additional processing with the images such as resizing and upload to S3. This can take up to 10 extra seconds. Obviously we do this in a background. However, we want to show the user the result page immediately and simply show spinners in place until the images arrive in their permanent home on s3.
I'm looking for a way to detect that a certain image failed to load correctly (404) in a cross browser way. If that happens, we want to use JS to show a spinner in it's place and reload the image every few seconds until it can be successfully loaded from s3.
Handle the <img> element's onerror event.
First option:
<img src="picture1.gif" onerror="this.onerror=null;this.src='missing.gif';"/>
Second option:
<html>
<head>
<script type="text/javascript">
function ImgError(source){
source.src = "/noimage.gif";
source.onerror = "";
return true;
}
</script>
</head>
<body>
<img src="image_example1.jpg" onerror="ImgError(this)" />
</body>
</html>
PS: it's pure javascript! you don't need any libraries. (Vanilla JS)
Example in Fidler
https://jsfiddle.net/dorathoto/8z4Ltzp8/71/
From: http://lucassmith.name/2008/11/is-my-image-loaded.html
// First a couple helper functions
function $(id) {
return !id || id.nodeType === 1 ? id : document.getElementById(id);
}
function isType(o,t) { return (typeof o).indexOf(t.charAt(0).toLowerCase()) === 0;}
// Here's the meat and potatoes
function image(src,cfg) { var img, prop, target;
cfg = cfg || (isType(src,'o') ? src : {});
img = $(src);
if (img) {
src = cfg.src || img.src;
} else {
img = document.createElement('img');
src = src || cfg.src;
}
if (!src) {
return null;
}
prop = isType(img.naturalWidth,'u') ? 'width' : 'naturalWidth';
img.alt = cfg.alt || img.alt;
// Add the image and insert if requested (must be on DOM to load or
// pull from cache)
img.src = src;
target = $(cfg.target);
if (target) {
target.insertBefore(img, $(cfg.insertBefore) || null);
}
// Loaded?
if (img.complete) {
if (img[prop]) {
if (isType(cfg.success,'f')) {
cfg.success.call(img);
}
} else {
if (isType(cfg.failure,'f')) {
cfg.failure.call(img);
}
}
} else {
if (isType(cfg.success,'f')) {
img.onload = cfg.success;
}
if (isType(cfg.failure,'f')) {
img.onerror = cfg.failure;
}
}
return img;
}
And here how to use it:
image('imgId',{
success : function () { alert(this.width); },
failure : function () { alert('Damn your eyes!'); },
});
image('http://somedomain.com/image/typooed_url.jpg', {
success : function () {...},
failure : function () {...},
target : 'myContainerId',
insertBefore : 'someChildOfmyContainerId'
});
just bind the attr trigger on the error event.
$(myimgvar).bind('error',function(ev){
//error has been thrown
$(this).attr('src','/path/to/no-artwork-available.jpg');
}).attr('src',urlvar);
This worked for me (mine is in coffeescript). You'll need to replace with a spinner instead, of course.
checkImages = ->
$("img").each ->
$(this).error ->
$(this).attr("src", "../default/image.jpg")
$(document).on('page:load', checkImages)
I'm guessing the javascript equivalent is something like
function checkImages() {
$("img").each(function() {
$(this).error(function() {
$(this).attr("src", "../default/image.jpg");
});
});
};
$(document).on("page:load", checkImages);
I just did
if ($('#img')[0].naturalWidth > 0) {
as i noticed there was no naturalWidth if the image 404'd.
However, i can understand wanting to use a method above.

How to create a JavaScript callback for knowing when an image is loaded?

I want to know when an image has finished loading. Is there a way to do it with a callback?
If not, is there a way to do it at all?
.complete + callback
This is a standards compliant method without extra dependencies, and waits no longer than necessary:
var img = document.querySelector('img')
function loaded() {
alert('loaded')
}
if (img.complete) {
loaded()
} else {
img.addEventListener('load', loaded)
img.addEventListener('error', function() {
alert('error')
})
}
Source: http://www.html5rocks.com/en/tutorials/es6/promises/
Image.onload() will often work.
To use it, you'll need to be sure to bind the event handler before you set the src attribute.
Related Links:
Mozilla on Image.onload()
Example Usage:
window.onload = function () {
var logo = document.getElementById('sologo');
logo.onload = function () {
alert ("The image has loaded!");
};
setTimeout(function(){
logo.src = 'https://edmullen.net/test/rc.jpg';
}, 5000);
};
<html>
<head>
<title>Image onload()</title>
</head>
<body>
<img src="#" alt="This image is going to load" id="sologo"/>
<script type="text/javascript">
</script>
</body>
</html>
You can use the .complete property of the Javascript image class.
I have an application where I store a number of Image objects in an array, that will be dynamically added to the screen, and as they're loading I write updates to another div on the page. Here's a code snippet:
var gAllImages = [];
function makeThumbDivs(thumbnailsBegin, thumbnailsEnd)
{
gAllImages = [];
for (var i = thumbnailsBegin; i < thumbnailsEnd; i++)
{
var theImage = new Image();
theImage.src = "thumbs/" + getFilename(globals.gAllPageGUIDs[i]);
gAllImages.push(theImage);
setTimeout('checkForAllImagesLoaded()', 5);
window.status="Creating thumbnail "+(i+1)+" of " + thumbnailsEnd;
// make a new div containing that image
makeASingleThumbDiv(globals.gAllPageGUIDs[i]);
}
}
function checkForAllImagesLoaded()
{
for (var i = 0; i < gAllImages.length; i++) {
if (!gAllImages[i].complete) {
var percentage = i * 100.0 / (gAllImages.length);
percentage = percentage.toFixed(0).toString() + ' %';
userMessagesController.setMessage("loading... " + percentage);
setTimeout('checkForAllImagesLoaded()', 20);
return;
}
}
userMessagesController.setMessage(globals.defaultTitle);
}
Life is too short for jquery.
function waitForImageToLoad(imageElement){
return new Promise(resolve=>{imageElement.onload = resolve})
}
var myImage = document.getElementById('myImage');
var newImageSrc = "https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620"
myImage.src = newImageSrc;
waitForImageToLoad(myImage).then(()=>{
// Image have loaded.
console.log('Loaded lol')
});
<img id="myImage" src="">
You could use the load()-event in jQuery but it won't always fire if the image is loaded from the browser cache. This plugin https://github.com/peol/jquery.imgloaded/raw/master/ahpi.imgload.js can be used to remedy that problem.
If the goal is to style the img after browser has rendered image, you should:
const img = new Image();
img.src = 'path/to/img.jpg';
img.decode().then(() => {
/* set styles */
/* add img to DOM */
});
because the browser first loads the compressed version of image, then decodes it, finally paints it. since there is no event for paint you should run your logic after browser has decoded the img tag.
Here is jQuery equivalent:
var $img = $('img');
if ($img.length > 0 && !$img.get(0).complete) {
$img.on('load', triggerAction);
}
function triggerAction() {
alert('img has been loaded');
}
Not suitable for 2008 when the question was asked, but these days this works well for me:
async function newImageSrc(src) {
// Get a reference to the image in whatever way suits.
let image = document.getElementById('image-id');
// Update the source.
img.src = src;
// Wait for it to load.
await new Promise((resolve) => { image.onload = resolve; });
// Done!
console.log('image loaded! do something...');
}
these functions will solve the problem, you need to implement the DrawThumbnails function and have a global variable to store the images. I love to get this to work with a class object that has the ThumbnailImageArray as a member variable, but am struggling!
called as in addThumbnailImages(10);
var ThumbnailImageArray = [];
function addThumbnailImages(MaxNumberOfImages)
{
var imgs = [];
for (var i=1; i<MaxNumberOfImages; i++)
{
imgs.push(i+".jpeg");
}
preloadimages(imgs).done(function (images){
var c=0;
for(var i=0; i<images.length; i++)
{
if(images[i].width >0)
{
if(c != i)
images[c] = images[i];
c++;
}
}
images.length = c;
DrawThumbnails();
});
}
function preloadimages(arr)
{
var loadedimages=0
var postaction=function(){}
var arr=(typeof arr!="object")? [arr] : arr
function imageloadpost()
{
loadedimages++;
if (loadedimages==arr.length)
{
postaction(ThumbnailImageArray); //call postaction and pass in newimages array as parameter
}
};
for (var i=0; i<arr.length; i++)
{
ThumbnailImageArray[i]=new Image();
ThumbnailImageArray[i].src=arr[i];
ThumbnailImageArray[i].onload=function(){ imageloadpost();};
ThumbnailImageArray[i].onerror=function(){ imageloadpost();};
}
//return blank object with done() method
//remember user defined callback functions to be called when images load
return { done:function(f){ postaction=f || postaction } };
}
This worked for me:
// Usage
let img = await image_on_load(parent_element_to_put_img, image_url);
img.hidden = true;
// Functions
async function image_on_load(parent, url) {
let img = element(parent, 'img');
img.src = url;
await new Promise((resolve, reject) => {
element_on(img, 'load', () => {
resolve();
});
element_on(img, 'error', () => {
reject();
});
});
return img;
}
function element(parent, tag_name, text = '') {
let result = document.createElement(tag_name);
element_child_append(parent, result);
element_html_inner(result, text);
return result;
}
function element_child_append(parent, result) {
parent.appendChild(result);
}
function element_html_inner(result, text) {
result.innerHTML = text;
}
function element_on(e, event, on_event) {
e.addEventListener(event, async () => {
await on_event();
});
}
If you are using React.js, you could do this:
render() {
// ...
<img
onLoad={() => this.onImgLoad({ item })}
onError={() => this.onImgLoad({ item })}
src={item.src} key={item.key}
ref={item.key} />
// ...
}
Where:
- onLoad (...) now will called with something like this:
{ src: "https://......png", key:"1" }
you can use this as "key" to know which images is loaded correctly and which not.
- onError(...) it is the same but for errors.
- the object "item" is something like this { key:"..", src:".."}
you can use to store the images' URL and key in order to use in a list of images.

Categories