Building Interactive Sites with AMP
Mashhood Rastgar
Leads the Engineering Team at �Sastaticket.pk. Google Developer Expert for Web and Angular.
@mashhoodr
News and blogs
E-commerce
sites
Actions and events
click
mousedown
mouseup
touchstart
touchend
<div id="warning">This is a warning.</div>
<button onclick="document.getElementById('warning').hidden = true;">
Hide Warning
</button>
<div id="warning">This is a warning.</div>
<button onclick="$('#warning').hide();">
Hide Warning
</button>
<div id="warning">This is a warning.</div>
<button on="tap:warning.hide">
Hide Warning
</button>
Our menu
<amp-sidebar id="sidebar" layout="nodisplay" side="right">
<div class="menu-header">
<div role="button" on="tap:sidebar.toggle" tabindex="0">✕</div>
</div>
<ul class="label">
<li><a href="/product-listing?gender=women">Women</a></li>
<li><a href="/product-listing?gender=men">Men</a></li>
<li><a href="/contact.html">Contact us</a></li>
</ul>
</amp-sidebar>
<div role="button" on="tap:sidebar.toggle" tabindex="0">☰</div>
Composing components
<amp-script>
Menu with submenu
<amp-sidebar id="sidebar1" layout="nodisplay" side="right">
<ul>
<li>Menu item 1<li>
<li>Menu item with submenu!</li>
<amp-accordion layout="container">
<section>
<header>Expand me</header>
<ul>
<li>Submenus are great</li>
<li>Everyone loves them</li>
</ul>
</section>
</amp-accordion>
</li>
</ul>
</amp-sidebar>
Double carousel
<amp-selector id="selector" layout="container"
on="select:carousel.goToSlide(index=event.targetOption)">
<amp-img option="0" selected src="image0.jpg" width="60" height="40"></amp-img>
<amp-img option="1" src="image1.jpg" width="60" height="40"></amp-img>
<amp-img option="2" src="image2.jpg" width="60" height="40"></amp-img>
<amp-img option="3" src="image3.jpg" width="60" height="40"></amp-img>
</amp-selector>
<amp-carousel id="carousel" width="400" height="300" layout="responsive" type="slides"
on="slideChange:selector.toggle(index=event.index, value=true)">
<amp-img src="image0_large.jpg" layout="fill"></amp-img>
<amp-img src="image1_large.jpg" layout="fill"></amp-img>
<amp-img src="image2_large.jpg" layout="fill"></amp-img>
<amp-img src="image3_large.jpg" layout="fill"></amp-img>
</amp-carousel>
Server calls
<amp-form>
<form method="post" action-xhr="/submit-form" target="_top">
<div class="input">
<input type="text" name="name" id="form-name" required>
<label for="form-name">Name:</label>
</div>
<div class="input">
<input type="email" name="email" id="form-email" required>
<label for="form-email">Email:</label>
</div>
<input type="submit" value="Subscribe" class="btn">
<div submit-success>
<template type="amp-mustache">
<p class="form-submit-response">
Success! Thanks {{name}} for subscribing!
</p>
</template>
</div>
<div submit-error>
<template type="amp-mustache">
<p class="form-submit-response">
Oops! Sorry, there was an error.
</p>
</template>
</div>
</form>
<form id="form-cart-delete"
method="POST"
action-xhr="/api/delete-cart-item"
on="submit-success: AMP.setState({cartItemsList: event.response})">
<input type="hidden" name="productId" value=""
[value]="itemToRemove.productId">
<input type="hidden" name="color" value=""
[value]="itemToRemove.color">
<input type="hidden" name="size" value=""
[value]="itemToRemove.size">
</form>
<amp-form>
blank
<amp-list>
amp-mustache
<amp-list id="cart-count" src="/api/cart-count" height="17" width="17">
<template type="amp-mustache">
{{#count}}
<span>{{count}}</span>
{{/count}}
</template>
</amp-list>
{"items":[{"count":1}]}
<amp-list> & amp-mustache
Get fresh price and availability with <amp-list>
<amp-list>
<amp-list>
...
XHR Batching
<amp-list>
<amp-list>
State and binding
var itemToRemove = 123;
<amp-state id="itemToRemove">
<script type="application/json">
{
"productId": 123,
"color": "red",
"size": "L"
}
</script>
</amp-state>
Application state variable
<div role="button" class="cart-remove-icon" tabindex="0"
on="tap: AMP.setState({
itemToRemove: {
productId: 123,
size: 'red',
color: 'L'
}}), form-cart-delete.submit">
✕
</div>
Application state variable
<amp-bind>
State.
Bind.
Mutate.
<amp-state id="team">
<script type="application/json">
{ "star": "Yao Ming" }
</script>
</amp-state>
<p [text]="team.star + ' is tall!'">
Yao Ming is tall!
</p>
<button on="tap:AMP.setState({team: {star: '姚明'}})">
What's his real name?
</button>
Sort and
filter:
<amp-list>
+
<amp-bind>
STATE
<amp-state id="products">
<script type="application/json">
{
"gender": "<%productsGender%>",
"category": "<%productsCategory%>",
"filter": "high-low"
}
</script>
</amp-state>
BIND
<select name="price" id="price"
on="change: AMP.setState({products: {filter: event.value}})">
<option value="high-low">Price: High-Low</option>
<option value="low-high">Price: Low-High</option>
</select>
MUTATE
<amp-list id="products-list"
[src]="'/api/categories?categoryId=' + products.gender + '-' +
products.category + '&sort=' + products.filter"
src="/api/categories?categoryId=<%productsGender%>-<%productsCategory%>&sort=high-low"
height="1000"
width="300"
layout="responsive">
</amp-list>
/api/categories?categoryId=men-shirts&sort=high-low
/api/categories?categoryId=women-shorts&sort=low-high
...
Remove cart item
<amp-list>
+
<amp-bind>
+
<amp-form>
<amp-list> builds cart
<amp-list src="/cart_items" [src]="cartItemsList.items">
. . .
<template type="amp-mustache">
. . .
<div role="button" class="cart-remove-icon" tabindex="0"
on="tap: AMP.setState({
itemToRemove: {
productId: '{{productId}}'
}}),
form-cart-delete.submit">
✕
</div>
</template>
</amp-list>
Clicking button sets ID and submits form
<amp-list src="/cart_items" [src]="cartItemsList.items">
. . .
<template type="amp-mustache">
. . .
<div role="button" class="cart-remove-icon" tabindex="0"
on="tap: AMP.setState({
itemToRemove: {
productId: '{{productId}}'
}}),
form-cart-delete.submit">
✕
</div>
</template>
</amp-list>
Form sends product ID and rebuilds cart
<form id="form-cart-delete"
method="POST" action-xhr="/delete-cart-item"
on="submit-success: AMP.setState(
{cartItemsList: event.response}
)">
<input type="hidden" name="productId" [value]="itemToRemove.productId">
</form>
<amp-list> refreshes cart
<amp-list src="/cart_items" [src]="cartItemsList.items">
. . .
<template type="amp-mustache">
. . .
<div role="button" class="cart-remove-icon" tabindex="0"
on="tap: AMP.setState({
itemToRemove: {
productId: '{{productId}}'
}}),
form-cart-delete.submit">
✕
</div>
</template>
</amp-list>
https://amp.store
camp.samples.amp.dev
go.amp.dev/camp-code
50
Web Worker
DOM
WorkerDOM
postMessage
Main thread
Hello, world!
myscript.js
<amp-script layout="container" src="myscript.js">
<button>Hello amp-script!</button>
</amp-script>
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
document.body.textContent += 'Hello World!';
});
document.body
WordPress AMP
WordPress AMP
Thank you