This question already has answers here:
window.onload vs $(document).ready()
(17 answers)
Closed 6 years ago.
OVERVIEW: I'm creating DOM elements via javascript and then trying to access them. The problem is that they don't exist in the DOM (or that's the way I read it.)
function init(){
pagination();
}
window.onload = init;
In pagination I make create a DOM element called "more"
var more='<div id="more" class="box move"> > </div>';
This, along with all the other elements are displayed in the "Elements" section of the console log. Sweet. It's in the DOM isn't it (no).
I tried to call this div with jQuery but was unable to. I checked to see it existed. It does not.
console.log($("#more").length);
I made a dummy div in the html to see if jQuery was actually working. I checked it's length and yup it was there.
$(document).ready(function(){
console.log($("#aaa").length); // returns 1
console.log($("#more").length); // returns 0
The question is: what is the best way to have jQuery read these DOM elements?
Does my window.onload solution clash with jQuery's $(document).ready statement?
The code is as follows
function initFunction1(){ ...}
function initFunction2(){ ...}
...
function init(){
initFunction1();
initFunction2();
}
window.onload = init;
$(document).ready(function(){
}); // END jQuery
EDIT ADDED ENTIRE CODE SAMPLE
<!doctype html>
<head>
<meta charset="utf-8">
<title></title>
<link rel ="stylesheet" href="pagination3.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
</head>
<body>
<div id="aaa">aaa</div>
<div id="pagination"></div>
</body>
<script src="pagination.js"></script>
</html>
// pagination.js below
function pagination(){
var myPagination=document.getElementById("pagination");
var myDivStart='<div class="box">';
var myDivEnd='</div>';
/* */
var first='<div id="first" class="box move"> FIRST </div>';
var last='<div id="last" class="box move"> LAST </div>';
var less='<div id="less1" class="box move"> < </div>';
var less10='<div id="less10" class="box move"> < 10 </div>';
var less100='<div id="less100" class="box move"> < 100 </div>';
var more='<div id="more1" class="box move"> > </div>';
var more10='<div id="more10" class="box move"> 10 > </div>';
var more100='<div id="more100" class="box move"> 100 > </div>';
/* */
var radioButtonStart='<input type="radio" name="pagination" id="radio';
var radioButtonLabelStart='"><label for="radio';
var radioButtonLabelEnd='">';
var radioButtonEnd='</label>';
myPagination.innerHTML = first + less100 + less10 + less;
for(i=640; i<650; i++){
// myPagination.innerHTML += myDivStart + i + myDivEnd;
myPagination.innerHTML += radioButtonStart + i + radioButtonLabelStart + i + radioButtonLabelEnd + i + radioButtonEnd;
}
myPagination.innerHTML += more + more10 + more100 + last;
return myPagination;
}
function init(){
pagination();
}
window.onload = init;
$(document).ready(function(){
console.log($("#aaa").length);
console.log($("#more10").length);
$("#more10").click(function(){
console.log("aaa");
/*
1.get last radio button
2.add ten
3.send to for loop and recalculate
*/
var lastRadio="sss";
console.log(lastRadio);
});
}); // END jQuery
Some issues:
the jQuery ready callback is triggered before the window.onload callback. The jQuery ready event corresponds to the DOM's document.DOMContentLoaded event, and the DOM's load event to jQuery's load event.
You mix jQuery and native DOM API calls. This is not a problem in itself, but if you are willing to use the native DOM API, why use jQuery at all? Or if you want to use jQuery, why still use the longer syntax of the native DOM API?
There seems no good reason to respond to the load event; you could just join the two pieces of code and execute them on ready
So, remove this line:
window.onload = init;
Add add a call to init at the start of your ready handler:
$(document).ready(function(){
init();
console.log($("#aaa").length);
console.log($("#more10").length);
$("#more10").click(function(){
// ... etc.
});
});
That way you'll see the #more10 is found, and the click handler works.
Related
This question already has an answer here:
How to change image with fading
(1 answer)
Closed 3 years ago.
I'm quite new to js and jquery and I'm trying to do something very simple for my Rails app: I want to switch between 2 images every 3 seoncs with a fading effect. The problem is that I'm obtaining an error but don't know how to solve it (it's a typical error from what I've read but I had no luck in fixing it). I tested my code with jsfiddle and it works fine but when I run my app I get this error in the web console:
TypeError: $("#img").fadeOut is not a function.
Here is my code:
HTML code
<div class="container p-5">
<div class="row">
<div class="col">
<h2 class="display-5 mb-4">Title here</h2>
<p class="lead">Lead</p>
</div>
<div class="col">
<img id="img" src="http://localhost:3000/images/pdf_template.png" />
</div>
</div>
</div>
jquery code
<script type = "text/javascript">
var images = [];
images[0] = "http://localhost:3000/images/pdf_template.png";
images[1] = "http://localhost:3000/images/watermark_template.png";
var x = 0;
setInterval(displayNextImage, 3000);
function displayNextImage() {
x = x < images.length - 1 ? x : 0;
$("#img").fadeOut(300, function(){
$(this).attr('src', images[x]).fadeIn(300);
})
x++;
}
</script>
As I said, the code is working in a jsfiddle, so I suspect the problem is coming from my rails app but I didn't find anything relevant on google about it. The jquery code is located in my application.html.erb, in the head of the file. I managed to make some other jquery code works (an automatic image change but without fade effect) without any issue but this won't work.
I'm using Rails 5.2.3, jquery-rails 4.3.5, jquery 3.2.1
Any help would be appreciated, thanks.
I'm answering my own question here. #dbugger pointed out that it was a good practice to wrap functions in jquery in a document ready block. So here it is if anyone needs it:
jquery code
jQuery( document ).ready(function( $ ) {
var images = [];
images[0] = "http://localhost:3000/images/pdf_template.png";
images[1] = "http://localhost:3000/images/watermark_template.png";
var x = 0;
setInterval(displayNextImage, 3000);
function displayNextImage() {
x = x < images.length - 1 ? x : 0;
$("#img").fadeOut(300, function(){
$(this).attr('src', images[x]).fadeIn(300);
})
x++;
}
});
As you can see, the only change here is the addition of the jQuery( document ).ready(function( $ ) {}); block.
I am trying to write some code and I have one issue. Basically I am trying to write some statements (ifs, else etc) and I need to access some <p> elements from different <div> sections.
<body>
//works with the one below = changes its value from x to 10
<p id="one" class = "class">x</p>
<script type="text/javascript">
var time = new Date().getHours();
if (time < 20) {
document.getElementById("one").innerHTML = "10";
document.getElementById("two").innerHTML = "10";
}
</script>
<div class="green2">
<p id ="two" class="class" >x</p>
//with this one nothing happens
</div>
I guess it doesn't reach the actual element with id two so how can I handle it?
Your script is being loaded before the two, you should put your script tag always at the very bottom of your body tags (inside them), so that all your content will be loaded first, only then your script.
To expand on Pedro's answer, you can also use jQuery and wrap everything in a document.ready function:
$(document).ready(function(){
var time = new Date().getHours();
if (time < 20) {
document.getElementById("one").innerHTML = "10";
document.getElementById("two").innerHTML = "10";
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p id="one" class = "class" >x</p>
<div class="green2">
<p id ="two" class="class" >x</p>
</div>
This way you can have the JavaScript appear anywhere on the page.
Alternatively, you can add an event listener such as jQuery's .ready() or javascript's document.onDOMContentLoaded or window.onload events. Then you may place the script where you like and the function will only be executed when the page is ready.
Simply wrap your code in the listener function like such:
<p id="one" class = "class" >x</p>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(){
var time = new Date().getHours();
if (time < 20) {
document.getElementById("one").innerHTML = "10";
document.getElementById("two").innerHTML = "10";
}
});
</script>
<div class="green2">
<p id ="two" class="class" >x</p>
</div>
I am wondering if is possible to do this.
I have my javascript function
function doSomething(){
return "Hello World"; //its actually more complicated method but the logic is the same..
}
so, at my html I have this.
<div class="someClass">
<script type="text/javascript">
doSomething();
</script>
</div>
So, basically, I want to is to print that hello world inside the div where is called.
Any idea how to do this?
AFAIK JavaScript cannot easily determine the location of its script declaration. As Marc B suggested in a comment--it works for printing to the document stream, but other applications won't work. Not to mention if you want the same behavior in multiple places, you've violated the "don't repeat yourself" (DRY) principle. You should instead inspect the dom document and find the element you wish to print "hello" in. This is easily accomplished with jQuery:
$(document).ready(function () {
$('.someClass').text('hello');
});
As laugri suggests, you should add an id to your div if you want only the one div changed.
<div id="someId".../>
...
$(document).ready(function () {
$('#someId').text('hello');
});
You can generate a unique div to find wherever you're code is executing
http://jsfiddle.net/190p77wu/
var doSomething = function (id) {
var targ = document.getElementById(id).parentNode;
targ.innerHTML = "This was inserted for id " + id;
}
and your html:
<div>
You shouldn't see this text.
<script>
var uniqueId = "tmp_" + Math.round(Math.random() * 100000000);
document.write('<div id="' + uniqueId + '"></div>');
doSomething(uniqueId);
</script>
</div>
Edit: or even cooler, if you have a properly cached JS file, you can do something like this:
http://jsfiddle.net/190p77wu/1/
var doSomething = function (script) {
var targ = script.parentNode;
targ.innerHTML = "This was inserted dynamically";
}
and this html:
<div>
You shouldn't see this text.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" onload="doSomething(this)"></script>
</div>
Try setting an id at script element , calling script.parentElement within doSomething
<div class="someClass">
<script type="text/javascript" id="someClass">
function doSomething() {
var elem = document.getElementById("someClass");
elem.parentElement.appendChild(
document.createTextNode("Hello World")
)
}
doSomething();
</script>
</div>
I am trying to create a basic image rotate. I have my images stored locally by name in a folder called comics. each comic name is comic_(plus the number). It wont do anything when I click my buttons. It wont even disable my previous button. Please help. Thank you guys.
Here is my JS/Jquery...
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$(document).ready(function() {
//declare my variables
var comic_img = $('#comicpane').find('img')
var current_comic_number = parseInt(comic_img.attr('class').replace('comic_',''))
var prev_comic = current_comic_number - 1;
var next_comic = current_comic_number + 1;
});
if (current_comic_number == 1){
//disable the prev button
$("#prev").attr('disabled','disabled');
//When the user clicks on a nav item
$(".nav_link").on('click')function(){
//Get the button they clicked
current_button = $(This);
if (current_button.attr('id')) == 'next'
{
comic_img.attr('class','comic_') + next_comic + ".jpg";
comic_img.attr('src','comics/comic_1') + next_comic;
//change variables to reflect current comic
current_comic_number +=1;
next_comic +=1;
prev_comic +=1;
}
//Only other option
else
{
comic_img.attr('src','comics/comic_1') + prev_comic + '.jpg';
comic_img.attr('class','comic_') + prev_comic;
//Change variables to reflect comic
current_comic_number -=1;
next_comic -=1;
prev_comic -=1;
}
//If comic number is less or equal to 1 and prev button is Not disabled, it needs to be disabled.
if (current_comic_number <=1 && !$('#pev').attr('disabled','disabled'))
{
$('#prev').removeAttr('disabled')
}
}
}
</script>
Here is my HTML...
<html>
<head>
<title>SRS Comic Zone</title>
<link rel="stylesheet" href="srscomiczone.css" media="screen">
</head>
<body>
<div id="header">
<img id="header" src="HeaderPicture.png" align=center>
</div>
<div class="comiczone" id="comicpane" align=center>
<img class="comic_1" src="comics/comic_1.jpg">
</div>
<div id="comicNav" align=center>
<button id="prev" class="nav_link">Previous</button>
<button id="next" class="nav_link" >Next</button>
</div>
</body>
</html>
few mistakes,
1) this is how you call a click event
$(".nav_link").on('click',function(){
....
and not
$(".nav_link").on('click')function(){ //replace this with above code
you might also need to delegate your selector if it is added dynamically.....
2)
current_button = $(This);
should be
current_button = $(this);
3) also, notice..if you are using jquery 1.6+, use prop() instead of attr()
$("#prev").prop('disabled',true);
instead of
$("#prev").attr('disabled','disabled');
4) add all your codes inside document.ready $(document).ready(function(){ //here }); function and not outside.
5) most important, you either have to include the script (js file) inside you html page. or paste all your script codes inside <head> tag of your HTML file
Also this stuff should be wrapped by:
$(document).ready(function() {
$(".nav_link").on('click',function(){
...
});
not just your var declarations.
Your code is trashy. Better use tool like JS Hint (or other JS validator, or even Chrome/Firefox with web console) to actually make sure code can even run.
Here are (some) of the issues with it:
you're missing semicolons
your .ready() function is (as I believe) ending prematurely
you're doing click handling wrong (pointed out by #bipen)
your if statements are messed up
you (probably) haven't included scripts into the HTML document
Ad 1
Missing semicolon here:
var comic_img = $('#comicpane').find('img')
Ad 2
current_comic_number is a local variable in $.ready(), but it's used outside of this function
Ad 3
It's not valid JS (see #bipen's answer):
$(".nav_link").on('click')function(){
Ad 4
It's not valid if statement:
if (current_button.attr('id')) == 'next'
it should be:
if (current_button.attr('id') === 'next')
Ad 5
Use <script> tag only inside *.html file, not in *.js. On example:
<script src="main.js"></script>
Then, put all of your JS code into main.js file.
I'm working on a web page where I'm making an AJAX call that returns a chunk of HTML like:
<div>
<!-- some html -->
<script type="text/javascript">
/** some javascript */
</script>
</div>
I'm inserting the whole thing into the DOM, but the JavaScript isn't being run. Is there a way to run it?
Some details: I can't control what's in the script block (so I can't change it to a function that could be called), I just need the whole block to be executed. I can't call eval on the response because the JavaScript is within a larger block of HTML. I could do some kind of regex to separate out the JavaScript and then call eval on it, but that's pretty yucky. Anyone know a better way?
Script added by setting the innerHTML property of an element doesn't get executed. Try creating a new div, setting its innerHTML, then adding this new div to the DOM. For example:
<html>
<head>
<script type='text/javascript'>
function addScript()
{
var str = "<script>alert('i am here');<\/script>";
var newdiv = document.createElement('div');
newdiv.innerHTML = str;
document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>
You don't have to use regex if you are using the response to fill a div or something. You can use getElementsByTagName.
div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
eval(scripts[ix].text);
}
While the accepted answer from #Ed. does not work on current versions of Firefox, Google Chrome or Safari browsers I managed to adept his example in order to invoke dynamically added scripts.
The necessary changes are only in the way scripts are added to DOM. Instead of adding it as innerHTML the trick was to create a new script element and add the actual script content as innerHTML to the created element and then append the script element to the actual target.
<html>
<head>
<script type='text/javascript'>
function addScript()
{
var newdiv = document.createElement('div');
var p = document.createElement('p');
p.innerHTML = "Dynamically added text";
newdiv.appendChild(p);
var script = document.createElement('script');
script.innerHTML = "alert('i am here');";
newdiv.appendChild(script);
document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>
This works for me on Firefox 42, Google Chrome 48 and Safari 9.0.3
An alternative is to not just dump the return from the Ajax call into the DOM using InnerHTML.
You can insert each node dynamically, and then the script will run.
Otherwise, the browser just assumes you are inserting a text node, and ignores the scripts.
Using Eval is rather evil, because it requires another instance of the Javascript VM to be fired up and JIT the passed string.
The best method would probably be to identify and eval the contents of the script block directly via the DOM.
I would be careful though.. if you are implementing this to overcome a limitation of some off site call you are opening up a security hole.
Whatever you implement could be exploited for XSS.
You can use one of the popular Ajax libraries that do this for you natively. I like Prototype. You can just add evalScripts:true as part of your Ajax call and it happens automagically.
For those who like to live dangerously:
// This is the HTML with script element(s) we want to inject
var newHtml = '<b>After!</b>\r\n<' +
'script>\r\nchangeColorEverySecond();\r\n</' +
'script>';
// Here, we separate the script tags from the non-script HTML
var parts = separateScriptElementsFromHtml(newHtml);
function separateScriptElementsFromHtml(fullHtmlString) {
var inner = [], outer = [], m;
while (m = /<script>([^<]*)<\/script>/gi.exec(fullHtmlString)) {
outer.push(fullHtmlString.substr(0, m.index));
inner.push(m[1]);
fullHtmlString = fullHtmlString.substr(m.index + m[0].length);
}
outer.push(fullHtmlString);
return {
html: outer.join('\r\n'),
js: inner.join('\r\n')
};
}
// In 2 seconds, inject the new HTML, and run the JS
setTimeout(function(){
document.getElementsByTagName('P')[0].innerHTML = parts.html;
eval(parts.js);
}, 2000);
// This is the function inside the script tag
function changeColorEverySecond() {
document.getElementsByTagName('p')[0].style.color = getRandomColor();
setTimeout(changeColorEverySecond, 1000);
}
// Here is a fun fun function copied from:
// https://stackoverflow.com/a/1484514/2413712
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
<p>Before</p>