When my document loads, I'd like to have JavaScript reload my images' sources. To do so, I got the following code in my HTML document:
<img src="#" id="mypic" onload="reloadImage(this);"/>
and in my JavaScript document:
function reloadImage(imageElement) {
imageElement.src = "http://www.somedomain.com/image.png";
}
However, this doesn't work. Am I using this incorrectly, or does the problem lie elsewhere?
The syntax you use is correct in principle. The problem is that for the URL #, being an invalid image URL, the load event is probably never fired.
You're using this correctly, however that looks like something that might result in your function being called repeatedly if the image loads, however I doubt an image loaded from # is going to ever load. Are you sure that's what you want?
(Why are you calling your code a "document"?)
The code SHOULD work, however since you do not have an image in the tag, the onload has nothing to trigger on
Try this
<img src="blank.gif" id="mypic" onload="reloadImage(this);"/>
and test
if (imageElement.src.indexOf('blank')!=-1) imageElement.src="http://www.somedomain.com/image.png";
Related
I want to block all the images of any web page to lower the page loading time, consider the web page source code is loaded into browser but the documents/files still needed to be downloaded, is there any event to cover this problem?
I think can method must be followed in browsers text only mode.
No. If the src tag is already set the browser will Load the images no matter what. Remove the src tag after it was loaded doesn't change the fact that it was already downloaded.
The only way to avoid this is to set the src tags of imgs by Javascript dynamicly. And therefore not set images if you don't want to.
You can't make the browser not loading images if it's already in the html.
I'm not sure if it solves your problem but maybe you can try this:
<script type="text/javascript">
$(document).ready( function() { $("img").removeAttr("src"); } );
</script>
<div class="image"><img external-src="original.jpg" src="fake.jpg" /></div>
$(window).load(function(){
$('.image img').attr("src", $(this).attr('external-src')).removeAttr('external-src');
});
This will load all the images after whole dom loaded
You can remove the whole img tag
$("img").remove();
or you can just remove the image tag source attribute
$("img").removeAttr("src");
or you can just replace all the image source having shorter loading time
$("img").attr("src",'http://someimage.jpg');
This may be a dumb question, but I've a real confusion and want to get an opinion from somebody who knows this in-out.
Preloading images can be done either via JavaScript or CSS (to name two which I'm considering). I read the tutorials that if the browser finds the same image path again, it would render the cached image.
If I preload images like:
<img src="../images/bg.jpg" alt="background" width="1" height="1" style='display:none' />
and
<img src="images/bg.jpg" alt="background" />
Similar with javascript:
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
});
}
// Usage:
preload([
'../img/imageName.jpg',
'img/imageName.jpg' // case when using this script in a different hierarchical level)
]);
Will the second call result into rendering of the image from the cached version or it will not work because the image path specified is different (though ultimately it refers to the same file).
Thanks in advance.
I realise this is and old one but I get this one all the time from interns - so here goes...
Even though the onload function is in the JS file asking/telling the browser to look for the image; it is the browser looking for the image and is telling the JS that the image/s loaded.
So your image path in the JS should be the same as how you would enter it in the HTML.
PS: I noticed in your HTML the image folder is "/images" and in your JS the folder is "/img"
I'm running a Javascript replace function to replace standard images with class="replace-2x"on my jQuery Mobile site with Retina-quality images if the user is on a mobile device with Retina display. For example, on a Retina device, logo.png will be replaced with logo#2x.png. The JS function is here:
function highdpi_init() {
$(".replace-2x").each(function () {
var src = $(this).attr("src");
$(this).attr("src", src.replace(".png", "#2x.png").replace(".jpg", "#2x.jpg"));
});
}
$(".page").live('pageinit',function(event){
highdpi_init();
});
I'm now running into an issue where the replace function is running more than once. So for example, it replaces logo.png with logo#2x.png as the page is loading, but then as the page continues to load, it KEEPS replacing .png with #2x.png in the img src over and over so that the image tag ends up looking like this:
<img src="mobile/images/logo#2x#2x#2x#2x#2x#2x#2x#2x#2x#2x#2x.png" class="replace-2x" alt="logo" width="200">
How can I prevent this from replacing on a single img element more than once? Keep in mind, I will have multiple images on the same page, so the function will need to apply to all images, but only one time each.
The problem is surely that your 'pageinit' event is being called more than once. You can either follow MДΓΓ БДLL's idea (which won't work if images are dynamically added) or you can make your handler smarter so that it doesn't replace the src if it already was replaced
function highdpi_init() {
$(".replace-2x").each(function () {
var $this = $(this);
var src = $this.attr("src");
$this.attr("src", src.replace(".png", "#2x.png").replace(".jpg", "#2x.jpg"));
// Remove the class so it doesn't replace it again
$this.removeClass('replace-2x')
});
}
You don't need JS for this, you could do it in CSS only.
<link rel="stylesheet" media="only screen and (-webkit-min-device-pixel-ratio: 2)" href="/css/highdpi.css"/>
You could make your images look like
<img src="transparent.gif" class="logo-a" alt="logo" width="200" />
And in highdpi.css you could do
img.logo-a {
background-image: url('file#2x.png')
}
And in lowdpi.css
img.logo-a {
background-image: url('file.png')
}
Using .one() should work since it is just a binding and if you are using Jquery Mobile the way that is suggested it will be just fine. That is unless you are passing back the html from the server. In which case it would be a good idea to add an extra condition to make sure that the src doesn't already have #2x.png before replacing.
There is disappointingly little documentation on pageinit on the offical jQuery Mobile docs. So I'm going to speculate here. It looks like pageinit is used to fire events for when a specific DOM element has finished loading, since it may not have been loaded on the initial page load (deferred until needed). That being said, it may be that adding/altering images to the DOM element in question fires the pageinit again. Could you tag each updated image with something that says, 'hey, I've already been updated to 2x'? Something such as
$.data(targetimg, 'retinafied', true);
And then check for that value before replacing the src?
I'm attempting to call a javascript function (in our code) from a silverlight control. I'm attempting to call the function via:
HtmlPage.Window.Invoke("showPopup", new string[] { "http://www.example.com" });
and I get the error "Failed to Invoke: showPopup"
I can call HtmlPage.Window.Invoke("alert", new string[]{"test"}); without issue, but not my own function.
I can also open up the page in question in the IE developer tools and manually call showPopup("http://www.example.com") and it works as expected.
So the js function works, and the Silverlight binary can find other js functions. What am I missing here?
Additional Notes:
The function call is in a button click event handler, so it happens after the page (and the script) have been loaded)
Aha! I figured it out. Our app uses an iframe, so the rendered html looks something like this
<html>
<head></head>
<body>
Stuff
<iframe>
<html>
<head></head>
<body>Other Stuff</body>
</html>
</iframe>
<body>
</html>
And the Silverlight control in question is in the iframe. The problem was that the file that contained the showPopup function was referenced in the outer <head> (why I could call the function with the IE toolbar) but not the inner <head>. Adding a reference to the file in the in-the-iframe <head> solved the problem.
Sort of anticlimactic, but thanks for all the help.
Actually referencing the script again from the iframe is not the most efficient way to reference code contained in the parent. If your function is called "showPopup", you can insert this in your iframe:
<script type="text/javascript">
var showPopup = parent.showPopup;
</script>
And voilà. The explanation for this is that all "global" functions and objects are part of this "global namespace"... which is the "window" object. So if you're trying to access "global" functions from a child, you need to either call the function on the parent (e.g parent.showPopup('....')) or declare a local alias for it (which is what we do in the above example).
Cheers!
Is the showPopup javascript function on the same html or aspx page as the Silverlight control? You will normally get the "Failed to Invoke ..." error if the javascript function does not exist:
HtmlPage.Window.Invoke("functionThatDoesNotExist", new [] { "Testing" });
What browser are you using when you are getting this problem?
Are you using the latest version of Silverlight?
Are you using the ScriptableType attrbiute anywhere?
Is it possible to list the code for a short but complete program that causes this problem to happen on your machine...
Make sure your script is fully loaded before trying to invoke functions from it.
Here's how I do it. But I'm creating silverlight without visual studio. I just have raw html, xaml, and js (javascript). Notice MouseLeftButtonUp and it's value "LandOnSpace"
<Canvas x:Name="btnLandOnSpace" Background="LightGreen" MouseLeftButtonUp="LandOnSpace"
Cursor="Hand" Canvas.Top ="0" Width="70" Height="50">
<TextBlock Text="LandOnSpace" />
</Canvas>
function LandOnSpace(sender, e) { //on server
if (!ShipAnimateActive && !blnWaitingOnServer) {
blnWaitingOnServer = true;
RunServerFunction("/sqgame/getJSLLandOnSpace");
ShowWaitingBox();
};
else {
alert('Waiting on server.');
};
}
I had the same problem in VS 2010 with SL 4. I had created a few methods and put them into one single JS file. However this file had not been added to the head section of the ASPX file. Adding it solved the problem. The difference is that though I did not have a separate head section in the iframe, I had the problem and it got solved.
Is it possible to call a JavaScript function from the IMG SRC tag to get an image url?
Like this:
<IMG SRC="GetImage()" />
<script language="javascript">
function GetImage() {return "imageName/imagePath.jpg"}
</script>
This is using .NET 2.0.
Nope. It's not possible, at least not in all browsers. You can do something like this instead:
<img src="blank.png" id="image" alt="just nothing">
<script type="text/javascript">
document.getElementById('image').src = "yourpicture.png";
</script>
Your favourite JavaScript framework will provide nicer ways :)
If you're in the mood for hacks, this works as well.
<img src='blah' onerror="this.src='url to image'">
Is it possible to call a JavaScript function from the IMG SRC tag to get an image url?
Do you mean doing something like the following?
<img src="javascript:GetImage()" />
Unfortunately, no - you can't do that. However, you can do the following hack:
function getImageUrl(img) {
var imageSrc = "imageName/imagePath.jpg";
if(img.src != imageSrc) { // don't get stuck in an endless loop
img.src = imageSrc;
}
}
Then, have the following html:
<img src="http://yourdomain.com/images/empty.gif" onload="getImageUrl(this)" />
The onload event will only fire if you have an actual image set to the src attribute - if you don't set that attribute or set it to an empty string or something similar, you will get no love. Set it to a single pixel transparent gif or something similar.
Anyway, this hack works, but depending on what you are really trying to accomplish, this may not be the best solution. I don't know why you would want to do this, but maybe you have a good reason (that you would like to share with us!).
You cannot do it inline the image #src, but you should be able to call it from an inline script block immediately following your image:
<img src="" id="myImage"/>
<script type="text/javascript">
document.getElementById("myImage").src = GetImage();
</script>
you could dynamically feed the image by calling an aspx page in the SRC.
Ex;
<img src="provideImage.aspx?someparameter=x" />
On the page side, you`ll need to put the image in the response and change the content type for an image.
The only "problem" is that your images won't be indexed a you better put some cache on that provider page or you'll ravage the server.
Are you looking for this.src ?`
<img src='images/test.jpg' onmouseover="alert(this.src);">
Since you're using .NET, you could add the runat="server" attribute and set the src in your codebehind.
You might be able to do it on the server side. Alternately you could attach an onload event to swap the image src out. I guess the question then becomes, why would you have to use Javascript in the first pace?
I've had to do something like this before, and IIRC the trick winds up being that you can't change an src attribute of an image that's part of the DOM tree. So your best bet is to write your HTML skeleton without the image and 1)create an onLoad function that generates a new img element with document.createElement, 2) set the src attribute with setAttribute(), and 3) attach it to your DOM tree.
OnLoad event of image called again and again do some thing like this
how about this?
var imgsBlocks = new Array( '/1.png', '/2.png', '/3.png');
function getImageUrl(elemid) {
var ind = document.getElementById(elemid).selectedIndex;
document.getElementById("get_img").src=imgsBlocks[ind];
}
it's not work?
<img src="'+imgsBlocks[2]+'" id="get_img"/>
You may try this way also
const myImage = new Image(200, 200);
myImage.src = 'data:image/jpeg;base64,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';
document.body.appendChild(myImage);
No. The Img's SRC attribute is not an event, therefore the inline JS will never fire.
OnLoad event of image called again and again do some thing like this