Return to Tutorials index

Random collection of misc. code and snippets

  1. Private variable using closures

    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.
  2. Remembering variables via closures

    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

  3. Closures have access to variables that can be changed

    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).
  4. Various ways for Object creation

    
    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 */ }
    
    
  5. Defining object methods

    function MyObj() {}
    
    MyObj.prototype = {
        foo: function () {
            alert(this);
            }    
        ...etc..
        }
    
    var my1 = new MyObj();
    my1.foo();
    
  6. Toggling display visibility

    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:

    1. Don't use both non-inline styles and inline styles when toggling display property via style.display = ... (only use inline styles)
    2. or, change the stylesheet/classname as well as the display property if using classname styles or both inline/non-inline at the same time.

    See: stack overflow thread

  7. Changing CSS for an element

    //only changes/modifies inline style
    elem.style.xxx = ...
    //classname
    elem.className  = ...
    
    Either inline styles or className can be used.
  8. Use className

    elem.className = 'foo';
    
    Use className and not class (since class can be a reserved word).
  9. Use cssFloat

    elem.cssFloat = 'left';
    
    Use cssFloat for the CSS float property and not float, since float is a reserved word in JS.
  10. Use classList when elements have multiple classes

    For multiple classes, one has to be careful to parse/save the class string properly, for example:
    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
  11. Ways to invoke JS event handlers

    -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

  12. DOM 0 Event handlers are methods

    <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 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.

    Further reading see: quirksmode, another great tutorial

  13. Using the id attribute

    When the id attribute is used, all elements should have unique id's. The same id for multiple elements results in all sorts of problems in IE, even when using something like prototype's down/up, where we want a unique id (and there is a unique id) when starting downwards from a given element.
  14. Programmatic assignment of classes

    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.
  15. Ease of DOM

    $('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).
  16. Force CSS layout

    window.resizeBy(0,1)
    window.resizeBy(0, -1)
    
    This forces css relayout and rendering updates.
  17. Accessing css styles from JS

    Styles for an element are reflected in the element.style property. To read a particular style, say foo, say:
    $('x').style.foo
    
    foo is only available if either is true:
    1. it is set in an INLINE style definition on 'x'
    2. if it was previously assigned in JS (before it is accessed later), like:
      $('x').style.foo = 4

    Otherwise, 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
  18. Get all applicable CSS rules

    To get all styles applicable to an element (whether inline as discussed above, via .style) or via a document or external stylesheet, say:
    window.getComputedStyle(element, propertyName)
    
    More here: MDN
  19. All styles properties should be valid CSS strings

    When setting style properties, such as 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";
    
  20. DOM/HTML: attributes are useful

    <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.
  21. DOM Objects attributes and values are conceptually separate (and sometimes equal)

    +-------------------------------------------+
    | 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:
    • Attributes are reflected onto the JS object corresponding to the DOM element. These are available in the attributes property/array.
    • get,set,removeAttribute act on the attributes array.
    • Standard HTML attributes are also reflected onto top level properties (with the same name) in the JS Object These are initially synchronized as the values in attributes (with some corner cases, for example, 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");
      
    • Also, non-standard HTML attributes (like foo in the above example) are not reflected as top level properties (they are available in the attributes array though). Any non standard properties (non reflected) to the JS Object propABC in the above example) will be normal JS properties on the DOM object but will not be in the attributes array and will not be accessible via get/set/removeAttribute methods.
    • Any property that starts with data- is reflected onto the top-level dataset property (not in the attributes array). This can be simply used in JS like so:
      myelem.dataset.x
      
  22. Event bubbling

    An event bubble is not invoked on parent if the parent does not support that event handler (even if we add a event handler to the parent, the parent will never see it)
  23. setTimeout/setInterval

    setTimeout invokes the specified function once. The specified function can then invoke itself again, which as the same affect as clearTimeout

    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.

    More here mozilla MDN
  24. Idioms when using setTimeout/setInterval

    1. Recursively calling setTimeout and storing state and custom variables in the JS Object/DOM element itself.
      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'));
      
    2. Recursively calling setTimeout and storing state and custom variables in the function (using a closure)
      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'));
      
    3. Using set/clearInterval and storing state and custom variables in the function (using a closure)
      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'));
      
  25. Simple animation

        ---| 
        -----| 
        --------| 
        -----------|
    
    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);
    
  26. Simple fade effect

    Useful upon adding/deleting items on a page.
    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.

  27. Prevent Caching of a resource

    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
  28. Useful methods to retreive elements from DOM

    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).

  29. Quick and cool method to retreive form elements from the DOM

    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..
    
  30. DOM/HTML node/tree methods

    Also see: quirksmode for more info.

    document.createElement('div')
    Creates a element node (div in this example)
    document.createTextNode()
    Creates a text node
    document.createDocumentFragment()
    Creates an empty DOM tree (useful for appending/creating elements too, and then transferring the entire tree to the actual document in one go)
     
    Using innerHTML instead is easier and simpler in most cases.

    Properties of nodes

    node.nodeType
    1. Node.ELEMENT_NODE == 1
    2. Node.ATTRIBUTE_NODE == 2
    3. Node.TEXT_NODE == 3
    4. Node.ENTITY_NODE == 6
    5. Node.DOCUMENT_NODE == 9
    6. Node.DOCUMENT_FRAGMENT_NODE == 11
    MDN
    node.nodeValue
    value of text for a Text node (useful for #text). Null for most other nodes (including element nodes) MDN
    node.nodeName
    mainly useful for the element tag name or "#text" for text nodes.
    1. Element ==> Element.tagName ("DIV", "H1", etc, UPPERCASE)
    2. Text => "#text"
    MDN
    node.getAttribute()
    Gets an attribute for a node, such as getAttribute("href")
    node.setAttribute()
    Sets an attribute for a node, such as node.setAttribute("href", "http://bar.com");

    Operations on Nodes

    Finding nodes
    1. Children: firstChild, lastChild, childNodes
    2. Siblings: nextSibling, previousSibling
    3. Parents: parentNode
    Adding/Removing nodes
    1. removeChild(), appendChild()
    2. insertBefore(newnode, someOtherChild)
  31. Removing the current node from the DOM tree

    var node = ..some_element..
    node.parentNode.removeChild(node);
    
  32. Inserting a node before another node

    var list; 
    var newnode;
    list.insertBefore(newnode, list.firstChild);
    
  33. Cloning a node (shallow or deep copy)

    var node = ...
    var newnode = node.cloneNode(true|false); true=deep copy, else shallow
    
  34. Replacing a child node with another node

    var list;
    var newnode;
    list.replaceChild(newnode, list.oldchild)
    
  35. Using HTML 5 input types

    Use: email, url, range and date. They default to type=text if not supported by browser so no downside.

    input type=email:
    input type=url:
    input type=range:
    input type=date:
  36. document.writeln can be useful

    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>");
    
  37. Add functionality to built-in JS classes

    Easy to assign new methods to existing JS classes, like String that are available to all instances.
    String.prototype.xxx = function() { ... };
    "foo".xxx();
    
  38. Return false from event handlers to prevent default action

    To prevent default browser actions, like form submission, link transversal, etc, return false 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.

  39. Make any element editable

    Specify the contenteditable attribute in any element to make it editable. Can also specify the spellcheck=false|true attribute to enable/disable spellcheking.

    Optionally, then use onblur on the editable element to save the edited text to a server, etc.

    <div contenteditable></div>
    

  40. input type=button, link and button element

    An 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