SlideShare a Scribd company logo
Creating container
components
in Web Components and Angular
ng-conf: March 5, 2015
Kara Erickson
Web Engineer
kara
karaforthewin
Rachael L Moore
UI Engineer
morewry
morewry
Roadmap
Web Components
Angular 1.3
Angular 2.0
Creating GUI container components in Angular and Web Components
Creating GUI container components in Angular and Web Components
<!-- #include virtual="head.html" -->
<!-- #include virtual="menu.html" -->
I render in body.
<!-- #include virtual="foot.html" -->
Server Side Includes
{{> head}}
{{> menu}}
I render in body.
{{> foot}}
mustache
UI Components
<ot-site>
I render in body.
</ot-site>
Native Elements
<input type="range" />
<input type="range" min="1"
max="8" />
Creating GUI container components in Angular and Web Components
Creating GUI container components in Angular and Web Components
<div id="site">
</div>
Component Development
<div id="site">
<header></header>
</div>
Head 
Component Development
<div id="site">
<header></header>
<nav></nav>>
</div>
Component Development
Menu 
<div id="site">
<header></header>
<nav></nav>
<main></main>
</div>
Component Development
Body 
<div id="site">
<header></header>
<nav></nav>
<main></main>
</div>
Component Development
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
</div>
Component Development
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
Component Development
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
Component Development
<div id="site">
<header>
<svg id="logo"></svg>
<!-- point-1 -->
</header>
<nav>
<!-- point-2 -->
</nav>
<main>
<!-- point-3 -->
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
Component Development
Component Use
<ot-site>
</ot-site>
Component Use
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
I render in head.
I render in menu.
I render in body.
Component Use
<ot-site>
<div>
<!-- insert-1 -->
I render in head.
</div>
<div>
<!-- insert-2 -->
I render in menu.
</div>
<div>
<!-- insert-3 -->
I render in body.
</div>
</ot-site>
I render in head.
I render in menu.
I render in body.
<div id="site">
<header>
<svg id="logo"></svg>
<!-- point-1 -->
</header>
<nav>
<!-- point-2 -->
</nav>
<main>
<!-- point-3 -->
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
<ot-site>
<div>
<!-- insert-1 -->
I render in head.
</div>
<div>
<!-- insert-2 -->
I render in menu.
</div>
<div>
<!-- insert-3 -->
I render in body.
</div>
</ot-site>
Match Content → ← Match Component
Creating GUI container components in Angular and Web Components
Head 
Menu 
Body 
Web Components
Shadow DOM
<ot-site>
Native Elements
<input type="range" />
Secrets and Shadows
Creating GUI container components in Angular and Web Components
Shadow DOM
Light DOM
Shadow DOM
Light DOM
<input type="range" />
<input type="range" />
#shadow-root (user-agent)
<div pseudo="track" id="track">
<div pseudo="thumb" id="thumb">
</div>
</div>
UA Shadow DOM
...had flourished.
<span id="myspan">
Long ago there was something in me, but now that thing is
gone.
</span>
I cannot...
Shadow Host
var $ = document.querySelector.bind(document)
var span = $("#myspan")
span.createShadowRoot()
Shadow Root
...had flourished.
<span id="myspan">
Long ago there was something in me, but now that thing is
gone.
</span>
I cannot...
Shadow Host
...had flourished.
<span id="myspan">
#shadow-root
Long ago there was something in me, but now that thing is
gone.
</span>
I cannot...
Shadow Root
Before
...had flourished. Long
ago there was something
in me, but now that thing
is gone. I cannot...
After
...had flourished. I
cannot...
var host = $("ot-site")
host.createShadowRoot()
host.shadowRoot.innerHTML = ``
ot-site.js
host.shadowRoot.innerHTML = .``.
ot-site.js
host.shadowRoot.innerHTML = `
<div id="site">
<header>
<svg id="logo"></svg>
<!-- point-1 -->
</header>
<nav>
<!-- point-2 -->
</nav>
<main>
<!-- point-3 -->
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
`
ot-site.js
host.shadowRoot.innerHTML = `
<div id="site">
<header>
<svg id="logo"></svg>
<!-- point-1 -->
</header>
<nav>
<!-- point-2 -->
</nav>
<main>
<!-- point-3 -->
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
`
ot-site.js
host.shadowRoot.innerHTML += `
<style>
/* use your imagination */
</style>
`
ot-site.js
<ot-site>
#shadow-root
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>©</footer>
</div>
<style>/**/</style>
</ot-site>
Composed DOM
Creating GUI container components in Angular and Web Components
host.shadowRoot.innerHTML = `
<div id="site">
<header>
<svg id="logo"></svg>
<!-- point-1 -->
</header>
<nav>
<!-- point-2 -->
</nav>
<main>
<!-- point-3 -->
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
`
ot-site.js
host.shadowRoot.innerHTML = `
<div id="site">
<header>
<svg id="logo"></svg>
<content />
</header>
<nav>
<content />
</nav>
<main>
<content />
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
`
ot-site.js
host.shadowRoot.innerHTML = `
<div id="site">
<header>
<svg id="logo"></svg>
<content select="" />
</header>
<nav>
<content select="" />
</nav>
<main>
<content select="" />
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
`
ot-site.js
host.shadowRoot.innerHTML = `
<div id="site">
<header>
<svg id="logo"></svg>
<content select="[head]" />
</header>
<nav>
<content select="[menu]" />
</nav>
<main>
<content select="[body]" />
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
`
ot-site.js
<ot-site>
<div>
<!-- insert-1 -->
I render in head.
</div>
<div>
<!-- insert-2 -->
I render in menu.
</div>
<div>
<!-- insert-3 -->
I render in body.
</div>
</ot-site>
index.html
<ot-site>
<div head>
I render in head.
</div>
<div menu>
I render in menu.
</div>
<div body>
I render in body.
</div>
</ot-site>
index.html
Match Content →
<div id="site">
<header>
<svg id="logo"></svg>
<content select="[head]"/>
</header>
<nav>
<content select="[menu]"/>
</nav>
<main>
<content select="[body]"/>
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
<ot-site>
<div head>
I render in head.
</div>
<div menu>
I render in menu.
</div>
<div body>
I render in body.
</div>
</ot-site>
← Match Component
Light DOMShadow DOM
<div id="site">
  <header>
    <svg id="logo"></svg>
    <content select="[head]"/>
</header>
<nav>
<content select="[menu]"/>
</nav>
<main>
<content select="[body]"/>
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
<ot-site>
<div head>
I render in head.
</div>
<div menu>
I render in menu.
</div>
<div body>
I render in body.
</div>
</ot-site>
Creating GUI container components in Angular and Web Components
<div id="site">
<header>
<svg id="logo"></svg>
<content select="[head]"/>
</header>
<nav>
<content select="[menu]"/>
</nav>
<main>
<content select="[body]"/>
</main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>
Light DOMShadow DOM
<ot-site>
<div head>
I render in head.
</div>
<div menu>
I render in menu.
</div>
<div body>
I render in body.
</div>
</ot-site>
I render in head.
I render in menu.
I render in body.
I render in head.
I render in menu.
I render in body.
Code Demo: Content Projection
Code Demo: Final
Angular 1.3
Transcluding Directive
<ot-site>
.directive("otSite", function() {
return {
template: ``
};
});
ot-site.js
.directive("otSite", function() {
return {
template: `
<div id="site">
<header> <!-- point-1 -->
<svg id="logo"></svg>
</header>
<nav></nav> <!-- point-2 -->
<main></main> <!-- point-3 -->
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
ot-site.js
Creating GUI container components in Angular and Web Components
Transclusion
<ot-site>
</ot-site>
index.html
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
index.html
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
index.html
ot-site.js
.directive("otSite", function() {
return {
template: `
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: `
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
DOM
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
DOM
DOM
<ot-site>
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>©</footer>
</div>
</ot-site>
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
DOM
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
Clone DOM
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
Clone DOM
Clone DOM
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
<ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
</ot-site>
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
<ot-site>
</ot-site>
Clone DOM
<ot-site>
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>©</footer>
</div>
</ot-site>
Clone
<div>
I render in head.
</div>
<div>
I render in menu.
</div>
<div>
I render in body.
</div>
DOM
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: `
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: `
<div id="site">
<header ng-transclude>
<svg id="logo"></svg>
</header>
<nav ng-transclude></nav>
<main ng-transclude></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
 
Code Demo
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: `
<div id="site">
<header ng-transclude>
<svg id="logo"></svg>
</header>
<nav ng-transclude></nav>
<main ng-transclude></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: `
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: `
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>
© 2015 OpenTable, Inc.
</footer>
</div>`
};
});
<ot-site>
<div>
<!-- insert-1 -->
I render in head.
</div>
<div>
<!-- insert-2 -->
I render in menu.
</div>
<div>
<!-- insert-3 -->
I render in body.
</div>
</ot-site>
index.html
<ot-site>
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
</ot-site>
index.html
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
DOMClone
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
DOMClone
angular.forEach(clone, function(cloneEl) {});
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
DOMClone
angular.forEach(clone, function(cloneEl) {});
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
DOMClone
angular.forEach(clone, function(cloneEl) {});
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
DOMClone
var tId = cloneEl.attributes["t-to"].value;
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
DOMClone
var target = temp.find('[t-id="'+tId+'"]');
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
DOMClone
target.append(clone);
<div t-to="head">
I render in head.
</div>
<div t-to="menu">
I render in menu.
</div>
<div t-to="body">
I render in body.
</div>
DOMClone
<ot-site>
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
<div t-to="head">
I render in head.
</div>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer>©</footer>
</div>
</ot-site>
</ot-site>target.append(clone);
angular.forEach(clone, function(cloneEl) {
// get desired target ID
var tId = cloneEl.attributes["t-to"].value;
// find target element with that ID
var target = temp.find('[t-id="'+tId+'"]');
// append element to target
target.append(cloneEl);
});
custom-transclude.js
Transclude function
transclude(function(clone) {
# DOM manipulation
});
Transclude function access points
compile: function(tElem, tAttrs, transclude)
controller: function($scope, $element, $transclude)
link: function(scope, iElem, iAttrs, ctrl, transclude)
compile: function(tElem, tAttrs, transclude)
controller: function($scope, $element, $transclude)
link: function(scope, iElem, iAttrs, ctrl, transclude)
Transclude function access points
compile: function(tElem, tAttrs, transclude)
controller: function($scope, $element, $transclude)
link: function(scope, iElem, iAttrs, ctrl, transclude)
Transclude function access points
Directive Life Cycle
1
2
3
4
5
6
7
8
Child compile
Child controller
Child pre-link
Child post-link
Parent compile
Parent controller
Parent pre-link
Parent post-link
Directive Life Cycle
1
2
3
4
5
6
7
8
Child compile
Child controller
Child pre-link
Child post-link
Parent compile
Parent controller
Parent pre-link
Parent post-link
Transclude function availability
compile: function(tElem, tAttrs, transclude)
controller: function($scope, $element, $transclude)
link: function(scope, iElem, iAttrs, ctrl, transclude)
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
}
};
});
ot-site.js
.directive("otSite", function() {
return {
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
transcluding directive with isolate scope
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
Code Demo
Angular 2.0
Component Directive
<ot-site>
Angular 1.3
Transclusion
Angular 2.0
Shadow DOM
Angular 2.0Angular 1.3
Transclusion
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer> © 2015 OpenTable, Inc. </footer>
</div>
ot-site template
<div id="site">
<header t-id="head">
<svg id="logo"></svg>
</header>
<nav t-id="menu"></nav>
<main t-id="body"></main>
<footer> © 2015 OpenTable, Inc. </footer>
</div>
ot-site template
<div id="site">
<header>
<svg id="logo"></svg>
</header>
<nav></nav>
<main></main>
<footer> © 2015 OpenTable, Inc. </footer>
</div>
ot-site template
<div id="site">
<header>
<svg id="logo"></svg>
<content select="[head]"></content>
</header>
<nav>
<content select="[menu]"></content>
</nav>
<main>
<content select="[body]"></content>
</main>
<footer> © 2015 OpenTable, Inc. </footer>
</div>
ot-site template
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
Shadow DOM
Angular 2.0Angular 1.3
Transclusion
Manual scope
proper transclusion scope
Transclusion
Manual scope
Shadow DOM
Sensible default context
Angular 2.0Angular 1.3
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
ot-site.js
.directive("otSite", function() {
return {
template: ...
};
});
.directive(."otSite"., function() {
return {
template: ...
};
});
ot-site.js
ot-site.js
.directive(."otSite"., function() {
return {
.template: ....
};
});
Shadow DOM
Sensible default context
Angular 2.0Angular 1.3
Transclusion
Manual scope
One DDO
ot-site.js
.directive("otSite", function() {
return {
scope: {},
transclude: true,
template: ...,
link: function(scope, elem, attr, ctrl, transclude) {
transclude(function(clone) {
angular.forEach(clone, function(cloneEl) {
var tId = ...
var target = ...
if (target.length) {...}
else {...}
});
});
}
};
});
Shadow DOM
Sensible default context
Class & annotation
Angular 2.0Angular 1.3
Transclusion
Manual scope
One DDO
class OtSite() {
constructor () {
}
// public methods here
}
ot-site.js
ot-site.js
class OtSite() {
constructor () {
}
// public methods here
}
OtSite.annotations = [
];
ot-site.js
class OtSite() {
constructor () {
}
// public methods here
}
OtSite.annotations = [
new Component({
})
];
ot-site.js
class OtSite() {
constructor () {
}
// public methods here
}
OtSite.annotations = [
new Component({
selector: "ot-site"
})
];
ot-site.js
class OtSite() {
constructor () {
}
// public methods here
}
OtSite.annotations = [
new Component({
selector: "ot-site"
}),
new Template({
url: "ot-site.html"
})
];
ot-site.js
class OtSite() {
constructor () {
}
// public methods here
}
OtSite.annotations = [
new Component({
selector: "ot-site"
}),
new Template({
url: "ot-site.html"
})
];
ot-site.js
class OtSite() {
constructor () {
}
// public methods here
}
@Component({
selector: "ot-site"
})
@Template({
url: "ot-site.html"
})
class OtSite() {
constructor () {
}
// public methods here
}
@Component({
selector: "ot-site"
})
@Template({
url: "ot-site.html"
})
ot-site.js
@Component({
selector: "ot-site"
})
@Template({
url: "ot-site.html"
})
class OtSite() {
constructor () {
}
// public methods here
}
ot-site.js
ot-site.js
@Component({
selector: "ot-site"
})
@Template({
url: "ot-site.html"
})
class OtSite() {
constructor () {
}
// public methods here
}
<ot-site>
<div head>
I render in head.
</div>
<div menu>
I render in menu.
</div>
<div body>
I render in body.
</div>
</ot-site>
Thanks, everyone!
Kara Erickson
Web Engineer
kara
karaforthewin
Rachael L Moore
UI Engineer
morewry
morewry
We’re hiring!
Visit our careers page at
opentable.com/careers/
We’re hiring!
Visit our careers page at
opentable.com/careers/

More Related Content

What's hot (20)

PDF
GWT integration with Vaadin
Peter Lehto
 
KEY
Jarv.us Showcase — SenchaCon 2011
Chris Alfano
 
PDF
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Thomas Fuchs
 
PDF
Polymer 1.0
Cyril Balit
 
PPTX
Getting the Most Out of jQuery Widgets
velveeta_512
 
PDF
Write Less Do More
Remy Sharp
 
PDF
jQuery in 15 minutes
Simon Willison
 
KEY
jQuery Anti-Patterns for Performance & Compression
Paul Irish
 
PDF
ActiveResource & REST
Robbert
 
KEY
An in-depth look at jQuery UI
Paul Bakaus
 
KEY
Html5 For Jjugccc2009fall
Shumpei Shiraishi
 
PPTX
jQuery for Sharepoint Dev
Zeddy Iskandar
 
PDF
Yearning jQuery
Remy Sharp
 
PDF
Sane Async Patterns
TrevorBurnham
 
KEY
Javascript unit testing, yes we can e big
Andy Peterson
 
PDF
Better Selenium Tests with Geb - Selenium Conf 2014
Naresha K
 
PDF
Polymer - pleasant client-side programming with web components
psstoev
 
PDF
Is HTML5 Ready? (workshop)
Remy Sharp
 
PDF
HTML5: friend or foe (to Flash)?
Remy Sharp
 
PDF
HTML5: where flash isn't needed anymore
Remy Sharp
 
GWT integration with Vaadin
Peter Lehto
 
Jarv.us Showcase — SenchaCon 2011
Chris Alfano
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Thomas Fuchs
 
Polymer 1.0
Cyril Balit
 
Getting the Most Out of jQuery Widgets
velveeta_512
 
Write Less Do More
Remy Sharp
 
jQuery in 15 minutes
Simon Willison
 
jQuery Anti-Patterns for Performance & Compression
Paul Irish
 
ActiveResource & REST
Robbert
 
An in-depth look at jQuery UI
Paul Bakaus
 
Html5 For Jjugccc2009fall
Shumpei Shiraishi
 
jQuery for Sharepoint Dev
Zeddy Iskandar
 
Yearning jQuery
Remy Sharp
 
Sane Async Patterns
TrevorBurnham
 
Javascript unit testing, yes we can e big
Andy Peterson
 
Better Selenium Tests with Geb - Selenium Conf 2014
Naresha K
 
Polymer - pleasant client-side programming with web components
psstoev
 
Is HTML5 Ready? (workshop)
Remy Sharp
 
HTML5: friend or foe (to Flash)?
Remy Sharp
 
HTML5: where flash isn't needed anymore
Remy Sharp
 

Viewers also liked (7)

PDF
Distributing UI Libraries: in a post Web-Component world
Rachael L Moore
 
PDF
Operations Tooling for UI - DevOps for CSS Developers
Rachael L Moore
 
PDF
3a8 picture driven computing in assistive
AEGIS-ACCESSIBLE Projects
 
PDF
Microformats I: What & Why
Rachael L Moore
 
PDF
Refresh Tallahassee: The RE/MAX Front End Story
Rachael L Moore
 
PDF
Redefining your core product
InVision App
 
PDF
Open table pdf
Stephen Woodruff
 
Distributing UI Libraries: in a post Web-Component world
Rachael L Moore
 
Operations Tooling for UI - DevOps for CSS Developers
Rachael L Moore
 
3a8 picture driven computing in assistive
AEGIS-ACCESSIBLE Projects
 
Microformats I: What & Why
Rachael L Moore
 
Refresh Tallahassee: The RE/MAX Front End Story
Rachael L Moore
 
Redefining your core product
InVision App
 
Open table pdf
Stephen Woodruff
 
Ad

Recently uploaded (20)

PDF
From Code to Challenge: Crafting Skill-Based Games That Engage and Reward
aiyshauae
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PDF
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
From Code to Challenge: Crafting Skill-Based Games That Engage and Reward
aiyshauae
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
Ad

Creating GUI container components in Angular and Web Components