Can you set variables in the beginning of a file to be set through out?
Example:
var works = $('#id1');
var span = $('.icon');
works.focus(function() {
if(this.value.length == 0)
span.hide();
});
works.keyup(function() {
if(this.value.length > 0 && !span.is(':visible'))
span.stop().show();
else if(this.value.length == 0)
span.stop().hide();
});
The variable span inside the function doesn't work. Instead of adding var span = $('.icon'); in each function is it possible I can make it work?
Thanks alot
Ideally you would declare them first, then set them later when the DOM is ready.
<script>
var myFunVariable;
var anotherVariable;
$(function(){
myFunVariable = $("#someElement");
anotherVariable = $("#anotherElement").children();
});
</script>
Yes, you can have global variables, but if you initialize them in a <script> block in the <head> they'll be empty. The DOM won't have been loaded.
You can instead do this:
$(function() {
var span = $('.whatever');
$('something.else').click(function() {
// span will work here
});
});
Not quite the same as globals, but in a way that's better since true globals are kind-of a bad idea. Anything declared with var inside the $(function() { ... }) code will be effectively global to all code in that initialization function.
Oh, and note that putting the initialization code in a function invoked with $() is the jQuery way of deferring execution until the DOM is ready. That will work in a script in the <head>, and it'll also work if you import your scripts at the end of the <body> as many luminaries now advise.
Related
I have some JS in a file, and some JS on a page.
If I try to access my function via NucleusPreview, it can't be found
If I access it via window.NucleusPreview, it is found
Why is that? Am I doing something wrong, or do I need to be explicit when accessing objects in window scope when in another function?
Update: I was creating NucleusPreview inside the onReady, but moved it so I think the window scope was a red herring. The problem is that when calling it in onReady, gave it time to load the file, but when I moved it out I started calling it too early.
The JS in the the file is basically:
var NucleusPreview;
(function ($) {
NucleusPreview = function NucleusPreview(source) {
//ctor stuff
};
NucleusPreview.prototype.AdjustCaption = function AddCaption() {
//caption stuff
};
})(jQuery);
My JS on the page:
$('.nucleus-preview').each(function eachNucleusPreview(index, element) {
var jElement = $(element),
vidId = jElement.data('video-id'),
np = new NucleusPreview($(element)); //Uncaught RefError: NucleusPreview is not defined
_wq.push({
id: vidId,
onReady: function (video) {
np.AdjustCaption();
}
});
});
As long as the first bit of code you provided is executed first and none of the code is executed prior to the DOM being loaded (you can put all of this code in a document.ready() callback to ensure that is the case), you should be able to. Run this code snippet and wait a moment, you will see that it works without qualifying window.
In the example below, I've placed all the code in a document.ready() callback (although that is not required for the code to run) to ensure that you don't try to access $('.nucleus-preview') before the DOM is ready.
Additionally, doing this will keep NucleusPreview out of the global scope in the first place, which is always a good idea.
// Always make sure the DOM is fully loaded prior to scanning for DOM elements.
// This can be done by placing all of your code in a "document.ready()` callback
// function as I'm doing here or by placing the code at the end of the HTML document,
// just before the close of the body (</body>).
$(function(){
// Now NucleusPreview is scoped to this function, which keeps it out of the
// global scope and that's always good, so you don't pollute the window.
var NucleusPreview;
(function ($) {
NucleusPreview = function NucleusPreview(source) {
//ctor stuff
};
NucleusPreview.prototype.AdjustCaption = function AddCaption() {
//caption stuff
};
})(jQuery);
var _wq = []; // Added to allow code to execute
$('.nucleus-preview').each(function eachNucleusPreview(index, element) {
var jElement = $(element),
vidId = jElement.data('video-id'),
np = new NucleusPreview($(element)); // <-- Works just fine!
_wq.push({
id: vidId,
onReady: function (video) {
np.AdjustCaption();
}
});
});
});
console.log($('.nucleus-preview'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nucleus-preview"></div>
<div class="nucleus-preview"></div>
<div class="nucleus-preview"></div>
I have this code in JavaScript:
status = document.getElementById('status2');
$('#slider > img').hover(
function() {
stopLoop();
status.innerHTML = "paused";
},
function() {
startSlider();
status.innerHTML = "playing";
}
);
where I look for all the images in my html that have the id slider and when I hover on then I want to add a word (paused or playing) to a span tag that has the id status2. But I don't know why the global variable is not working, the only way that I make it work is putting a local variable inside each funcion like this:
function() {
stopLoop();
var status = document.getElementById('status2');
status.innerHTML = "paused";
},
function() {
startSlider();
var status = document.getElementById('status2');
status.innerHTML = "playing";
}
Can anyone me why?
NOTE: as I said before all works with the local variables but not setting it as a global variable.
Because by the time you run
status = document.getElementById('status2');
DOM was not ready so you get status as undefined and so it wont work further.
So either put the code in ready
$(document).ready(function(){
//code goes here
})
or
Put the script at the end of file.
Do add in a
$(document).ready(function(){
});
This waits to execute the code inside until everything has finished loading. That way it shouldn't return undefined.
ALSO
I couldn't help but noticing that you seem to be trying to give multiple items the same ID.
Don't use IDs for multiple elements. That's not how they are designed to be used, nor do they work that way.If you give multiple elements the same ID and then try and style them with CSS, it'll only style the first one. Use a class. If you use
document.getElementById();
to try and grab multiple elements with the same ID, then the script will ONLY grab the FIRST element with that ID, because, given that it is an ID, it expects only one element. If you want to work with multiple elements, use a class, and then use
document.getElementsByClassName();
this will grab ALL elements with that class. So for example,
say you have four span elements with the class "foo". To grab all these and change the text, do this:
elements=document.getElementsByClassName("foo");
for (i=0; i<elements.length; i++){
elements[i].innerHTML='insert your text here';
}
About global and local variables, a GLOBAL variable is declared this way:
global_variable='foo'
and a local variable is declared this way:
var local_variable='foo'
a Global variable can be declared anywhere in the script and be used anywhere inside the script(and even in other scripts that are attached to the same HTML file ), whereas a Local variable, if declared inside the function, can only be used inside the function, or if you declare it outside the function, it can't be accessed within the function unless you pass the variable to it.
Hope that helps!
My scenario is that I have one JS file which is being used on two HTML pages. One has a button with id="a" and the other doesn't have it. I have attached an event on id="a" by doing this.
document.getElementbyId("a").onclick = function () { .. }
My problem is when I run second file which doesn't have the button with id="a" and it throws the error
TypeError: document.getElementbyId(...) is null
which causes some unexpected behaviour! Is there any way to keep using just one JS file or should I separate the JS file for every html page?
I read a question on StackOverflow here which is about why jQuery doesn't throw an error if the selector is invalid. I need same or similar functionality with vanilla JavaScript.
The simple fix is to add a check:
if (document.getElementById("a") !== null) {
document.getElementById("a").onclick = function () /* .. */ };
}
jQuery will never break on missing elements, it just silently fails. You can argue about whether that is good or not.
The trick jQuery uses is that it will always return something. $("#id") will return a jQuery wrapper. That wrapper has functions like .on and .load and .html. A selector can match one, more or no elements. For the wrapper it doesn't matter how many elements are matched.
It works like this:
var elem = get_element("a");
elem.onclick(callback);
function get_element(id) {
var elem = document.getElementById(id);
return { // return a wrapper
onclick: function (callback) {
if (elem !== null) {
elem.onclick = callback;
} else {
// silently fail
}
}
};
}
Consider testing existance
var elm = document.getElementById("a");
if (elm) elm.onclick = function () { .. };
Or falling back in the case of a falsy
(document.getElementById("a") || {}).onclick = function () { .. };
In this second method, the function still gets set but will be quickly GC'd as the reference to {} dies by the next line.
All of the above solutions are correct. However, you should definitely move away from writing whatever.onclick = function as that is no longer the best way to write your code. Using this method, you only get one click event. Using a more modern approach allows you to attach as many events as you want.
Also, you mention jQuery but there is no jQuery in the supplied code only vanilla JavaScript. Do you need a jQuery solution or JavaScript?
JavaScript
document.addEventListener('DOMContentLoaded', function(){
var elm = document.getElementById('a');
if ( elm ) { //if the element exists add the click event
elm.addEventListener('click', function(){
//Your "onclick" code here
});
}
});
jQuery
$(function(){
$('#a').on('click', function(){
//Your "onclick" code here
});
});
I want to create an element in place where javascript function run.
<script>
var uniqid='an unique Id';
document.write('<iframe id='+uniqid+'></iframe>');
someAsyncFunction(callback)
</script>
in other part of code I set additional parameters for this element
<script>
callback=function(paramfromcallback){
getElementById(uniqid).url=paramfromcallback;
}
</script>
but this is not work in IE. I can't find this element.
My problem is:
There are many elements on page, for each element must be set only this element parameters
I do not know which element is parent, I do not know the script element ID. I need insert an element in place where are first script called
First part of code executed before any call back, and I want to keep it asynchronous
Depending on the order your script blocks are hit, you could have a number of issues here. document.write() creates interesting problems with inline script. More often than not, any script that comes after it won't be able to use the results of the doc.write until after the page finishes loading -- or from within another document.write() block. Waiting for the window to be fully loaded could solve your issue. How about something like this -
Defined Once:
function callback(id) {
var el = document.getElementById(id);
if (el !== null) {
el.url = 'http://google.com';
}
}
Then anywhere you want to write out an iframe:
(function(){
var id = 'an_unique_Id';
document.write('<iframe id='+id+'></iframe>');
var l = window.onload;
var n = function() { someAsyncFunction(function() { callback(id); }); };
window.onload = (typeof l == 'function') ? function() { l(); n(); } : n;
})();
First, use:
document.getElementById(uniqid).url = 'http://google.com';
The method is part of the document object, so you can only use it by prepending document.
Second, use:
var callback = function() {
Will not break your code probably, but variables should be declared with var
i'm creating a img when i click in a input, then i get the html or anyelse from the created img.
but i dont know why this is not working!
always return null
my js:
$("#click").click(function(){
var $imgDone = $('<img/>').attr('src', 'someImage/insomewhere.jpg');
$(this).after($imgDone);
setTimeout(function(){
alert($(this).next().html());
}, 1000);
});
i mande a exp.: Demo
this is pointing at the wrong place in setInterval.
The this you have in the outer scope isn't the same as the this that you get inside the callback, which will usually be the window object, since:
setInterval(f, t)
is actually
window.setInterval(f, t);
To solve the problem, take a copy of this in the outer scope:
$("#click").click(function(){
var self = this;
var $imgDone = $('<img/>').attr('src', 'someImage/insomewhere.jpg');
$(this).after($imgDone);
setTimeout(function(){
alert($(self).next().html());
}, 1000);
});
For efficiency, as #T.J. Crowder suggests, you could actually use the jQuery constructor to take that copy, and save yourself a few calls to jQuery:
$("#click").click(function(){
var $this = $(this);
var $imgDone = $('<img/>')
.attr({src: 'someImage/insomewhere.jpg'})
.insertAfter(this); // NB: not $this here
setTimeout(function(){
alert($this.next().html());
}, 1000);
});
The other problem is that .html() shows the inner contents of tags, not the tags themselves, and your img tag has no inner contents.
There doesn't appear to be any builtin jQuery method that returns the actual whole HTML of an element. To do that you'd need to put your element into something else (e.g. a <div>) and then take the .html() of that.
Here's a plugin I just made that does this, inspired by something I found via Google:
(function($) {
$.fn.outerhtml = function() {
return $('<div/>').append(this.clone()).html();
};
})(jQuery);
Demo of it in use on your problem at http://jsfiddle.net/alnitak/qaSmS/
because the timeout function is called form a different context, this no longer applies.
$("#click").click(function(){
var $imgDone = $('<img/>').attr('src', 'someImage/insomewhere.jpg');
$(this).after($imgDone);
myImg = $(this);
setTimeout(function(){
alert($(myImg).next().html());
}, 1000);
});
The ".html()" method gets the contents of something, not including the markup for the container itself.
The other answers indicating that the use of this in the timeout handler are correct, of course. When you fix that, however, the alert will just be empty.