Jan 6, 2017

HTML Import

HTML5 Import provides a standard way of importing html from a separate file onto the page, in the similar way we reference JavaScript and CSS. This can also be used to bundle JS, CSS and HTML. Without bundling you will have to have style and script referenced on all your pages, and also in a particular order. This way you can bundle everything for your custom element so that consumer don't have to worry about referencing necessary CSS/JS. HTML from external file must be added to the head of the page. 

<link rel="import" href="myimport.html" id="myimport">

JavaScript and CSS from the imported file get executed and applied immediately where as html is inert, meaning it's loaded in the browser but is not rendered. So if you have console.log('i am coming from myimport.html') javascript in the myimport.html, this will get executed by just putting above link. But to render html from the imported page you need to do following

     <script>
         var content = document.getElementById('myimport').import;
         var markupimportedfromfile = content.getElementById('fromimportedfile');
         document.body.appendChild(markupimportedfromfile);
     </script>
With the template tag, everything inside (markup or JS or CSS) is inert until cloned and this will still be the case if it is in the import file, but any CSS and JS directly defined in the import file will be executed\applied immediately. CORS rule will be applied for importing html.

Imported file can also have import within it. You can use this for importing JS/CSS library, this way sub-import file will have these libraries and you will import this file in all your custom element file. This can help in avoiding different custom element using different version of those libraries.

Referencing Owner Document
If you use selector on document object (document.querySelector) in the import file, it will search through the DOM defined in the file where it is imported. To get reference from the import file, you must use selector on document.currentScript.ownerDocument

Events
The link element has two events, onload and onerror. Script for that need to be added before adding the link

<script>
function loaded(event)  {
  console.log('import loaded');
}
 
function error(event)  {
  console.log('could not load ' + event.target.href);
}
     
    </script>
    
    <link rel="import" id="myimport" href="myimport.html" onload="loaded(event)" onerror="error(event)">`

Jan 4, 2017

Table of Content

Shadow DOM

Shadow DOM encapsulates DOM sub tree and their style. It creates a boundary, so that it maintains a separation from the main document. This avoids leaking of styles from the main DOM to shadow DOM and visa versa. Markup is also protected as they cannot be accessed through standard selectors. In past people have used iframe to achieve short of similar feature, but that comes with extra baggage as iframe is mainly designed to host separate web page. Also interaction between iframe and its host may not be straight forward.

How to Create Shadow DOM
                   var host = document.createElement('div');                   
                   var root = host.createShadowRoot();
                   root.innerHTML = "<h1>This is shadow DOM</h1>";

Terminologies

  • Light DOM - DOM which is not within shadow DOM is called Light DOM. In other words it the DOM which people refer prior to concept of shadow..
  • Logicl DOM - Together Light DOM and Shadow DOM are referred as logical DOM.
  • Shadow Host - Its the element in the Light DOM which host shadow DOM
  • shadow-root - This contains the shadow dom, and will be a child to the main DOM. Anything underneath this cannot be accessed through standard selector like this (document.querySelector('h1')),rather you have to use selector on shadow root object. All following methods are supported shadow root
    • getElementById()
    • getElementByClassName()
    • getElementByTagName()
    • getElementByTagNameNS()
    • querySelector()
    • querySelectorAll()

java script
js within shadow dom is not encapsulated. js defined in template tag will still be attached to windows object, but since markup will not be accessible across shadow boundary through standard selector, chances of accidentally impacting mark up across boundary is very less.

Content Insertion Points
Content tag provides a way through which mark up defined in the Light DOM can be distributed in Shadow DOM. You can provide selector that specify the markup which you want to distribute. You can have multiple content tag and the first content tag which match selector and is not already inserted will display it. If you create empty content tag, it will insert everything which is not already inserted. If there is no empty content tag, then only selected markup will be displayed, rest will be ignored.

Content create an insertion point. Elements inserted (which comes from Light DOM) at this insertion point is called distributed node. Distributed nodes are just displayed at the insertion point and they are not actually inserted into the Shadow DOM. Distributed node remains part of Light DOM and you can still user standard selector (document.querySelector('h1')) for distributed node, whereas selector on the root (root.querySelector('content div')) will not return anything.

Following api are provided in order to access distributed node as well as insertion point
getDistributedNode 
root.querySelector('content').getDistributedInsertionNode()

getDistributedInsertionPoints Get list of all content tag where light dom is inserted
document.querySelector('h1').getDistributedInsertionPoints()

Supported Content Selector
<content select="h1"> match all h1 element from light DOM
<content select=".myclass">
<content select=".myid">
<content select="input type=[text]">
<content select=":not(#test1)">

Shadow Insertion Points
You can create multipe shadow root for a host, but only the last one (referred as youngest) will be displayed. To include the previous shadow root, you need to include shadow tag in the displayed shadow root.

var host = document.getElementById('myshadowhost');
var root1 = host.createShadowRoot();
var root2 = host.createShadowRoot();
var root3 = host.createShadowRoot();
root1.innerHTML = '<div>Shadow DOM root1</div>';
root2.innerHTML = '<div>Shadow DOM root2</div> <shadow></shadow>'; // This will display older shadowRoot which in this case is root1
root3.innerHTML = '<div>Shadow DOM root3</div> <shadow></shadow>'; // This will display older shadowRoot which in this case is root2

You can use following methods in javascript to get hold of shadow roots
root.olderShadowRoot
host.shadowRoot will always return youngest shadowRoot

Events
Some of shadow dom events (like click) are re targeted as if they are coming from shodow host, where as some of the events (like change) are just killed at within shadow dom and is not re targeted.

Jan 3, 2017

Custom Element

Custom element give power of defining your own custom element which can be used as native html element. You can also extend existing native HTML element, which can add more features to it, based on your requirement.

Currently most of the web pages looks like this, this may not be easy to understand/maintain as div is just a generic container and which does not indicate about the item which it contains.

<div>
<div>
<div></div>
<div></div>
</div>
</div>

With the use of custom element you can transform it like this. By element's name itself its clear what it contains.

<product-item>
<product-review>
<user-avatar></user-avatar>
<user-comment></user-comment>
</product-review>
</product-item>

Registering and utilizing a custom element

  • Define a prototype for the custom element

                 var MyElementPrototype = Object.create(HTMLElement.prototype);

                 var MyButtonPrototype = Object.create(HTMLButtonElement.prototype);


  • Add callback function in which you create element


               MyElementPrototype.createdCallback = function(){
                              this.innerHTML = "<h2>My Element</h2>";
                       }

              MyButtonPrototype.createdCallback = function(){
     this.style.color='red';
     this.innerHTML = "test";
      }

  • Register the element

             var MyElement = document.registerElement('my-element',{
                                   prototype:MyElementPrototype
                     });

             var MyButtonPrototype = document.registerElement('my-button',{
                                  prototype:MyButtonPrototype,
                  extends: 'button'
     });

Instantiate Custom element

  • Markup

 <my-element/>


  • new operator

    var myElement = new MyElement();
    document.getElementById('someid').innerHTML = '<my-element/>'


  • create element

     var myElement = document.createElement('my-element');
     document.getElementById('someid').appendChild(myElement);


  • Inner HTMLElement

     document.getElementById('someid').innerHTML = '<my-element/>'

Life cycle callback

  • createdCallback - Instance is created
  • attachedCallback - Instance inserted to DOM
  • detachedCallback - Instance detached from DOM
  • attributeChangedCallback - Any attribute update

Dec 24, 2016

Template

Template is inert chunk of cloneable markup.  Markup inside template is hidden and will not have any side effect until it's activated, for example if there is a image tag, it's source will not be loaded until it is activated, bad path on the image tag will not show 404. Templates can be placed anywhere on the html. Content of the template is not accessible via normal selection techniques like document.getElementById or querySelector can't return child node of the template.

Defining template


       <template id="mytemplate1">
             <p>  I will not be displayed until I am cloned and displayed on the page. <span class="injectsomething"></span></p>
    </template>


Activating Template


 <script>
       var template = document.querySelector('template');
        var clone = document.importNode(template.content, true);
        clone.querySelector('.injectsomething').textContent = "This has been dynamically injected";
        document.body.appendChild(clone);
 </script>

If you are using nested templte, then each template has to be cloned and added separately.

Injecting Dynamic Data
You can have a place holder in the template which you can handle in the script to dynamically inject data. More convenient (as in case of angular {}[]) way of inserting data are available through polymer, though HTML5 and template spec does not require that support.

Dec 23, 2016

why web component

Undescriptive Markup - Currently we have deeply nested makeup (div/span), which sometimes becomes harder to understand/maintain. Refer any of the popular web page source and you will find deep nested mark up. Though some provide meaningful id/class.

Style conflicts - There is no guarantee that css from one part of the page will not conflict to other.

No native templates - Template is a mechanism for holding client-side content that is not to be rendered when a page is loaded, but may be subsequently be instantiated during runtime using JS. Its a content fragment that can be used in the document.

HTML Imports - There is no way to include and reuse HTML documents in other HTML documents.

No bundling - You cannot bundle css, javascript, html together. like bootstarp need to have at least 3 reference - jquery,bootstrap js and css. 

No standard - Multiple library like jQuery, angular (directive), bootstrap provide their own convention, but there is no standard. 

HTML5 Web component addresses these issues, by using combination of following four technologies.
  • Template
  • Shadow DOM
  • Custom Element
  • HTML Import

Dec 20, 2016

My first look at elastic search

Elasticsearch is a document oriented database. The entire object is stored in a denormalized state which enhances retrieval performance, as you do not need to join tables, like in case of relational database. On the other hand, update becomes little complicated, since you have to update all the documents rather than updating a referenced table. Relational db also let you specify constraints (like foreign key etc), which is not with the case of document oriented db.

Elasticsearch is schema flexible, which means you do not have to specify schema upfront, rather it recommended to have schema (mapping) defined based on you search need.

Basic concept

  • Cluster
  • Node
  • Index - Its a collection of document which are somewhat similar. Index is stored in set of shards and during search, elasticsearch merges result from all searched shards. So if you have documents which has minor difference in structure, its better to store it in single index with multiple types, which will result in less number of merge. But in case if you have completely different structure, then its better to have separate index, as the way elasticsearch stores data, fields that exist in one type will also consume resources for documents of types where this field does not exist. (localhost:9200/my_index)
  • Type - Type is defined for a document which has set of properties. You can have multiple types for a single index. ( localhost:9200/my_index/my_type)
  • Document
  • Shards & Replicas - Elasticsearch provides the ability to subdivide your index into multiple pieces called shards, which horizontally split/scale the data and also help in performance by allowing you to distribute and parallelize operations across shards.

Mapping
Enabled - Elasticsearch tries to index all of the fields you give it, but sometimes you want to just store the field without indexing it as you may not want to query on the basis of that field.
Dynamic - By defaults fields are dynamically added to a document. The dynamic setting (true, false, strict) controls whether new fields can be added dynamically or not. Setting dynamic does not alter content of source.

Analysis
Analysis is the process of converting text into tokens or terms which are added to the inverted index for searching. Analyzers are used for both indexing and searching (only in case of match query and not term). By default it uses the same analyzer for both indexing and searching, but you can have different analyzer for searching.

An analyzer does following

  • A character filter receives the original text as a stream of characters and can transform the stream by adding, removing, or changing characters.
  • A tokenizer receives a stream of characters, breaks it up into individual tokens, and outputs a stream of tokens. ex whitespace, standard (based on whitespace and punctuation), ngram (min/max gram)
  • A token filter receives the token stream and may add, remove, or change tokens. ex lowercase, stopword (stop the word from being indexed), snowball (removes trailing characters such as "ed," "ing," etc.)