modular applications with montage components
DESCRIPTION
There is a growing demand to build increasingly complex mobile applications with HTML5, in part due to its cross-platform nature. However delivering these applications is still very challenging. The Montage framework was designed from the ground up to build complex HTML5 applications. This talk will explain how Montage’s reusable and encapsulated Components provides a natural and effective way to write modular, robust, applications by allowing team members to work on different part at the same time.TRANSCRIPT
montagejs.org
Benoît Marchant
with Montage Components
Modular Applications
modules
template
mobile
componentHTML5
encapsulated
MVC
data-binding
promises CommonJS
declarative
BSD
serialization
package
separation of concernsreusable
ECMAScript 5
composition
TEAMworkflow
simplify
write once batterygpucpuapplications
property change
listener
CSS
framework
widgetsflow repetition condition
substitution
text
button
loader
listprogress
slider
inputaudioslot
videocheckbox
radiotoggle
textfield
event
cross-platform
deferred drawing
Mobile Applications
HTML5 vs Native
HTML5 vs Native
Janky User Experience
HTML5 vs Native
Janky User Experience
Longer Development Time
HTML5 vs Native
Janky User Experience
Longer Development Time
Higher Development Cost
HTML5 vs Native
Janky User Experience
Longer Development Time
Higher Development Cost
Harder to Iterate
Modular Applications
Simple Application
Large Application
Large Application
Montage Application
Refactor
Refactor
Montage Application
Popcorn Demo
montagejs.org/apps/popcorn/
Component
Assigned one DOM Element
MVC Structure
From Widget to App Specific
Deferred Drawing
Template
Deferred Drawing
Maximize Performance
Orchestrate DOM Changes
Third Party Components
Degrade Gracefully
willDraw() / draw() / didDraw()
Template
Full HTML5 document
Resource Encapsulation
Object Serialization
Great JS / CSS Team Work
Automatic Dependencies Load
.reelHTML JS CSS
Identify Components
Main ComponentLoads data from Web Service
Relies on sub-components for presentation
Movie Content
Navigation
Movie Content
Navigation
Components establish their own API to accept data through properties
or methods
MainMovie Categories
Event to change CategoryId
Selected CategoryId
MainMovie Categories
Event to change CategoryId
Selected CategoryId
MainMovie Categories
Event to change CategoryId
Selected CategoryId
Movie Content
Movie Content
Flow Component
Movie Detail Component
Movie Detail Component
Flow Component
Movie ContentmoviesController
selectedMovie
<html>...<body> <div data-montage-id="facade-flow" class="facade-flow"> <div data-montage-id="flow" class="flow flow-fade-out"> <div data-montage-id="image" class="Image"></div> </div> <div class="film"></div> <div data-montage-id="details"></div> </div></body></html>
Main.reel/Main.html
<div data-montage-id="facade-flow" class="facade-flow"> <div data-montage-id="flow" class="flow flow-fade-out"> <div data-montage-id="image" class="Image"></div> </div> <div class="film"></div> <div data-montage-id="details"></div> </div>
Markup
Object Serialization<script type="text/montage-serialization">{ "owner": { "properties": { "element": {"#": "facade-flow"} } },
... "flow": { "prototype": "montage/ui/flow.reel", "properties": { "element": {"#": "flow"}, "isSelectionEnabled": false, "cameraFov": 36.99, "cameraTargetPoint": [0, 0, 0], "stride": 1 }, "bindings": { "contentController": {"<-": "@owner.buttonController"} } },
"details": { "prototype": "ui/details.reel", "properties": { "element": {"#": "details"} }, "bindings": { "data": {"<-": "@owner.selectedMovie" } } }}</script>
<div data-montage-id="facade-flow" class="facade-flow"> <div data-montage-id="flow" class="flow flow-fade-out"> <div data-montage-id="image" class="Image"></div> </div> <div class="film"></div> <div data-montage-id="details"></div> </div>
<script type="text/montage-serialization">{ "owner": { "properties": { "element": {"#": "facade-flow"} } },
... "flow": { "prototype": "montage/ui/flow.reel", "properties": { "element": {"#": "flow"}, "isSelectionEnabled": false, "cameraFov": 36.99, "cameraTargetPoint": [0, 0, 0], "stride": 1 }, "bindings": { "contentController": {"<-": "@owner.buttonController"} } },
"details": { "prototype": "ui/details.reel", "properties": { "element": {"#": "details"} }, "bindings": { "data": {"<-": "@owner.selectedMovie" } } }}</script>
"flow": { "prototype": "montage/ui/flow.reel", "properties": { "element": {"#": "flow"}, "cameraFov": 36.99, "cameraTargetPoint": [0, 0, 0], "stride": 1 }, "bindings": { "contentController": {"<-": "@owner.moviesController"} } },
<div data-montage-id="facade-flow" class="facade-flow"> <div data-montage-id="flow" class="flow flow-fade-out"> <div data-montage-id="image" class="Image"></div> </div> <div class="film"></div> <div data-montage-id="details"></div> </div>
Module Id
"flow": { "prototype": "montage/ui/flow.reel", "properties": { "element": {"#": "flow"}, "cameraFov": 36.99, "cameraTargetPoint": [0, 0, 0], "stride": 1 }, "bindings": { "contentController": {"<-": "@owner.moviesController"} } },
<div data-montage-id="facade-flow" class="facade-flow"> <div data-montage-id="flow" class="flow flow-fade-out"> <div data-montage-id="image" class="Image"></div> </div> <div class="film"></div> <div data-montage-id="details"></div> </div>
Setting Property Values
"flow": { "prototype": "montage/ui/flow.reel", "properties": { "element": {"#": "flow"}, "cameraFov": 36.99, "cameraTargetPoint": [0, 0, 0], "stride": 1 }, "bindings": { "contentController": {"<-": "@owner.moviesController"} } },
<div data-montage-id="facade-flow" class="facade-flow"> <div data-montage-id="flow" class="flow flow-fade-out"> <div data-montage-id="image" class="Image"></div> </div> <div class="film"></div> <div data-montage-id="details"></div> </div>
data binding
<div data-montage-id="facade-flow" class="facade-flow"> <div data-montage-id="flow" class="flow flow-fade-out"> <div data-montage-id="image" class="Image"></div> </div> <div class="film"></div> <div data-montage-id="details"></div> </div>
"details": { "prototype": "ui/details.reel", "properties": { "element": {"#": "details"} }, "bindings": { "data": {"<-": "@owner.selectedMovie" } } },
Movie Detail
Movie Detail
Title
SynopsisTrailer Button
Rent Button
Release Date Runtime Audience Critics
Movie Detail Components
DynamicText
DynamicText
DynamicText DynamicText Dynamic Text Dynamic Text
Button
Button
Movie Detail
Title
Description
Date Runtime Audience
Critics
Trailer Button
Rent Button
data.title
data.date
actionEvent
actionEvent
data.criticScore
data.synopsis
data.runtimedata.audienceScore
Trailer Button
action event
"trailerButton": { "prototype": "montage/ui/button.reel", "properties": { "element": {"#": "trailer-button"} }, "listeners": [ { "type": "action", "listener": {"@": "owner"} } ] },
<button data-montage-id="trailer-button">Trailer</button>
Listeners
"trailerButton": { "prototype": "montage/ui/button.reel", "properties": { "element": {"#": "trailer-button"} }, "listeners": [ { "type": "action", "listener": {"@": "owner"} } ] },
<button data-montage-id="trailer-button">Trailer</button>
Object Reference
"trailerButton": { "prototype": "montage/ui/button.reel", "properties": { "element": {"#": "trailer-button"} }, "listeners": [ { "type": "action", "listener": {"@": "owner"} } ] },
handleTrailerButtonAction: { value: function(event) {
...}
}handleAction
handleEvent
Owner EventHandling
MethodPrecedence
Mop it!
Modular Applications
Encapsulated Components
HTML5 Templates
Scale Larger Team/Projects
Shorter Development Time
Easier to Refactor
Q&A