1. Get started
2. Dependency Injection
3. Routing
4. Databinding
5. Composition
6. Eventing
Programme
• Aurelia is a next gen JavaScript client framework that leverage the technology of the future but target today's mobile, desktop and browser environments.
Aurelia
http://aurelia.io/
• use JSPM and SystemJS
• Written with ES6 and ES7
• Integrates with Web Components
• Designed for Evergreen Browsers as Chrome, Firefox, IE11 and Safari 8.
• (Soon IE9 and above)
Install dependencies
Install Gulp npm install -g gulp
Install JSPM npm install -g jspm
Install Yeoman generator npm install -g yo generator-aurelia
Generate Aurelia application yo aurelia
Loading appBootstrapping <!-- index.html --> <!doctype html> <html> ... <body aurelia-app=“main”> ... <script src="jspm_packages/system.js"></script> <script src="config.js"></script> <script> System.import('aurelia-bootstrapper'); </script> </body> </html>
// src/main.js export function configure(aurelia) { aurelia.use .standardConfiguration() .developmentLogging();
aurelia.start().then(a => a.setRoot()); }
Views & viewmodelsTo create a viewmodel, edit an JS file that export a class // app.js export class App { firstName = 'John'; lastName = 'Doe';
@computedFrom('firstName', ‘lastName') get fullName(){ return `${this.firstName} ${this.lastName}`; } submit(){ alert(`Welcome, ${this.fullName}!`); } }
To create a view, edit an HTML file with an HTMLTemplate inside <!-- app.html --> <template> <input type="text" value.bind="firstName"> <input type="text" value.bind="lastName"> <p>${fullName}</p> <input type="submit" click.trigger="submit()">Submit</button> </template>
Dependency InjectionInject services to constructor import {inject} from 'aurelia-framework'; import {HttpClient} from 'aurelia-fetch-client';
@inject(HttpClient) export class MyViewModel { constructor(http) { this.http = http; } }
DI container assumes that everything is a singleton instance. To provide new instances, use transient decorator import {transient} from 'aurelia-framework';
@transient() export class MyViewMdel { ... }
Dependency InjectionLazy.of import {Lazy, inject} from 'aurelia-framework'; import {HttpClient} from 'aurelia-fetch-client';
@inject(Lazy.of(HttpClient)) export class MyViewModel { constructor(getHttp) { this.getHttp = getHttp; } }
All.of import {All, inject} from 'aurelia-framework'; import {Message} from ‘my-messages-class‘;
@inject(All.of(Message)) export class MyViewModel { constructor(messages) { this.messages = messages; } }
Optional.of import {Optional, inject} from 'aurelia-framework'; import {HttpClient} from 'aurelia-fetch-client';
@inject(Optional.of(HttpClient)) export class MyViewModel { constructor(http) { this.http = http; } }
Configure routes
export class MyViewModel { configureRouter(config, router){ this.router = router;
config.title = 'Router'; config.map([ // Static routes - Matches the string exactly. { route: ['', 'home'], name: 'home', moduleId: 'home/index' }, { route: 'users', name: 'users', moduleId: 'users/index'}, // Parameterized routes - Matches the string and then parses an id // parameter. Your view-model's activate callback will be called with an // object that has an id property set to the value that was extracted // from the url. { route: 'users/:id', name: 'user', moduleId: 'users/detail' }, // Wildcard routes - Matches the string and then anything that follows // it. Your view-model's activate callback will be called with an object // that has a path property set to the wildcard's value { route: 'files*path', name: 'files', moduleId: 'files/index'} ]); } }
Navigation// app.js export class App { configureRouter(config, router){ this.router = router;
config.title = 'Router'; config.map([ { route: 'home', name: 'home', moduleId: 'home/index', nav: true }, { route: 'users', name: 'users', moduleId: 'users/index', nav: true }, { route: 'users/:id', name: 'user', moduleId: 'users/detail' } ]); } }
<!-- app.html --> <template> <div class=“spinner" show.bind="router.isNavigating"></div> <ul> <li repeat.for="item of router.navigation"> <a href.bind="item.href">${item.title}</a> </li> </ul>
<router-view></router-view> </template>
Intercept navigationexport class MyViewModel { configureRouter(config) { config.title = 'Aurelia'; config.addPipelineStep('authorize', AuthorizeStep); config.map([ { route:'home', name: 'home', moduleId: 'home/index', nav: true }, { route:'users', name: 'users', moduleId: 'users/index', nav: true }, { route:'users/:id', name: 'user', moduleId: 'users/detail' } ]); } }
class AuthorizeStep { run(routingContext, next) { // some logic return next.cancel(new Redirect('login')); // or return next(); } }
Multiple viewports
export class EditorViewModel { configureRouter(config) { config.map([ { route: 'edit', viewPorts: { left: { moduleId: 'editor' }, right: { moduleId: 'preview' } } } ]); } }
<template> <div class="left-side"> <router-view name="left"></router-view> </div> <div class="right-side"> <router-view name="right"></router-view> </div> </template>
ActivationActivation Lifecycle
export class MyViewModel { canActivate(params, routeConfig, navigationInstruction) { // some logic return true; // false or Promise or navigation command } activate(params, routeConfig, navigationInstruction) { // some logic return true; // false or Promise } canDeactivate() { // some logic return true; // false or Promise or navigation command } deactivate() { // some logic return true; // false or Promise } }
CompositionComposition Lifecycle export class MyViewModel { bind(bindingContext) { // some logic } unbind() { // some logic } attached() { // some logic } detached() { // some logic } }
Demo Githoubhttps://github.com/aradjdi/AureliaGithoub
git checkout step-1
CommandsBind, one-way, two-way & one-time <template> <input type.one-time="inputType" name.one-way="inputName" value.two-way="inputValue">
</template>
Default binding behaviour is one-way binding for everything except form controls which is two-way binding. The example bellow is equivalent : <template> <input type.one-time="inputType" name.bind="inputName" value.bind=“inputValue">
</template>
Delegate, trigger & call <template> <form submit.delegate="submit($event)"> <button type="submit">Submit</button> </form> </template>
Templating attributesShow - Changes visibility of Element<template> <div show.bind="isSaving" class="spinner"></div> </template>
If - Add or remove the Element <template> <div if.bind="isSaving" class="spinner"></div> </template>
Repeat - Render a template multiple times <template> <ul> <li repeat.for="item of items">${item.content}</li> </ul> </template>
Expression, variable, converterString interpolation - ${expression} <template> <div class="dot ${color} ${isHappy ? 'green' : 'red'}"></div>
</template>
Value Converter - [expression] | [converterName]:[parameterExpression] <template> <title>${title | upper}</title> <input type="text" value.bind="fullName | upper">
</template>
Expression, variable, converterRef - create a local name for an element
• element.ref="someIdentifier" - Create a reference to the HTMLElement in the DOM.
• attribute-name.ref="someIdentifier"- Create a reference to a custom attribute's view-model.
• view-model.ref="someIdentifier"- Create a reference to a custom element's view-model.
• view.ref="someIdentifier"- Create a reference to a custom element's view instance (not an HTML Element).
• controller.ref="someIdentifier"- Create a reference to a custom element's controller instance.
<template> <input type="file" element.ref=“image"> <!-- use image without adding as attribute in viewmodel --> <img src.bind="image.value"/>
</template>
Others attributesAnd many others :
• value • model • checked • style • css • innerhtml • textcontent • … • create custom attribute also
Two-way data-binding is supported with contenteditable elements :
<template> <div textcontent.bind="contentString" contenteditable="true"></div> </template>
Binding computed propertiesSimple property > Object.observe > emulating Object.observe
Computed properties > Dirty checkin
To prevent Dirty checking import {computedFrom} from 'aurelia-framework';
export class Welcome{ firstName = 'John'; lastName = 'Doe';
@computedFrom('firstName', 'lastName') get fullName(){ return `${this.firstName} ${this.lastName}`; } }
ViewsCompose a view or a viewmodel <template> <compose view-model.bind="viewmodelName"></compose> </template>
<template> <compose view.bind="viewName"></compose> </template>
Aurelia can dynamically load components or per-view style sheets <template> <require from=“styles.css”></require> … </template>
Custom ElementCustom Elements add new tags to your HTML markup. // hello-world.js import {customElement, bindable} from 'aurelia-framework';
@customElement(‘hello-world') export class HelloWorld { @bindable to;
sayHello(){ alert(`Hello ${this.to}!`); } }
<!-- hello-world.html --> <template> <button click.trigger="sayHello()">Say Hello To ${to}</button> </template>
<!-- welcome.html --> <template> <require from=“hello-world”></require>
<input type="text" ref="name"> <hello-world to.bind=“name.value"></hello-world> </template>
Custom ElementCustom Elements as template. <!-- hello-world.html --> <template bindable="to"> <div>Hello ${to}</div> </template>
<!-- welcome.html --> <template> <require from=“hello-world.html”></require>
<input type="text" ref="name"> <hello-world to.bind=“name.value"></hello-world> </template>
Custom ElementCustom Elements without view // hello-world.js import {customElement, noView, bindable} from 'aurelia-framework';
@customElement(‘hello-world’) @noView() export class HelloWorld { @bindable to;
toChanged(newValue, oldValue) { alert(`Hello ${this.to}!`); } }
<!-- welcome.html --> <template> <require from=“hello-world”></require>
<input type="text" ref="name"> <hello-world to.bind=“name.value"></hello-world> </template>
Custom Element Decorator
• @useView(path) • @useShadowDom() • @inlineView(markup, dependencies?) • @containerless() • @children(selector) • @child(selector) • @processContent(false|Function) • … • create custom decorator also
Creating Decorator :
…
Demo Githoubhttps://github.com/aradjdi/AureliaGithoub
git checkout step-2
Killer featureRecursive Elements <!-- tree.html --> <template bindable="nodes"> <require from=“node”></require>
<ul> <li repeat.for="node of nodes”> <node if.bind=“node.isLeaf" content.bind=“node.value"></node> <tree if.bind=“node.isTree" nodes.bind=“node.nodes”></tree> </li> <ul>
</template>
Demo Githoubhttps://github.com/aradjdi/AureliaGithoub
git checkout step-3
EventAggregatorPublishing on a channel - Subscribing to a channel // a-publisher.js import {inject} from 'aurelia-framework'; import {EventAggregator} from 'aurelia-event-aggregator';
@inject(EventAggregator) export class APublisher { constructor(eventAggregator) { this.eventAggregator = eventAggregator; }
publish(){ this.eventAggregator.publish('channel name here', data); } }
// b-subscriber.js import {inject} from 'aurelia-framework'; import {EventAggregator} from 'aurelia-event-aggregator';
@inject(EventAggregator) export class BSubscriber { subscription; constructor(eventAggregator) { this.eventAggregator = eventAggregator; }
unsubscribe() { this.subscription.dispose(); } subscribe() { this.subscription = this.eventAggregator.subscribe(‚Àòchannel name here', payload => {...}); } }
Event AggregatorPublishing on a message - Subscribing to a message //some-massage.js export class SomeMessage{ }
//a-publisher.js import {inject} from 'aurelia-framework'; import {EventAggregator} from 'aurelia-event-aggregator'; import {SomeMessage} from './some-message';
@inject(EventAggregator) export class APublisher { constructor(eventAggregator) { this.eventAggregator = eventAggregator; }
publish() { this.eventAggregator.publish(new SomeMessage()); } }
//b-subscriber.js import {inject} from 'aurelia-framework'; import {EventAggregator} from 'aurelia-event-aggregator'; import {SomeMessage} from './some-message';
@inject(EventAggregator) export class BSubscriber { subscription; constructor(eventAggregator) { this.eventAggregator = eventAggregator; }
unsubscribe(){ this.subscription.dispose(); } subscribe(){ this.subscription = this.eventAggregator.subscribe(SomeMessage, message => {...}); } }
Demo Githoubhttps://github.com/aradjdi/AureliaGithoub
git checkout step-4
Conclusion
• aurelia-animate
• aurelia-animator-velocity
• aurelia-flux
• aurelia-validation
• aurelia-breeze