MollyPages.org
"You were wrong case. To live here is to live." |
Pages /
Database /
Forms /
Servlet /
Javadocs
/
License & Download /
Tutorials /
Cookbook
/
Contact & Hire
|
function x() { var id = 0; return function() { return id++; } } var makeid = x(); var i = makeid(); var j = makeid();
id
has effectively private access, via (and only) via
the closure makeid() function.
foo() { var req = xmlhttp(); req.onreadystatechange = function() { /*closure created here*/ if (req.readyState == 4) { ... } } }Even though the
onreadystatechange
is a property/method of
req, it is not invoked *via* req by the request handling
(browser) thread. Since t needs access to itself and can either
use a global variable (essentially window.req) or a closure
to hold/access a reference to it.
See also: mozilla developer docs
x = elements('a') for (var i = 0; i < 10; i++) x[i].onclick = function() { /*...use x[i] here...*/ } }All
onclick
functions will refer to x[10], the final/latest value of
the the closed variable i
(the loop counter variable i
is a closed variable for the inner function within the loop).
A) new and function definition combined var obj = new function() { /* stuff */ } B) object literal (this is cool since can use data retrieved via JSON as well as saves typing/easier to read anyway). var obj = { /* stuff */ }
function MyObj() {} MyObj.prototype = { foo: function () { alert(this); } ...etc.. } var my1 = new MyObj(); my1.foo();
var elem = getElement('elem'); elem.style.display = '';use
display: ''
as opposed to display: block
(this uses the default "none" type which can differ from block or
table-row or whatever, but in all cases, makes the element
visible properly.
However, setting elem.style.display = ''
only sets or removes
the inline style. If a document level css style declaration
also exists and applies to that element, then once the inline style
is removed, the element will be still be rendered with the document level
declaration (since elem.style.display
has effectively removed
the higher precedence inline style, but the document level declaration is
unaffected and will now apply).
So either:
style.display = ...
(only use inline styles)//only changes/modifies inline style elem.style.xxx = ... //classname elem.className = ...Either inline styles or className can be used.
elem.className = 'foo';Use
className
and not class
(since
class can be a reserved word).
elem.cssFloat = 'left';Use
cssFloat
for the CSS float property and not float
, since
float is a reserved word in JS.
elem.className = 'foo bar baz';Using classList makes working with multiple names easier, with the
add
, remove
and toggle
methods.
var cl = elem.classList; cl.add('foo'); cl.toggle("bar");See: Mozilla docs
-in HTML <a href="javascript:foo()" <anyelement onclick="javascript:foo()" <anyelement onclick="foo()" (the "javascript:" is optional) <form action="foo()" (the "javascript:" is optional) -in JS Code anyelement.onclick = foo;Don't return a value in onclick event handlers for href's etc, (return
void 0
or undefined
instead) because in some cases, the browser will show the return value instead (as if the user navigated to a new page with that value)
More reading: quirksmode
<body> <form> <button type='button' onclick="myfunc(this, 'button.onclick', event)">my button</button> </form> <div onclick="myfunc(this, 'div.onclick')">my div</button> <script> function myfunc(elem, msg, e) { console.log(elem, msg, e); } </script> </body>(as a small aside, a button inside a form submits that form unless a type=button is specified, the vagaries of legacy html)
the event
object is available in inline handlers via the 'event' object. If applicable handlers are declared on parent elements, then as events bubble up to parent, parent handlers will be invoked for the parent again (with 'this' being the parent when the parent handler is invoked). The event.target
always remains the original element upon which received the initial event (click, etc).
If this
is not passsed in the inline-handler, this refers to the window where the script is running, in the
event handler function itself.
event handlers declared in JS
Further reading
see:
quirksmode, another great tutorial
button.onclick = ...<.code> are methods of the corresponding DOM button object, in which the
this
object is automatically set to the element on which the event was invoked.
var table = document.getElementById('mytable'); var rows = table.getElementsByTagName('tr'); for (var i = 0; i < rows.length; i++) { if(i%2) { rows[i].className += " even"; } }Programmatically adding a class to a table to achieve a zebra stripes effect. JS functions for
onmouseover/onmouseout
can also be added this way.
$('foo').related = $('bar');Add properties to DOM objects themselves to refer to other related DOM objects as needed (this causes no memory leaks in IE since we are staying within the DOM).
window.resizeBy(0,1) window.resizeBy(0, -1)This forces css relayout and rendering updates.
$('x').style.foo
foo
is only available if either is true:
$('x').style.foo
= 4
foo
is not available.
This is a common issue when accessing left
and
top
style properties on a div (where the default
left/top are not available since they were not set in a inline
style). The solution is to set these initially, either inline
or via JS.
Working example (in the right column):
<style> #x, #y, #z { border: 1px solid #ccc; margin: 5px; } #y { font-size: 2em; left: 30px; position: relative; } #z { font-size: 2em; position: relative; } </style> <script> function show(name) { var div = document.getElementById(name); alert("left="+div.style.left + "\nfontSize="+div.style.fontSize); } </script> <div onclick="show('x')" id=x style="font-size: 2em;">x-div</div> <div style="position: relative"> <div onclick="show('y')" id=y>y-div</div> </div> <div style="position: relative"> <div onclick="show('z')" id=z style="left: 60px;">z-div</div> </div> |
x-div
y-div
z-div
|
window.getComputedStyle(element, propertyName)More here: MDN
top
, left
via JS, the values should be proper
CSS strings, including the dimensions (such as "px") suffix.
When retrieving style properties, parse them using
parseInt()
etc, to get the numerical value
//string to number when reading CSS property var currentLeft = parseInt(elem.style.left); //number back to string when assigning CSS property elem.style.left = currentLeft + 20 + "px";
<a href="javascript:showImg()"> <img title="my image" name='sunset'> </a>A simple slide show whereby moving over a href shows a corresponding image in a image area. The title and name attributes of the img tag can be easily used to achieve this (and other custom attributes can be used as well, although the page will not "validate" if that's the case, but no big deal).
Another example:
<input type=text pattern="^\w+$" required=true>At page load time, JS code walks through all form fields, and if the pattern/required attributes are present, adds a validate function that validates the contents of the text field conform to the regex pattern before the form is submitted.
+-------------------------------------------+
| element (say anchor a) |
| <a href="http://foo.com/bar.html" id='a1' |
| class="c1 c2" data-x='y' foo='bar' |
+-------------------------------------------+
| href: "http://foo.com/bar.html" |
| id: "a1" |
| className: "c1 c2" |
| data-x: "y" |
| propABC: "xxx" |
| |
| attributes: |
| href: "bar.html" |
| id: "a1" |
| class: "c1 c2" |
| foo: "bar" |
| |
| dataset: |
| x: "y" |
+-------------------------------------------+
a.propABC = 'xxx'
Notes:
get,set,removeAttribute
act on the attributes array.href
is not exactly the same). However, reading/writing the properties in the atributes array may or may not synchornize them further with the top level properties. Really depends on the property. So, one can say (modulo synchronization issue):
myelem.id = "123"; myelem.setAttribute("id", "123");
get/set/removeAttribute
methods.
myelem.dataset.x
clearTimeout invokes the specified function at some continuous frequency.
To specify a function with parameters in setTimeout, there are 3 ways:
setTimeout("foo(" + param1 + ")", ....)
- specify an expression that is 'eval()'ed at runtime. finicky and outdated.
setTimeout(function () { foo(param1) }, ....)
- specify a anonymous function (that has access to parameters via closures, etc)
setTimeout(foo, 500, param1, param2,...)
- specify parameters after the timeOut interval (modern version)
A further wrinkle is the this
pointer available inside the invoked function. this
will refer to the window object since the invoked function is invoked without a object reference. Can pass this
as a parameter, if necessary.
function progress(elem) { var style = elem.style; if (! elem.isAnimating) { elem.origWidth = parseInt(style.width); style.width = "0px"; //initialize element } //this will remain true for next round of invokation via setTimeout until //set to false at end of animation elem.isAnimating = true; /*not elem.getAttribute("origWidth") since not set via setAttribute()*/ if (parseInt(style.width) < elem.origWidth ) { //have to use parseInt and "px", all properties accessed/set //via style are css strings style.width = parseInt(style.width) + 5 + "px"; setTimeout(progress, 500, elem); } else{ elem.isAnimaing = undefined; elem.origWidth = undefined; } } progress(document.getElementById('myimg'));
function progress(elem) { var style = elem.style; var origWidth = parseInt(style.width); style.width = "0px"; //initialize element function go() { if (parseInt(style.width) < origWidth) { style.width = parseInt(style.width) + 5 + "px"; setTimeout(go, 500); //keep invoking itself } } } progress(document.getElementById('myimg'));
function progress(elem) { var style = elem.style; var origWidth = parseInt(style.width); style.width = "0px"; //initialize element //tell JS to keep invoking go until stopped var intervalId = setInterval(go, 500); function go() { if (parseInt(style.width) < origWidth) { style.width = parseInt(style.width) + 5 + "px"; } else{ clearInterval(intervalId); return; } } } progress(document.getElementById('myimg'));
---| -----| --------| -----------|simple animation of a progress bar: keep increasing the width of a div or img.
function progress() { var img = ..the img.. if (img.width < 200) { //using reflected width attribute directly, so "px" not required img.width += 5; img.height = 5; //to not autosize height along with width } else { img.width = 400; //original width clearInterval(progress_id); } var progress_id = setInterval("progress()", 500);
function yellowFade(el) { var b = 155; function f() { el.style.background = 'rgb(255,255,'+ (b+=4) +')'; if (b < 255) { setTimeout(f, 40); } }; f(); }
Snippet taken from this article.
document.write("< img src='foo.jpg?" + Math.random() + "' />");We change the URL harmlesslessly (as long as the stuff after "?" is ignored by the server) and prevent browser caching of the image
getElementById(element id) getElementsByTagName(tag name, like b, div, etc) getElementsByName(name attribute, like name=mylink) getElementsByClassName(class name assigned to a element) querySelectorAll(cssSelector...any cssSelector!)If called on a node, like
someNode.getElementsByName
, finds children of that node
only.
Except for querySelectorAll
, elements returned by methods that return collections (such as getElementsByTagName
) are live. If they are deleted while iterating through the collection, the index of the following elements might change (since the list is updated live).
form, href & img
elements with a name attribute are reflected as top-level properties
in the DOM tree and can be retrieved simply.
document.myFormNameFoo document.myHrefNameBar document.myImgNameBaz ..etc..
document.createElement('div')
div
in this example)document.createTextNode()
document.createDocumentFragment()
node.nodeType
node.nodeValue
node.nodeName
node.getAttribute()
getAttribute("href")
node.setAttribute()
node.setAttribute("href", "http://bar.com");
firstChild, lastChild, childNodes
nextSibling, previousSibling
parentNode
removeChild(), appendChild()
insertBefore(newnode, someOtherChild)
var node = ..some_element.. node.parentNode.removeChild(node);
var list; var newnode; list.insertBefore(newnode, list.firstChild);
var node = ... var newnode = node.cloneNode(true|false); true=deep copy, else shallow
var list; var newnode; list.replaceChild(newnode, list.oldchild)
email, url, range
and date
. They default to type=text if not supported by browser so no downside.
document.writeln
can be useful for writing out templates (like a table, etc) as well as injecting scripts and iframes. When writing the script tag dynamically, escape the angle brackets, because the browser will close the script
otherwise, even inside a writeln string.
document.writeln("<\/script>"); --or-- document.writeln("<" + "/script>");
String
that are available to all instances.
String.prototype.xxx = function() { ... }; "foo".xxx();
false
from event handlers to prevent default actionfalse
from any event handler attached to that action.
The only exception (for historical reasons) is returning true
for onmouseover
on a <a ...
element, to prevent display of the linked URL in the status bar.
Optionally, then use onblur on the editable element to save the edited text to a server, etc.
<div contenteditable></div>
input type=button
shows a regular button, useful only with a onclick event hander.
A <a...>
does the same thing, useful with a javascript href or onclick event handler
An <button>
HTML element is an alternate to the above and can contain HTML to display (instead of a plain text value in the case of a input button)
my cool link