Jquery img added through append() triggers onload twice - javascript

The code that produces the headache for me is rather simple:
$(function(){
$("#test").append('<img onload="alert(\'hi\')" src="Image.jpg"/>');
})
I have the above code in my head and a div with id 'test' in the body. Now my problem is that the page produces two alerts when the image is loaded, but I expected it to produce only one as the 'onload' should be triggered only once- The way it happens when I add the image manually without any javascript..
See the fiddle I made at: http://jsfiddle.net/9985N/
Any help/explanation is greatly appreciated...

UPDATED (Because some people don't believe me, lol)
Because .append creates the node first and then moves it to its appropriate position. Try appending the element first then adding its attributes as follow:
$(function() {
$("#test").append(
$("<img />").attr({
src: "http://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Bachalpseeflowers.jpg/300px-Bachalpseeflowers.jpg",
onload: "alert(\'hi\')"
})
);
});
My answer does not "avoid" the problem, it answers it very directly. If you open the jQuery.js file in uncompressed format you can clearly see that .append creates the node on the document which is when the onload event is first called and then shifts it into position which is when it gets called again. Perhaps shift is the wrong word, forgive me as vocabulary is not my strong suit. However if you follow the code you see its creation and its movement, however the same is not said for using append again to move it, as the node is already created it simply moves from one element to another with no respark of onload. As I said, not sure best terminology, but it's very easy to follow along on the jQuery.js.
Don't believe me? Just tested the following fiddle in MSIE9, FF12, & GoogleChrome20 with 0 problems.
jsFiddle
just FYI, it's not really a horrible practice, but I see people write whole lines of HTML in jQuery all the time and that kind of defeats the purpose. It's a library with many books to read on purpose. Sometimes a complete line of HTML might seem easier, but it may not be faster as it doesn't follow all the great layout work that has been done for you. The idea is to "Write less, do more" and this includes HTML. After all, if you were gonna write the whole line of HTML, why use jQuery at all when you could just PHP it in!? :P Just a thought.

or this:
var img = $('<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Bachalpseeflowers.jpg/300px-Bachalpseeflowers.jpg"/>').on('load', function(){
$('#test').append(img);
alert('loaded');
});

Related

Cloning more than one image javascript

I'm trying to use this glitch effect in a slideshow, so it can work I have to clone the source image 3 more times. The first image works just fine, it's when I try to add the second image of the slideshow that the problem comes up. Instead of cloning que second image itself, the first image kind of reads that like one of it's clone.
Here's a fiddle of what I got so far https://jsfiddle.net/oqbf6kkc/
I think the main problem is the javascript but I can't really understand.
$(document).ready(function(){
$(".glitch-image img").clone().appendTo(".glitch-image").end()
})
Trailing commas are always a problem.
Please remove the comma present in front of nth-child selector
.glitch-image img:nth-child(2), {
Also, I am not sure about the effect you mentioned but there is some problem with your JS code as well. You are not iterating over all of the elements.
$(document).ready(function(){
$(".glitch-image img").clone().appendTo(".glitch-image").end()
})
I made some changes to your code.
Check them here.

JavaScript - dynamic SVG - onload attribute - event not triggered

Inserting dynamic SVG content into the DOM does not work as expected, having the SVG element onload attribute (containing JavaScript) regarding: "setInterval()".
As noted in the search tags of this question; this is plain (valilla) JavaScript (not jQuery); here's a breakdown of the issue:
I have some SVG code (plain text) that gets inserted into a <div> as innerHTML
the SVG element has an onload attribute with some JavaScript inside it
the JavaScript contains setInterval(...) - (which does not work at all)
I grab the SVG element from the temporary div and return it as the result of a function.
this result is appended into some element in the live DOM (body)
the strange issue:
any other code inside that onload attribute works fine,
only setInterval & setTimeout is completely ignored
More info:
During runtime (start-up), the SVG code is grabbed from an existing embed element .getSVGDocument() (after it has loaded) and prepared as plain HTML which can just be used as a template to create many others from the same source-code. I'm not using cloneNode(true) -because: the interval is for animation (continuous slow & smooth rotation) - which could have a heavy impact on client-side resources, hence, I thought it best to grab the code and keep it as template - then remove the original from the DOM.
With all the above in mind, everything works fine:
The (new) SVG shows up on screen, all nice and dandy-like
When I console.log the (inline) SVG code that is used, all looks perfect
I get no errors, and there is no error handler that mutes errors (window.onerror == null)
The JavaScript (text) inside the SVG node's onload attribute works for things like: console.log(this) - (which produces the SVG element in the log) - however, as mentioned: setInterval() & setTimeout() is just simply ignored - without any error and no warning.
The following code is a very short example, and (regrettably) it works; however, in my production app it doesn't.
The code:
var html = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" onload="setInterval(function(){ console.log(\'testing\'); },500);">';
var temp = document.createElement('div'); temp.innerHTML = html;
var node = temp.getElementsByTagName('svg')[0];
document.body.appendChild(node);
If you test the above code in a new js file, it works; however, for the life of me I can't find the reason why it breaks in my app; as explained, it's quite simple really.
The question:
Does anyone know if there is some "gotcha" I'm not aware of regarding this? Maybe name-spacing?
If the source-code is required, I can load it up on JSFiddle, or CodePen -if required, but, it's a lot of code, and many files, which may not be necessary for publication.
I'm sure it's just something small; like, how timers register according to scope, and maybe how it's affected in .bind() ?
I'm really stuck with this, and I kinda need it working for a good impression for a job-interview; so if you know anything that could help, I would appreciate your input very much.
Thank you.
embedded content, onload attributes & the DOM
The following may help in related scenarios:
when targeting an asynchronous source, make sure the contentDocument or getSVGDocument() contains the resources you need to access. The window.onload, or the DOMContentLoaded event is relative to the current DOM, so it may help constructing your own listener->trigger for a cross-browser solution, because the contents you need may not be ready in a synchronous fashion.
the onload attribute/event is not triggered when inserting dynamic content that is not asynchronously loaded, but may fire under certain circumstances, so, again, a custom:
listen->trigger will solve that.
question specific
The question is directly related to the 2nd point above, and the answer is quite simple really:
in the "onload" attribute of said SVG, set a simple value as property of this like:
<svg onload="this.ready = true; setTinterval(...)"
in the constructor function, after the element was dynamically created, simply check if the svg-node's onload event was fired like so:
if (!svgNode.ready){ svgNode.onload(); }
If there is an error in your code, but no error is shown, make sure window.onerror is either null -or if it's a function, make sure it does NOT return true - else it may suppress errors and you'll have a hard time tracking down what's wrong.
Please feel free to either improve this answer, or comment and I'll improve it accordingly; however, better answers will be appreciated.
6 years later...
With vanilla JavaScript Web Components you can do:
<load-svg></load-svg>
<script>
customElements.define("load-svg", class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<svg></svg>`;
setInterval(() => {
console.log("testing");
}, 500);
}
});
</script>

jQuery .attr Not Working Properly, Miss-Retrieving Links

This is a page I'm currently working on as a project
$(function() {
$(".modal-launcher, #modal-background").click(function() {
$(".modal-content, #modal-background").toggleClass("active");
$(".vid-1i").attr("src", "link1");
$(".vid-2i").attr("src", "link2");
$(".vid-3i").attr("src", "link3");
$(".vid-4i").attr("src", "link4");
$(".vid-5i").attr("src", "link5");
$(".vid-6i").attr("src", "link6");
$(".vid-7i").attr("src", "link7");
$(".vid-8i").attr("src", "link8");
//$('html').toggleClass('active').css('top', -(document.documentElement.scrollTop) + 'px');//
});
});
above the actual links are replaced just to display a quick idea of the bad jQuery.
In it, I am attempting to create my own popup launcher for videos; however, I am having trouble using jQuery to replace the "" src of an iframe element to a YouTube link. I am unable to figure out why the jQuery is not working. I understand that the jQuery is, of course, working properly, and that it is me who has written the code incorrectly, but here I am asking if anyone is able to figure out what it is I've done wrong, or what can be changed to make it work.
For some reason, the last video in the jQuery list is always the one retrieved.
Understand that the images are missing from the page due to them being local files and not network locations. Clicking above the captions that read like "Match One" will have the "intended" result, regardless if the image is showing or not.
Coming back to this and understanding more of JavaScript and jQuery, my problem was simply misunderstanding the code. In order to do something like this, one function per link would be more suitable.
function video1()
{
$("#popup, #modal-background").toggleClass("active");
$("#popup").prop("src", "https://www.youtube.com/embed/7h1s15n74r3all1nk");
document.getElementById('scroll').style.cssText ='overflow:hidden';
}
complementary html would look like this:
<div onclick="video1()"></div>
The previous code would run each line, effectively setting the last link as the source of the element. The new code is button independent, ensuring only one link belongs to each button.

Image gallery pagination

I have created the following image gallery.
http://jsfiddle.net/sfiddle/Nf7yR/7/
I think the thing is, that even though I can get a hand on the paragraphs css, the currentIndex won't update, i.e. an event listener seems to be missing.
var thumb = document.getElementById("thumb");
myParagraphs = thumb.getElementsByTagName("p");
console.log(myParagraphs[1]);
function thumby(){
$(myParagraphs[currentIndex]).css("background-color", "red");
}
thumby();
The thing is that I can not manage to link the image index with the index of the pagination dot (which has a normal p tag).
I want to code it in that way that if the first picture is displayed the first dot is red, if the second image is displayed the second ...
How could I approach this?
Thanks for any good advice as I invested a few hours already but can not get my head around it.
PS: no, I want no plugin or ready made imagegallery, I want my approach to work :-)
You made a function thumby() but you are calling it only once (during script start). You just need to call it when you change currentIndex. Here you have fixed code: http://jsfiddle.net/Nf7yR/10/ (I commented my edits).
BTW your code looks terrible. You should indent it properly to make it easier to read :)

Javascript getElementById - reading works, altering doesn't

So, I have this pretty complex ajax thing going.
It loads new html (including div tags and all) to show up on the page.
I included a 'more' link to load additional data.
This more link links to my javascript function. The 'more' link is located in a div, which I gave a unique id. The next time the load function is called, I use document.getElementById(the id).style.display="none"; to "remove" this div from the look of the page.
I set error traps for this, the div with that id is found without problems, but javascript fails to change my style property.
I tested alert(document.getElementById(the id).innerHTML); and that worked without problems - hence the title of the question.
So, does anyone have any ideas/do I need to offer more information? The main problem is that it doesn't throw any errors anywhere, yet it fails to complete the task I asked...
Here's a bit of code to go with it -
try
{
var myidthing = "morelink" + ContentStart.toString(); //the id is correct
var div = document.getElementById(myidthing);
if (!div)
{
}
else
{
div.style.display="none"; //this doesn't work, but doesn't raise an error
alert(div.innerHTML); //this works without problem
}
}
catch(theerr)
{
alert(theerr);
}
------------------------->EDIT<-------------------------
I'm incredibly sorry if I upset any people.
I'm also angry at myself, for it was a stupid thing in my code. Basically, I had a variable that stored the contents of a parent div. Then I (succesfully) removed the div using the removeChild() method. Then my code pasted the contents of that vaiable (including the div I wanted gone) back into the parent div.
I switched around the order and it works fine now.
Again, excuse me for this.
Throwing out a few ideas of things to look for:
You said the div is generated by javascript. Is it possible the div you are targeting is not the one you think you are? It could be you are targeting another div, which is already hidden, or obstructed... or maybe the innerHTML you are displaying goes with a different element than the one you intend to target. Put an alert or script breakpoint in the if(!div) case, also, and see if it's going down that path.
If the above code is only a stripped-down version of your actual code, check your actual code for typos (for example: style.display = "none;";)
Using the FireBug plugin for FireFox, inspect the target element after the operation completes, and make sure that the display: none appears in the style information. If not, use FireBug's debugger to walk through your javascript, and see if you can figure out why.
Use FireBug to break on all script errors, in case there is another error causing this behavior.
Try empty quotes instead of 'none' and see if that works?:
document.getElementById('element_id').style.display="";
Failing that, don't change the style, just add a class which hides the element.

Categories

Resources