I have this loop code to reduce the DOM calls in my Javascript, and reuse them.
aarr = [];
for (var z=1; z<=10; z++) {
c = z-1;
aarr[c] = document.getElementById("a"+z);
}
I have been shown that if the code is ran before the DOM is complete, then the array is null. Moving the script after the last html code will work.
So now I want to put this code inside the window.onload event so to not have to move the script code to the bottom of the page. But it apparently does not work because it appears that the array loop is executed before the DOM is completed.
window.onload=function(){
var aarr = [];
for (var z=1; z<=10; z++) {
c = z-1;
aarr[c] = document.getElementById("a"+z);
}
}
Also, I have tried to remove the "var" to remove scope without making a difference.
You could also try this approach without using a framework:
window.onload = (function(){
return function(){
var aarr = [];
for (var z=1; z<=10; z++) {
aarr.push(document.getElementById("a"+z));
alert(aarr[z-1].id);
}
};
})();
JSFiddle
If you can use jquery, then you can use the document ready listener:
$(document).ready(function() {
var aarr = [];
for (var z=1; z<=10; z++) {
c = z-1;
aarr[c] = document.getElementById("a"+z);
}
});
http://www.jquery.com
as per the comment above, have you tried:
if (document.readyState === "complete") { init(); } // call whatever function u want.
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images and sub-frames have finished loading.
MDN - window.onload
I guess you try calling code outside of onload. See this fiddle
Better to use a function without pre-scanning the dom to create a cache, Pre-scanning is not needed when you use a simple function with a cache construction. With jQuery you can can create a function like this (native javascript method below this):
window.__jcache = {};
window.$jc = function(u) // jQuery cache
{
if( u == undefined )
{ return window.jQuery; }
if( typeof u == 'object' || typeof u == 'function' )
{ return window.jQuery(u); }
if( window.__jcache[u] == undefined )
{ window.__jcache[u] = window.jQuery(u); }
return window.__jcache[u];
};
Or without a framework (native javascript):
window.__domcache = {};
window.getObj = function(u) // jQuery cache
{
if( u == undefined )
{ return null; }
if( typeof u == 'object' || typeof u == 'function' )
{ return u; }
if( window.__domcache[u] == undefined )
{ window.__domcache[u] = document.getElementById(u); }
return window.__domcache[u];
};
So you can do:
var o = $jc('a1'); // for jquery version
var o = getObj('a1'); // The native javascript method (jamex)
That does the trick.
Greetz, Erwin Haantjes
Related
I am trying to build a associative array parentTds however it's not working the way I would like.
var parentTds = {};
var index = 0;
$.each(clone, function () {
var $currentItem = $(selectedActivities[index]);
var $currentItemTd = $currentItem.closest('td');
console.log($currentItemTd.get(0));
var borderLeft = 0;
console.log(parentTds[$currentItemTd.get(0)]);
console.log(parentTds[$currentItemTd]);
if (typeof parentTds[$currentItemTd.get(0)] === "undefined") {
console.log('NOT OK');
borderLeft++;
parentTds[$currentItemTd.get(0)] = $currentItemTd;
} else {
console.log('OK');
}
index++;
});
For some reason parentTds[$currentItemTd.get(0)] always returns the 1st item stored. I get NOT OK just the 1st time the loop runs whereas I should be getting NOT OK a few more times. I suspect the problem is parentTds[$currentItemTd.get(0)] itself.
Any ideas please?
Javascript is not as forgiving as for example PHP. When you use this:
if (typeof parentTds[$currentItemTd.get(0)] === "undefined") {
$currentItemTd.get(0) might be evaulated as 0 and therefore the reference is always parentTds[0]
In these circumstance I use to break up the code-block and do something like this:
var cig = $currentItemTd.get(0);
if (typeof parentTds[cig] === "undefined") {
I'm storing stuff in javascript/DOM and submitting an ajax call. In the success and/or .done function when I do:
$('#results').html(data);
The javascript/DOM model becomes corrupted but when I do:
var el = document.getElementById('results');
el.innerHTML = data;
then everything works as expected. I know there isn't much information here but my question is what else is the jQuery html() doing apart from setting the innerHTML that may be effecting the state of the page.
The main reason to use the html function with a string rather than innerHTML is to prevent memory leaks or inconsistent in memory data : this function removes event handlers or other jQuery data linked to the removed elements.
If data is a string, there is no reason for $('#results').html(data); to "corrupt" your DOM more than by using innerHTML.
In Internet Explorer 9 and earlier tables in the DOM were read-only. That meant that trying to do el.innerHTML = newHTML; would result in an error being thrown if el was a TBODY, TR, etc. The jQuery .html() function handles that case for you by using a fallback method - this.empty().append(value) in the jQuery source - allowing you to use the same code for all of the browsers, regardless of version.
It may be worth taking a look at the code for the method in the jQuery source:
html : function (value) {
return jQuery.access(this, function (value) {
var elem = this[0] || {},
i = 0,
l = this.length;
if (value === undefined) {
return elem.nodeType === 1 ?
elem.innerHTML.replace(rinlinejQuery, "") :
undefined;
}
// See if we can take a shortcut and just use innerHTML
if (typeof value === "string" && !rnoInnerhtml.test(value) &&
(jQuery.support.htmlSerialize || !rnoshimcache.test(value)) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test(value)) &&
!wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for (; i < l; i++) {
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
if (elem.nodeType === 1) {
jQuery.cleanData(getAll(elem, false));
elem.innerHTML = value;
}
}
elem = 0;
// If using innerHTML throws an exception, use the fallback method
} catch (e) {}
}
if (elem) {
this.empty().append(value);
}
}, null, value, arguments.length);
}
How can you set a var to something you want to later check if it's defined or not?
Example: To check if jQuery is not defined, you'd do this:
if (typeof(jQuery) === 'undefined') {
}
But what if I want to do something like this (this obviously doesn't work):
var toCheckLater = jQuery; // This fails.
// Some time later..
if (typeof(toCheckLater) === 'undefined') {
}
What I'm trying to do is dynamically load scripts from an array, but I want to set ahead of time the variable whose definition I'll check for later. And I'd like to avoid a big block of ifs or switch statement. Meaning I'm hoping to find a solution a bit more elegant than:
switch (scriptName) {
case 'jQuery':
if (typeof(jQuery) === 'undefined') {
}
break;
case 'someOtherScriptName':
.
.
.
}
Any ideas?
Thanks in advance.
A function would do:
var toCheckLater = function() { return typeof jQuery == "undefined"; }
// later:
toCheckLater()
You might also use a fabric for such functions:
function getChecker(name) {
return function() {
return typeof window[name] == "undefined";
// alternative:
return name in window; // can be undefined, but the variable exists
};
}
var toCheckLater = getChecker("jQuery");
Use
if (typeof jQuery === "undefined")
to check for undefined.
I don't quite get what you're trying to achieve, but I think you could do something like this
var toCheckLater = typeof jQuery; //if, for example, jQuery is defined you'll get "function"
// Some time later..
if (toCheckLater === 'undefined') {
}
Simply do this:
var scriptName = 'jQuery';
if( !window.hasOwnProperty(scriptName) ){
//jQuery is undefined
}
var checker = function(scriptArray) {
for(var i in scriptArray)
this[i] = i?i:loadScript(i); // make your own loadScript function
}
checker({'jquery','anothercode'});
//access checker.jquery / checker.anothercode
You could use something like this. Create a 'class' that load all the scripts.
You have use the typeof Method
typeof(variable_name) will give you "string", "object", "undefined" or "number" depending on the variable
typeof(jQuery) == "undefined"
is the way to go.
Your array of scripts:
var scripts = ['script1', 'jQuery'];
After loading the scripts you can use the same array and loop through it.
for (var i = 0, n = scripts.length; i !== n; i++) {
if (!window.scripts[i]) {
// falsy
}
}
This assumes that the scripts array references a global variable that the script will expose when loaded.
However, if I understand what you're going for, a better method would be to register a callback for when the appropriate script element is loaded. See these questions for some examples: (1), (2)
Code like this is pretty standard:
function loadScriptAsync(src, callback) {
var script = document.createElement('script'),
place = document.getElementsByTagName('script')[0];
script.type = "text/javascript";
script.async = true;
script.src = src;
script.onload = script.onreadystatechange = function() {
callback();
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
};
place.parentNode.insertBefore(script, place);
}
Is it possible to listen to any function invocation or state change
I have a object that wrap another
function wrapper(origiObj){
this.origObj = origObj;
}
var obj = wrapper(document);//this is an example
var obj = wrapper(db);//this is an example
now everytime someone tries to invoke obj.innerHTML or obj.query(..)
I would like to listen to that..
Yes, it's possible:
functions are easy, and properties has to be watched
function FlyingObject(obj){
this.obj = obj;
for(var p in obj){
if(typeof obj[p] == 'function'){
console.log(p);
this[p] = function(){
console.log("orig func");
};
}else{
this.watch(p,function(){
console.log("orig property");
});
}
}
}
var obj = {
f:function(a,b){ return a+b},
m:1
};
var fo = new FlyingObject(obj);
fo.m = 5;
fo.f(1,4);
If your browser/node.js doesn't support Object.watch, check this out:
Object.watch() for all browsers?
Yes you can, define a getter/setter for properties and a shadow function for the function like this: http://jsfiddle.net/fHRyU/1/.
function wrapper(origObj){
var type = origObj.innerHTML ? 'doc' : 'db';
if(type === "doc") {
var orig = origObj.innerHTML;
origObj.__defineGetter__('innerHTML',
function() {
// someone got innerHTML
alert('getting innerHTML');
return orig;
});
origObj.__defineSetter__('innerHTML',
function(a) {
// someone set innerHTML
alert('setting innerHTML');
orig = a;
});
} else if(type === "db") {
var orig = origObj.query;
origObj.query = function() {
//someone called query;
alert('calling query');
orig.apply(this, arguments);
};
}
return origObj;
}
var obj = wrapper(document.body);
obj.innerHTML = 'p';
alert(obj.innerHTML);
var db = function() {}
db.query = function() {alert('foo');}
obj = wrapper(db);
obj.query();
edit: "Deleting" answer since it's tagged node.js, leaving it in case it happens to be useful to anyone else:
The general answer is no, it isn't. At least not in every browser, so any solution anyone gives isn't going to work in many cases.
There are a few things that can work, but again there is horrible support for them:
dom modified events (FF only, I believe)
DOMAttrModified
DOMNodeInserted
DOMNodeRemoved
etc
object.watch (FF only)
i have been using jquery for a while now but only thing i know about jquery is probably a dozen of functions that get my job done. but i want to understand how jquery evolved from simpl plain javascript i.e how
$("#xyz").val();
is converted to
document.getElementById('xyz').value;
i have searched for my answer on the web but most of the writers are happy to show how you can hook on to different DOM elements with jquery, selector details etc. but nothing can be found about how actually the transition was made. can anyone refer me to some tutorial where i can get my required material?
thanks
jQuery is not a compiler. jQuery does not get compiled into javascript.
.val is a method of an object. The jQuery object.
Specifically it is
function (value) {
if (!arguments.length) {
var elem = this[0];
if (elem) {
if (jQuery.nodeName(elem, "option")) {
// attributes.value is undefined in Blackberry 4.7 but
// uses .value. See #6932
var val = elem.attributes.value;
return !val || val.specified ? elem.value : elem.text;
}
// We need to handle select boxes special
if (jQuery.nodeName(elem, "select")) {
var index = elem.selectedIndex,
values = [],
options = elem.options,
one = elem.type === "select-one";
// Nothing was selected
if (index < 0) {
return null;
}
// Loop through all the selected options
for (var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++) {
var option = options[i];
// Don't return options that are disabled or in a disabled optgroup
if (option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName(option.parentNode, "optgroup"))) {
// Get the specific value for the option
value = jQuery(option).val();
// We don't need an array for one selects
if (one) {
return value;
}
// Multi-Selects return an array
values.push(value);
}
}
return values;
}
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
if (rradiocheck.test(elem.type) && !jQuery.support.checkOn) {
return elem.getAttribute("value") === null ? "on" : elem.value;
}
// Everything else, we just grab the value
return (elem.value || "").replace(rreturn, "");
}
return undefined;
}
var isFunction = jQuery.isFunction(value);
return this.each(function (i) {
var self = jQuery(this),
val = value;
if (this.nodeType !== 1) {
return;
}
if (isFunction) {
val = value.call(this, i, self.val());
}
// Treat null/undefined as ""; convert numbers to string
if (val == null) {
val = "";
} else if (typeof val === "number") {
val += "";
} else if (jQuery.isArray(val)) {
val = jQuery.map(val, function (value) {
return value == null ? "" : value + "";
});
}
if (jQuery.isArray(val) && rradiocheck.test(this.type)) {
this.checked = jQuery.inArray(self.val(), val) >= 0;
} else if (jQuery.nodeName(this, "select")) {
var values = jQuery.makeArray(val);
jQuery("option", this).each(function () {
this.selected = jQuery.inArray(jQuery(this).val(), values) >= 0;
});
if (!values.length) {
this.selectedIndex = -1;
}
} else {
this.value = val;
}
});
}
If we break the above wall down we can get
function (value) {
if (arguments.length === 0) {
return (this[0].value || "")
}
this.value = val;
return this;
}
Of course jQuery has a lot more code to deal with various edge cases and special things.
In essence jQuery takes a selector. finds the elements. Stores them internally then returns you an object.
This object has all kinds of methods that allow you to mutate the underlying dom objects stored internally. .val is one of them.
There are plenty of articles on how jQuery works (there are screencasts too).
jQuery, as you've noticed, is basically a bunch of methods operating on an array of elements. It is also intended to normalize browser differences under the hood.
Take the basic usage $("#xyz").val();
I can even tell you what jQuery is doing behind the scenes, but I don't think you really want to know. :)
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
},
// ...
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
// ...
},
// ...
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
So basically $(selector) means newjQuery.fn.init(selector), it's just a shortcut for easier typing (and also to prevent the "bug" where fogetting new binds this to the global object, instead of the current instance).
Also, the so-called plug-ins added as jQuery.fn.ext are mapped to jQuery.fn.init.prototype as you can see in the last line, it's another shortcut. So when you call $(selector) everything that is added to jQuery.fn will also be on jQuery.fn.init.prototype and so the new instance will have those methods as $(selector).ext(...).
// as you use it today
jQuery.fn.plugin = function ( ... ) { ... }
$(selector).plugin( ... )
// as it would be without shortcuts
jQuery.fn.init.prototype.plugin = function ( ... ) { ... }
(new jQuery.fn.init(selector)).plugin( ... )