Memoizing previously queried data for charts rendering

This is a common scenario: suppose you need to write a function to display bar/pie charts for some data infographics  through remote REST API call.

Like click a button to display a bar chart, but you only need to query once; after first time AJAX call, it is not necessary to call the remote API anymore when user click on the button again or query the same chart again. Say you have  parameters and id to query a static REST data, it is a good practice to allow the function to memoize the previous queried data. How ?

Use function property.

function displayChart(para,id){
   if(display[para+id]){//already queried
   }else{
     display[para+id] = query(para,id);
   } 
   render(display[para+id]);
}
function query(para,id){
  $.ajax({})//return the data
}
function render(data){
  //display the chart according to the data
}

From an idea to store distinct data on array:
 var store = {
   parking: [],
   cache: {},
   add: function(item) {
      if ( !this.cache[item]) { 
          this.cache[item]= 1;
          this.parking.push(item);
      }
  }
};
Advertisements

DOM Event Bubbling and Capturing

For example:

<div id="parent">
 Hello Parent!
<div id="child">
Child
</div>
</div>
var div = document.getElementById('parent');
var p = document.getElementById('child');
1.
div.addEventListener("click", function(){
 alert('parent'); 
 }, false);
p.addEventListener("click", function(){
 alert('child');
}, false); 
When you click on the child, 'child' will be alerted first in this way, and then alert 'parent', even you don't click on the parent div.

if you bind a click event handler to the parent div, when you click on the child div, it also triggers the handler. This is because of event bubbling.
Event bubbling

          / \
---------------| |-----------------
| element1    | |                |
|  -----------| |-----------     |
| |element2  | |          |     |
| -------------------------     |
|  Event BUBBLING           |
-----------------------------------

the event handler of element2 fires first, the event handler of element1 fires last.

for IE 9+ and other browsers, there are two phase of event processing, one is the above event bubbling, and the other is below event capturing.

Event capturing

          | |
---------------| |-----------------
| element1    | |                |
|  -----------| |-----------     |
| |element2  \ /          |     |
| -------------------------     |
|  Event CAPTURING          |
-----------------------------------

the event handler of element1 fires first, the event handler of element2 fires last.

For attach an event handler, you can decide which phase to trigger the handler by setting a boolean true when you code:

elem.addEventListener( type, handler, true);//event capturing phase to trigger handler
elem.addEventListener( type, handler, false);//default, event bubbling phase to trigger handler
From above example 1, make a boolean change:
div.addEventListener("click", function(){
 alert('parent');
}, true);
p.addEventListener("click", function(){
 alert('child');
}, false);
When you click on the child, 'parent' will be alerted first in this way.

Reference:

http://www.quirksmode.org/js/events_order.html

http://www.quirksmode.org/js/events_order.html

One application of this will be delegation, you handle all the children by listening to the parent for DOM event.

For example, change background of td in a table on click event: (from JS Ninja)

 var cells = document.getElementsByTagName('td');
 for(var n=0;n<cells.length;n++){
   addEvent(cells[n],'click',function(){this.style.backgroundColor='yellow'}); 
 }
 this is a way to bind many event handlers, which is not good. However, you can reduce to
 var table = document.getElementById('table-1');
 addEvent(table,'click',function(e){
  if(e.target.TagName.toLowerCase() == 'td')
     e.target.style.backgroundColor = 'yellow'; 
 });

With statement in JavaScript

The with statement extends the scope chain for a statement. (from MDN)

with (expression) {
 statement
}

expression: Adds the given expression to the scope chain used when evaluating the statement. The parentheses around the expression are required.
statement: Any statement. To execute multiple statements, use a block statement ({ … }) to group those statements.

var value = 6;
var test = {
 value:5,
 id:0,
 inner:{
 value:9 
 }
};

with(test){
 alert(value); //5
 name = 'added'; //you can assign a new property and only use it inside with statement
 alert(name);//added
 
 with(inner){//inner with test
 alert(value); //9
 }
 
}

alert(value);//6, unaffected global value
alert(test.name);//this will be undefined

The with statement is consider harmful as shown in YUI.