The Future of the Web
...and the one polyfill that makes it all possible today
Browser Support
WeakMap: Chrome, FF, IE11
Object.observe: Chrome 36
MutationObserver: all but IE10, Safari 6.1, Android 4.3
Web Components: Chrome 36, FF 32, Android 4.4
WeakMap
keys are objects
values can be anything
does not prevent garbage collection of keys
Use Cases
Associate data with an element w/out augmenting the element
Associate data with a read-only object
More efficient information hiding
e.g.
var map = new WeakMap();
var someEl =
document.getElementById('someEl');
map.set(someEl, {foo: 'bar'});
if (map.has(document.getElementById('someEl') {
map.get(someEl).foo; // bar
}
Object.observe
Receive callbacks when an object changes in any way
Native impl for Angular's scope.$watch
For Arrays: Array.observe
Angular will delegate in 2.0
Angular
scope.name = 'Ray';
scope.$watch('name', function(newV, oldV) {
console.log('old name: ' + oldV);
console.log('new name: ' + newV);
});
Native
scope.name = "Ray";
Object.observe(scope, function(change) {
if (change.name === 'name') {
console.log('old name: ' +
change.oldValue);
console.log('new value: ' +
change.object[change.name]);
}
});
MutationObserver
Receive callbacks when an element changes in any way
Element descendendants can also be observed
Replacement for inefficient Mutation Events
e.g.
var callback = function(records) { var record = records[0]; // for demo simplicity only var added = record.addedNodes;
if (added.length) { var newTags = 0; for (var i = 0; i < added.length; i++) { if (added[i].className.indexOf('tag') >= 0) { newTags++; } }
if (newTags) { alert(newTags + " new tags added."); } } };
var observer = new MutationObserver(callback); observer.observe(tagsContainerEl, {childList: true});
Web Components
Templates
Custom Elements
Shadow DOM
Templates
Create re-usable content
<template> is not rendered, must be "activated"
Any elements can be children
<template>
<div>hi there</div>
<div>you can't see me right now</div>
<blink>luckily for you</blink>
</template>
Live example [jsbin]
<template>
<div>hi there</div>
<div>you can't see me right now</div>
<blink>luckily for you</blink>
</template>
HTML Imports
Pull another HTML file into the current document
Inject a packaged component (and all deps) w/ one line
Re-use templates stored in a central location
<link rel="import" href="/license.html">
Using an imported document
// Grab the <link> that imports the licensing blurb var licensingLink = document.getElementById('licenseLink');
// Grab the relevant content from the imported doc
var content = licensingLink.import.getElementById('license');
// Append the content to our doc document.body.appendChild(content);
NOTE: Server must return proper CORS headers for cross-domain imports
Custom Elements
<my-custom-element></my-custom-element>
MUST contain a dash
Take heed angular directive writers.
Use ember? You're cool.
Why?
To avoid conflict w/ future standardized elements.
<my-custom-element></my-custom-element>
Creating Custom Elements
Initially an :unresolved HTMLElement
To "resolve", you must document.registerElement
Two types:
-
New* CE
- Type Extension CE
* I just made up this name
Standard Custom Element
<foo-bar> <!-- unresolved content --> </foo-bar> <script> document.registerElement('foo-bar');
</script>
Type Extension Custom Element
<video is="frame-grabber" src="somevideo.mp4">
</video> var frameGrabber = document.createElement('video', 'frame-grabber'); frameGrabber.prototype.grab = function() { // grab current frame & do something w/ it }
Shadow DOM
Allows creation of self-contained, sandboxed web components
A single Node can now be made up of 3 different subtrees:
- Light DOM
- Shadow DOM
- Composed DOM
Light DOM Tree
Part of the "logical DOM"
Content of the custom element provided by integrator
<blink-is-back>
Bring back the blink tag!
</blink-is-back>
Displayed pre-shadow-root render
Shadow DOM Tree
Part of the "logical DOM"
Internal to the custom element, not a child
Not directly accessible via the light DOM
- Include element on page
- Register (if CE)
- myElement.createShadowRoot();
- Append content to shadow root
-
Live example [jsbin]
Composed DOM Tree
Content that is actually rendered
Pieces of the light and shadow DOM combined
Composed DOM from the <blink-is-back> CE:
<blink-is-back>
<div style="text-decoration: line-through;">
Bring back the blink element!
</div>
<div>But seriously, don't make text blink.</div>
</blink-is-back>
Polymer
Shim for all specs discussed in this presentation
Defers to native impls, when present
So, You can use all of these cool specs now!
The first devolving framework
Less important as Web Components et al. coverage increases
Should disappear when these specs are implemented everywhere
A polyfill for Shadow DOM? How?
It's complicated
Everything is wrapped
Required to:
- maintain encapsulation
-
maintain separation between light & shadow DOM elements
- retarget events originally destined for the shadow DOM tree
file-input
Web Component built using Polymer
Allows <input type='file'> to be easily styled
Built-in file validation
More intuitive access to (valid) files
e.g.
<file-input class="btn btn-primary" extensions='["jpeg", "jpg"]' minSize="500000" maxSize="3000000"> <span class="glyphicon glyphicon-file"></span>
Select a file </file-input>
ajax-form
Web Component built using Polymer
Submit a form without a page reload
Send custom headers w/ form submit
Easy access to server response
Dirt simple validation support/control
Submit <file-input> elements too!
e.g.
<form is="ajax-form" method="POST" action="form/handler" headers='{"X-Cust-Header": "FooBar"}'> <input type="text" name="fullname" required>
<input type="submit"> </form>
form.addEventListener('submitted',
function(e) {
if (event.detail.status > 299) {
// submit may have failed
}
}
);
form.addEventListener('invalid',
function(e) {
e.detail.forEach(function(badEl) {
// do something w/ invalid element
});
}
);
Useful Links
The future of the web
By Ray Nicholus
The future of the web
Web Components, Object observers, mutation observers, and the polyfill that makes it all usable now
- 2,330