Javascript creating references to native functions - javascript

I have written this code (this is a snippet) that doesn't seem to be working. I have isolated it to here.
grab = window.document.getElementById;
grab("blueBox") // i.e. grab("blueBox").onclick [...]
Is it possible to create references to native function in javascript. I am doing something with the grabbed element, I just left it out for example. The grab function doesn't seem to work.
I am using FireFox's most recent version

The way you're doing it will mess up the assignment of the this value for the function.
grab = window.document.getElementById;
grab("blueBox") // i.e. grab("blueBox").onclick [...]
here this will be the global object. Try:
grab.apply(window.document, ["blueBox"])
or in newer browsers:
grab = window.document.getElementById.bind(window.document);
to get directly define what this will be.

The first step here is always the JavaScript console. Firebug is your friend. Tell us the error message if it doesn't mean anything to you.
In the mean time, here is a workaround:
var grab = function(id) { return window.document.getElementById(id); }

function grab(id) {
return window.document.getElementById(id);
}
grab("blueBox");

The reason is because the function getElementById is not being called as a method of document, so its this keyword doesn't reference the right object. Using call as suggested in other answers shows that when this references the document, getElementById works.

Related

Javascript - Need an Underscore in Function Name?

I don't have any trouble with this code but I am very curious as to why the function below seems to need an underscore in its name.
function _clear()
{
document.getElementById("test").innerHTML = "";
}
The function _clear() only executes after clicking the button if the function name contains an underscore.
<button type="submit" onClick="_clear()">Clear</button>
According to the MDN, clear() is a method of the Document object, which one might call by writing document.clear(). But, since this method is deprecated one ought not to call it at all. In fact, in HTML5, the method does nothing (see HTML5 spec).
So, until this method is actually removed from the Document object, one might conclude that a potential conflict exists in having a user-defined function with the same name as that of the Document's method. That said, the following code runs just fine using Google Chrome (Version 49.0.2623.112 m):
var d = document;
d.g = d.getElementById;
function clear()
{
d.g("test").innerHTML = "";
}
var test = d.g("test");
test.onmouseover=clear;
See demo
It's unlikely that there is a conflict between clear() and document.clear(). I wrote a user-defined function that uses the same name as another document method and the code ran flawlessly; see here.
Apparently, when the onclick event attribute is given the user-defined function "clear()" there is some kind of confusion with clear() being associated with document.clear(); see here and read the excellent explanation in the official answer. In brief, the issue boils down to "...the Document object is in the scope chain before the Window object (...)" (see JavaScript: The Definitive Guide).
If for some reason you were determined for the code to work, here's how to specify the correct context:
HTML:
<div id="test">a test to see if this will clear</div>
<button id="but" onclick="window.clear()">Clear</button>
So, the user-defined function actually becomes a method of the Window object, along side the built-in ones like window.open(), allowing the code to execute; see here.
Note, the best way to have an action occur when a click event occurs is to put this line in your JavaScript code given a button with an id of "but":
but.addEventListener('click',clear);
See demo.
That's because clear() is a function that already exists in JavaScript. You could also add the underscore to the end or add another c or do anything so that the function has a different name.

Appcelerator - Javascript - losing the reference

I have the following code on my app to add widgets:
while(i < rc_length) {
console.log(i);
mooncards[i] = Alloy.createWidget("moonCards");
mooncards[i].on('close',function(){
$.dashboard_scroll.remove(mooncards[i].getView());
});
$.dashboard_scroll.add(mooncards[i].getView());
i++;
}
So I can add mooncards on my scrollview and add a function to be triggered inside the widget to remove itself.
That was the idea, but unfortunately the only widget removed is the last one. Clearly the reference remove(mooncards[i]) is lost while adding new widgets.
I'm still learning about Javascript, so I don't what I'm doing wrong here.
How can I add a lot of widgets and remove each one specifically, without losing the reference?
Please, let me know If I need to be more clear.
You have a classic javascript binding issue.
I would try changing:
$.dashboard_scroll.remove(mooncards[i].getView());
to
$.dashboard_scroll.remove(this.getView());
You can use bind:
mooncards[i].on('close',function(){
$.dashboard_scroll.remove(this.getView());
}.bind(mooncards[i]));
bind will replace this in your function with the first parameter that you give to it. Consider this example:
x = function() { console.log(this); }
// outputs the window context if running in browser
// because the value of 'this' is the context where
// where the function was executed
x();
// outputs a String object, 'hello' because the value of
// this has now been bound to the string 'hello'
x.bind('hello')();
If your users are in IE8 and below, you will need to use the polyfill provided in the link above.

unable to change body background color using javascript callback

I am learning to program in Javascript. I have created a jsfiddle here - http://jsfiddle.net/vvMRX/1/
function turnRed(node,f){
setTimeout(f,2000,[node]);
}
(function pageLoaded(){
turnRed(document.body,function(node){
alert(node);node.style.backgroundColor = '#ff0000';
});
})();
I am trying to use a setTimeout call on a function to change the body background color. I pass document.body as a node. In the callback, I change the node.style.backgroundColor but it does not work. Interestingly enough, using document.body.style.backgroundColor directly works. If I put an alert(node), it correctly identifies it as html bodyelement.
What am I missing here?
Appreciate responses.
Here's the following error that's being thrown in your JS:
Uncaught TypeError: Cannot set property 'backgroundColor' of undefined
The reason for this is because in your setTimeout, you're passing node in an array. However, in your callback, you're accessing the node directly. Two ways of addressing this are:
Update your callback to access the node within the array.
(function pageLoaded(){
turnRed( document.body, function(node){
alert(node);
// Updated code below
node[0].style.backgroundColor = '#ff0000';
});
})();
The other way would be to update your setTimeout and pass node directly.
function turnRed(node,f){
setTimeout(f,2000,node);
}
Here's an updated fiddle: http://jsfiddle.net/vvMRX/3/
You mentioned that using document.body.style.backgroundColor worked - which makes sense - since document.body will point to the element that contains the content. For most pages, this is almost always the <body> element. However, for frameset documents, this would return the outer frame. (w3.org reference)
Finally, regarding the alert - what's up with that, right? You call alert(node), and it displays [object HTMLBodyElement], which means you were passing the correct element, right? (At least, that's what I would think too!)
What's actually happening is that alert is alerting the value of your array.
Here's a fiddle demonstrating that: http://jsfiddle.net/4Lf3J/
You should see three alerts.
In the first alert, I've updated the original alert to call node.constructor. Object.prototype.constructor will return a reference to the object that created the instance (MDN reference).
In this case, we'll see
function Array() { [native code] }
This hopefully will re-enforce the idea that you're passing an array.
The second alert is actually calling alert(document.body.constructor), which is what we EXPECTED to see originally. In this case, we see:
function HTMLBodyElement() { [native code] }
Finally, a third alert shows the values 1,2,3,4,5, which is just an alert of a simple array with those values (again, re-enforcing the idea that alerts will alert the value of an array - which is why you thought the alert was correct).
Hopefully this helps as you continuing learning JavaScript!
In your function turnRed you are passing node in an array. Try this:
function turnRed(node,f){
setTimeout(f,2000,node);
}
I tried this in the fiddle it works.
In this case i guess that you should use document.bgColor property directly
You can obtain more information and code samples here:
http://www.javascripter.net/faq/backgrou.htm
http://www.webcodingtech.com/javascript/change-background-color.php

RaphaelJS Set.forEach()

I read in the documentation raphaeljs description of Set.forEach, and can't understand
how it works. Please can anyone give me an example of usage.
Here you have a working example:
http://jsfiddle.net/9X6rM/
And this is the important part of It:
set.forEach(function(e){
e.attr({fill:'#000'})
})
Its a little bit tricky at first, but its pretty handy when you get it. You need to pass to the forEach() method the function that you want to execute on each element, and this function need to have, like an argument, a variable name to bind to the element. So in this case e is the rectangle that is being processed. Got it?
This thread is pretty helpful in understanding how forEach works
Edit :
You have a working example in the Raphaƫl Documentation
Raphael.el.red = function () {
this.attr({fill: "#f00"});
};
Raphael.st.red = function () {
this.forEach(function (el) {
el.red();
});
};
// then use it
paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red();
Some things that are missing from the Raphael forEach documentation:
What is passed to the function you define
set.forEach(function(element, index){
element.attr({fill:'#000'});
alert('This is the element that can be accessed as set['+index+']');
})
Two arguments are passed passed to the callback function:
The Raphael element that is currently being looked at.
The index number indicating the position of that Raphael element in the set.
this in the scope of a cycle of Raphael's forEach is unchanged from the surrounding function (unlike jQuery's .each()).
Possible crashes or unexpected behaviour
Unlike jQuery's .each() function, Raphael's .forEach() crashes out if it's passed a singular Raphael element instead of a set. If a variable might contain one element, or might contain a set of multiple elements, check what type of Raphael object it is first.
As mentioned, Raphael's .forEach() doesn't create a closure like in jQuery - it's really just an iteration through an array. Variables in each iteration aren't 'frozen' in that iteration, they can be overwritten by following iterations.

Using jQuery in a JavaScript function

function divlightbox(val)
{
if(val)
{
val=val.replace( /^\s+/g, "" );
var count_js=0;
var big_string='';
document.getElementById("video_lightbox").innerHTML="";
document.getElementById("divlightbox").style.display = "block";
$("#video_lightbox").css({"height":"430px","top":"10%","width":"480px"});
I found out that the error is in the above. My question is can't I use jQuery and traditional JavaScript at same time? I have done coding like this numerous times and never ran into a problem like this. I used to use jQuery methods like .hide() and .css() inside JavaScript functions but this time it doesn't work.
Thanks in advance.
While the other answers fix the specific problems, I don't think the OP's question (in bold) is really answered here, as depending on the specific context, $ may possibly not be defined as a jQuery object yet (having had this problem myself a few times now.)
In which case you would need to do something like:
function divlightbox(val) {
// ...
// just use jQuery instead of $ one time
jQuery("#video_lightbox").css({"height":"430px","top":"10%","width":"480px"});
}
OR
function divlightbox(val) {
// define the $ as jQuery for multiple uses
jQuery(function($) {
// ...
$("#video_lightbox").css("height":"430px");
$("#video_lightbox").css("top":"10%");
$("#video_lightbox").css("width":"480px");
});
}
jQuery is JavaScript so YES. Instead .innerHTML="" just use .empty(). Instead .getElementById() use $('#..') and so on.
to do things like hide(); and css() you need jquery objects. you can't do them to dom elements.
so you could do $('#video_lightbox').html("");
or
$('#video_lightbox').empty();
You must provide error in javascript console.
1) Do you pass a val argument to divlightbox function()? When do you call it?
2) why do you use the same identifier divlightbox both for a function and for a div id? Change name to the function please, maybe the problem could be here.
3) Always check if video_lightbox and divlightbox exist before accessing them.

Categories