Aurelia intro

45
Intro to Aurelia 4.11.2015 @ Tartu Ats Uiboupin

Transcript of Aurelia intro

Intro to

Aurelia

4.11.2015 @ Tartu

Ats Uiboupin

Warning & credentials

Slides are mostly based on:

–Aurelia documentation

Slides are packed with text

–Meant forrecalling the presentation

people not attending the presentation

–You might not want to read the slides if You are listening

Agenda

Past, Present & Future

Aurelia: project, design, features

Concepts

How to get started

Using Aurelia with TypeScript

Binding, View/Element lifecycle

Conclusion

Bonus slides (can't fit into presentation timeframe)

Past, Present & FuturePast– HTML4, XHTML

– ES3 (ECMAScript3) - JavaScript that works "everywhere"

– Flash, Applets, Silverlight, … - deprecated, somewhat working with plugins

Present

– HTML5

– ES5 - native support in "evergreen browsers": IE10, FF, Chrome

– ES6(aka ES2015), ES7(aka ES2016) - limited native supportcan be used with transpilers to compile them to ES5 or ES3)

fun fact - guess what browser has the most support for ES6?

– TypeScript - using transpier to compile it to ES6, ES5 or ES3

Future

– HTML + Web Components

– native support forES6 and when standardized, then ES7, …

WebAssembly (aka wasm)

Web Components (proposal)

Templates - used to clone html and place it into DOM after modifications– content is hidden, scripts, images, audio not evaluated until clone is placet into DOM

even document.getElementById() won't find content from template

Custom Elements - create your own custom HTML elements with– HTML Templates, JS, CSS

– example: <my-date-picker min-date="today" max-date="1.1.2111">

Shadow DOM - isolation for CSS, element id's, DOM access through JS from surrounding document (see visualizer)

HtmlImports (probably removed from the proposal) - importing otherhtmls

Aurelia project

Basically next-generation of Durandal (SPA web framework)

WebSite: aurelia.io

Open source (MIT License): github.com/aurelia

Maintainer:– Durandal Inc

– Rob Eisenberg (former AngularJS core dev, previously Durandal framework)+ 14 core members + lots of contributors

Browser support: IE9, Safari 8, Evergreen browsers

Chat (quite responsive, lots of active users): gitter.im/Aurelia/Discuss

Aurelia design

Simple, powerful programming model

Modular framework architecturelots of small modules

can be replaced, extended with plugins

Forward thinking, future standards– written in ES2016 (aka ES7), transpiled to ES5

– polyfills for missing/future technologies

– convention over configurationbut configurable and even conventions can be replaced with your own conventions

– tries to use Web Components proposal, with exceptions:Custom Elements - NOT implemented exactly based on the prosal– to be able to use DI - hopefully proposal will be changed

HtmlImports - not used by default (probably removed from draft, won't be standardized)

Aurelia features…

– HTML extensions (custom elements, custom attributes for behavior, template controllers)

– WebComponents approach, including actual WebComponents support

– Adaptive data binding (including 2-way, 1-way, 1-time and several effectivestrategies)

integrates well with other frameworks, such as ReactJS, Backbone, Knockout, Breeze, …

– Simple conventions (but configurable and even replaceable)

– No boilerplate for metadata (ES7 decorators ~ annotations in Java)

– Dependency Injection (Views, Custom Elements, Attached Behaviors, singletons, …)

…Aurelia features

– HTML extensions (custom elements, custom attributes for behavior, template controllers)

– WebComponents approach, including actual WebComponents support

– Adaptive data binding (including 2-way, 1-way, 1-time and several effectivestrategies)

integrates well with other frameworks, such as ReactJS, Backbone, Knockout, Breeze, …

– Simple conventions (but configurable and even replaceable)

– No boilerplate for metadata (ES7 decorators ~ annotations in Java)

Status of the project

Fully featured, Rapid adoption & Large Active Community

~24/7 chat for free support from core team and community

January 26th - Early preview: Introducing Aurelia (some companiesalready had adopted it)

June 2015 - I started using it (pre alpha)

Nov 2015 - beta (should be available in first half)– Q: “I am just wondering if Aurelia is ideal to use for production now?”

– A: “Officially the stance is currently no, but anyone in the community will tell you that Aurelia has been ideal to use in production for a while now. The beta is right around the corner, so honestly, go nuts.”

FutureBeta release

Performance Optimizations

Improvements for TypeScript declarations– Generated based on code with babel (ES6 with type metadata)

– Some modules are great, some have no type metadata

Interactive documentation (see example)

Use Aurelia components as standard Web Components for use without Aurelia

Platform Abstraction Layer will enable to develop solutions for:– view pre-compilation

– server-side rendering

– browser-less testing

– isomorphic application (e.g. can be rendered either in NodeJS or in browser)

Aurelia vs AngularJS

Custom element/attribute vs Directive

ValueConverter (bidirectional) vs Filter (model to view)

Aurelia has no $rootScope, parent scope is rarely used (for example in repeater) - scope is passed to the child directly (as much) asneeded/reasonable or injected

no need for $scope.apply()

dirty-check is last resort (can be avoided, but used when nothing better can'tbe used)

attributes: value.bind vs ng-value - Aurelia uses standard html element attributes (no special support or documentation needed)

See 1:1 comparison between Aurelia and Angular2

Aurelia concepts

model - JS view-model - simple JS class (with optional Aurelia lifecyclemethods)

view - html file with (optional) binding expressions

Code organized into:– Views - Pages with urls (HTML + JS)

– Custom Elements - html elements as reusable components (HTML+JS)

– Custom Attributes - html attributes as reusable components (JS)Template Controllers (e.g. if, repeat)

Lifecycle methods– called by Aurelia, e.g. when page is created, (de)activated

Getting started with Aurelia application

Let's investigate "GET STARTED" guide

• kickstart with official sample project (skeleton-navigation)

• prepare env:

• install Node.js

• `npm install -g gulp && npm install -g jspm && npm install && jspm install -y`

• start the app: `gulp watch`

Binding - conceptsEffective data binding engine (uses micro task ueue, not dirty checking or virtual DOM)

(View to model) binding methods:

one-way - from model to html (default for all attributes, except `value` of formelement)

two-way - from model to html and html to model

one-time - from model to html (only once)

Best default binding method chosen automatically when using `.bind`:

• form inputs: two-way

• everything else: one-way

Binding expressions

expression can be– field `firstName` (or `person.firstName`)

– getter `fullName`NB! use aurelia-computed or @computedFrom

– function call: `getFullName()` - NB! evaluated only once!

– complex expression: `firstName + " " + lastName`

inside html textcontent or plain html attribute:– ${someExpression}

<span class="msg-${msgType}">

<span>Hello ${name}</span>

as attribute on html element:– .bind=”someExpression” (`one-time`, `one-way` can be used instead of `bind`)

for example: `value.bind=”firstName”` or `textcontent.bind=”firstName”`)

Binding expressions - more samples

Instead of `.bind` You can use `.one-time` and `.one-way` when needed

Configuration conventions

Suffix of class name determines component type:

– …CustomAttribute vs @customAttribute('foo-bar')

– …CustomElement vs @customElement('foo-bar')

View (hml file) location based on ViewModel

Custom elements

Reusable components

<my-custom-element some-input.bind=”fullName” />

Can take dependencies through DI

– Only ancestor Custom Element can be injected to the child, MUST NOT BE INJECTED ELSEWHERE - use composition instead of injecting it directly

source of confusion, as Custom Elements are “prototype scoped beans”

– You’ll get new instance every time it is injected

– You can’t get an instance(s) You’ve used in html

SAMPLE: 1) html-only: <nav-bar>

Custom element - sample 2 (html + JS)

Usage:

Component

– say-hello.html:

– say-hello.js

Content selectors for Custom ElementsUsed in templates of custom elements to place content from custom element body tospecific location of custom element template:

Usage:

in modal.html:

ShadowDOM syntax (with CSS selectors),

could also use <content /> to select all to same location

Custom Attributes

View Lifecycle methods (IoC)

(Acceptable method return types are on line starting with ":")

canActivate(params, routeConfig, navigationInstruction)

– : boolean | Promise<boolean>

– to control if view-model can be navigated to.

activate(params, routeConfig, navigationInstruction)

– : void | Promise

– custom logic right before view-model is displayed (fetch data over http). After promise is resolved router binds and attaches the view.

canDeactivate()

– : boolean | Promise<boolean> | {navigate(router: Router)}

– can router navigate to another route.

deactivate()

– : void | Promise

– when your view-model is being navigated away from

Custom Element/Attribute Lifecycle methods

Construction– created(view:View)

when view and view-model have been created. Allows your behavior to have direct access to the View instance.

– bind(bindingContext:any)when the databinding engine binds the view. The binding context is the instance that the view is databound to.

– attached() - when the view that contains the extension is attached to the DOM.

Destruction:

– detached() - when the view that contains the extension is detached from the DOM.

– unbind() - when the databinding engine unbinds the view.

Aurelia-computed

automates dependency identification for getters

Removes need to add @computedFrom(...) for simple cases

– NB! adding `console.log(...)` will make it give up (fallback to dirty-checking)

supports more complex scenarios such as observing property paths (“owner.firstName”)

– @computedFrom will be improved to support it as well

ValueConverters - see also interactive doc

Import: either globally or with– No need to import when valueconverter is defined in the same file with view

Usage:

Event Aggregator

To loosely couple application components

Subscribe for an event:

or

Publish event:

or

<compose> element

Enables you to dynamically render UI into the DOM.

Basically dynamic custom element with content created based on:

• view-model (optional)

• model (optional)

• view (optional)

See the documentation for more information

Conclusion: Pros

Great project (easy to learn and use)

Minimal amount of framework and configuration code

Intuitive: don't need much documentation to code– understand basics, look up lifecycle hooks

Used a lot in real projects even months before beta release

Actively developed (with great speed and community)

Can use existing UI components created with standard Web Components

I probably had only 2 small issues with 5 months old Aurelia (foundworkaround, fixed now)

Conclusion: Cons

Has not reached version 1.0

Not so many OS UI componens

– compared to Angular 1, but easy to create Yourself

– but easy to use UI components created with standard Web Components

Documentation completeness (comming soon)

TypeScript support could be improved for some modules (moretype info to source code)

No IDE plugins (won't miss it much when using TypeScript)

The end (or start of the new era?)

Your comments, thoughts…

Bonus slides

Some more stuff that won't fit into presentation time frame

Advanced topics

– some not included in official documentation

Geeky implementation details

– You don't need to know them to code, but can be useful

Testing

See tests in official demo project: skeleton-navigation

Unit tests with Karma/Jasmine

E2E tests with Protactor

– written for Angular, works with Aurelia

trigger, delegate, call

trigger - event handler on single element (not very efficient)

delegate - efficient event handler

– or

call - pass custom event handler for custom element:

Router - dynamic route generation

Route generation:

in html: <a route-href="route: contacts; params.bind: {id:contact.id}"></a>

or

in JS: href = router.generate(routeName, params);

Bundling

Gulp plugin: aurelia-bundler

– even CSS and HTML can be bundled into same file with JS

if using default loader plugin (not HtmlImport template loader)

– multiple bundles can be created (login page, everything else)

Dependency Injection - different usagesLet's say, we want to inject 2 dependencies: HttpClient, Arg2Type

import all types to inject: `import {HttpClient} from 'aurelia-fetch-client'`

Depending on the language/transpiler capabilities:

With ES3 - `Decorators.inject(HttpClient, Arg2Type)`

With ES6 - add class field:`static inject = [HttpClient, Arg2Type]`

With ES7 - annotate class with `@inject(HttpClient, Arg2Type) `

With TypeScript (my preference, can't forget to inject after adding argument, same type info used by TS compiler and IDE autocomplete):– configure TypeScript compiler flag: `--emitDecoratorMetadata`

– annotate class with `@autoinject`

– add type info to constructor:

constructor(http: HttpClient, arg2: Arg2Type)

Dependency Injection - resolvers

DI container assumes that everything except Custom Elements/Attributes are a singletons (unless using @transient()).

Resolvers are useful, but rarely needed.

On class being injected:

@transient() - annotated type will be transient aka "prototype bean"

On injection target class (can be customized, combined - see OptionalParent)

Lazy.of(Type) - for example ` @inject(Lazy.of(HttpClient)) `

All.of(Plugin)

Optional.of(LoggedInUser)

Parent.of()

Binding with ref attribute

ref="someIdentifier" - create a reference to the HTMLElement in the DOM (added to view-model)

– can use in JS code (field with name given with ref attribute value)

– can use in html code (reference by name given with ref attribute value)

attribute-name.ref="someIdentifier"- create a reference to a custom attribute's class instance

element-name.ref="someIdentifier"- create a reference to a custom element's class instance

Adaptive Binding Strategies

Chosen based on browser features and object/prop type

DOM element?– getStrategy4DOM(elementType, attributeName)

Property with getter (defined using Object.defineProperty, such as `get fullName() {...}`)– Object.observe only supported on Chrome - so it won’t be used

– Dependencies declared (@computedFrom('firstName', 'lastName'))?

– Observable by some property observation adapter?

Standard object property– If Object.observe is used if supported (Chrome)

– Aurelia re-writes property using Object.defineProperty so assignments can be intercepted

Manually observing property changes (rarely needed)

Some annotationsOn class:

– @autoinject

– @containerless - remove <my-custom-element> wrapper from DOM

– @useView(path) - custom path to html file

– @noView - could be used to render with smth else, i.e. ReactJS

– @inlineView(markup, dependencies?) - provide view inline in js instead of html file

– @skipContentProcessing - could be used for documentation (or embedded Aurelia)

– @useShadowDOM - used to render view in ShadowDOM

– @bindable('isExpanded') - can also be used on field

On field

– @bindable - bind field to value passed in from the custom html element

– @syncChildren(property, changeHandler, selector) - array of decendants based on CSS selector

On function

– @computedFrom('firstName', 'lastName')

@templateController - Allows a custom attribute to turn the attributed HTML into an HTMLTemplate which it can then generate on the fly. This is how behaviors like if and repeat can be created.

@dynamicOptions - This allows a custom attribute to have a dynamic set of properties which are all mapped from the options attribute syntax into the class at runtime.

Bugs with 5 months old version

content of element with `show.bind` is shown even with null and undefined (fixed long ago, if.bind worked as expected)

Found second bug as well (can't remember exactly), but it wasn'tsignificant enough to need update to newer version

Aurelia core seems very solid

Plugins

I've used following plugins:

– aurelia-computed - to avoid dirty-checking or manually adding@computedFrom(..) to computed fields

– aurelia-validation - validate form inputs

– aurelia-i18n - internationalization

– aurelia-bs-modal - modal component

probably next time would consider aurelia-dialog