React
Polymer
Angular
Ember
Vue
Aurelia
A push for speed, reduction in bloat!
$.get('http://myResource/api/getThings')
.then(() => {})
.catch(console.error);
3.0 is A+ Promise Standard Compliant
Offers reasonable slim-version, plus pick your-own modules variable
Feel free to ignore this screenshot of patchnotes
Super useful for lightweight work
$(async () => {
const starterData = await $.get('a/resource');
$('#app .dataContainer').text(starterData);
});
"jQuery 3.0, if the browser supports it, uses requestAnimationFrame API to perform animations. The API uses GPU to perform animations. This method is powerful because it’s faster and smoother while performing animations, and on mobile devices, it’s a battery saver."- jQuery 3.0 Release Notes
"jQuery offers some custom selectors (like :visible and :hidden) that apparently look like a CSS selector, but are resolved by jQuery selector engine.
The developers found that with these selectors, some extra work can be skipped if used multiple times in the same document. After they optimized it in jQuery 3, the result is now ~17 times faster." - jQuery 3.0 Release Notes
Oldie but goodie
Simple API
<div data-bind="text: potato" />
ko.applyBindings({
potato: 'I am a binding!'
});
Easy Template Helpers
<div data-bind="foreach: things">
<span data-bind="if: showThing && $data % 2 === 0">
<div data-bind="text: 'Thing!: ' + $data" />
</span>
</div>
ko.applyBindings({
showThing: true,
things: ko.observableArray([1,2,3,4])
});
Reasonable Complexity Scale
var viewModelOne = {
some: ko.observable('data')
};
var viewModelTwo = {
some: ko.observable('other data')
};
window.addEventListener('hashchange', () => {
ko.cleanNode(window);
if(location.hash === '1')
ko.applyBindings(viewModelOne);
else if(location.hash === '2')
ko.applyBindings(viewModelTwo);
});
Unopinionated
var viewModelOne = function() {
this.core = 'core';
};
var viewModelTwo = {
core: 'core'
};
ko.applyBindings(
new viewModelOne()
);
ko.applyBindings(
viewModelTwo
);
<input
type="text"
data-bind="textInput: username" />
var viewModel = {
username: ko.observable('')
};
ko.applyBindings(viewModel);
Useful for small -> medium projects that require older browser support
Not a framework for ambitious web applications
Template Syntax is 'unique'
var TodoView = Backbone.View.extend({
template: _.template($('#item-template').html())
});
var Books = Backbone.Collection.extend({
url: '/books'
});
Designed around CRUD
var object = {};
_.extend(object, Backbone.Events);
object.on("alert", function(msg) {
alert("Triggered " + msg);
});
object.trigger("alert", "an event");
You leverage and extend Backbone objects
Does not abstract intuitively
They're keeping the Angular 1.x branding, and angularjs.com still takes you to the 1.x site.
class Greeter {
greeting: string;
constructor (message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<h2>My favorite hero is: {{myHero}}</h2>
`
})
export class AppComponent {
title = 'Tour of Heroes';
myHero = 'Windstorm';
}
ng serve --host 0.0.0.0 --port 4201
ng generate component my-new-component
ng g component my-new-component # using the alias
# components support relative path generation
# if in the directory src/app/feature/ and you run
ng g component new-cmp
# your component will be generated in src/app/feature/new-cmp
# but if you were to run
ng g component ../newer-cmp
# your component will be generated in src/app/newer-cmp
public description = 'DI';
constructor(public engine: Engine, public tires: Tires) { }
public engine: Engine;
public tires: Tires;
public description = 'No DI';
constructor() {
this.engine = new Engine();
this.tires = new Tires();
}
// Simple car with 4 cylinders and Flintstone tires.
let car = new Car(new Engine(), new Tires());
<p>{{myVar}}</p> //Good!
<button (click)="deleteHero()">Delete hero</button> //What?
//Weird
<button (click)="onSave($event)">Save</button>
<button *ngFor="let hero of heroes" (click)="deleteHero(hero)">{{hero.name}}</button>
<form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>
//Please stop
<!-- Bind button disabled state to `isUnchanged` property -->
<button [disabled]="isUnchanged">Save</button>
//No why
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>
//Component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'my-sizer',
template: `
<div>
<button (click)="dec()" title="smaller">-</button>
<button (click)="inc()" title="bigger">+</button>
<label [style.font-size.px]="size">FontSize: {{size}}px</label>
</div>`
})
export class SizerComponent {
@Input() size: number | string;
@Output() sizeChange = new EventEmitter<number>();
dec() { this.resize(-1); }
inc() { this.resize(+1); }
resize(delta: number) {
this.size = Math.min(40, Math.max(8, +this.size + delta));
this.sizeChange.emit(this.size);
}
}
//In Use
<my-sizer [(size)]="fontSizePx"></my-sizer> //Note the [()] syntax for 2-way binding
<div [style.font-size.px]="fontSizePx">Resizable Text</div>
// Define the class for a new element called custom-element
class CustomElement extends Polymer.Element {
static get is() { return "custom-element"; }
constructor() {
super();
this.textContent = "I'm a custom-element.";
}
}
// Register the new element with the browser
customElements.define(CustomElement.is, CustomElement);
<dom-module id="dom-element">
<template>
<p>I'm a DOM element. This is my local DOM!</p>
</template>
<script>
class DomElement extends Polymer.Element {
static get is() { return "dom-element"; }
}
customElements.define(DomElement.is, DomElement);
</script>
</dom-module>
Now I'm just Copy and Pasting
<dom-module id="picture-frame">
<template>
<!-- scoped CSS for this element -->
<style>
div {
display: inline-block;
background-color: #ccc;
border-radius: 8px;
padding: 4px;
}
</style>
<div>
<!-- any children are rendered here -->
<slot></slot>
</div>
</template>
<script>
class PictureFrame extends Polymer.Element {
static get is() { return "picture-frame"; }
}
customElements.define(PictureFrame.is, PictureFrame);
</script>
</dom-module>
I heard you like JSX...
Mustache-like syntax for variables in templates
<template>
<!-- bind to the "owner" property -->
This is <b>{{owner}}</b>'s name-tag element.
</template>
2-Way Binding... and more <template> tags
<link rel="import" href="https://polygit.org/polymer+2.0.0-rc.2/iron-input+polymerelements+:2.0-preview/shadycss+webcomponents+1.0.0-rc.2/components/iron-input/iron-input.html">
<template>
<iron-input bind-value="{{owner}}">
<input is="iron-input" placeholder="Your name here...">
</iron-input>
</template>
You have to import iron-input :/
npm install -g ember-cli@2.12
npm install -g bower
brew install watchman (OSX Only)
npm install -g phantomjs-prebuilt
Then...
ember new my-new-app
cd my-new-app
ember server
<p>
Hello,
<strong> {{firstName}} {{lastName}}</strong>!
</p>
import Ember from 'ember';
export default Ember.Controller.extend({
firstName: 'Trek',
lastName: 'Glowacki'
});
//route.js
export default Ember.Route.extend({
model(params) {
return this.store.findRecord('user', params.id);
}
});
//model.js
import DS from 'ember-data';
export default DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
articles: DS.hasMany(),
fullName: Ember.computed('firstName', 'lastName', function() {
return `${this.get('firstName')} ${this.get('lastName')}`;
}),
});
0.02 seconds faster than React
<script src="https://unpkg.com/vue"></script>
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
<div id="app">
<p>{{ message }}</p>
<input v-model="message">
</div>
var app6 = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
Optional
var data = { counter: 0 }
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// data is technically a function, so Vue won't
// complain, but we return the same object
// reference for each component instance
data: function () {
return data
}
})
new Vue({
el: '#example-2'
})
Kinda meh.
CLI?
Young.
Oh yeah, we had a talk on it!
export class Todo {
constructor(description) {
this.description = description;
this.done = false;
}
}
export class App {
constructor() {
this.heading = "Todos";
this.todos = [];
this.todoDescription = '';
}
addTodo() {
if (this.todoDescription) {
this.todos.push(new Todo(this.todoDescription));
this.todoDescription = '';
}
}
removeTodo(todo) {
let index = this.todos.indexOf(todo);
if (index !== -1) {
this.todos.splice(index, 1);
}
}
}
<template>
<h1>${heading}</h1>
<form submit.trigger="addTodo()">
<input type="text" value.bind="todoDescription">
<button type="submit">Add Todo</button>
</form>
<ul>
<li repeat.for="todo of todos">
<input type="checkbox" checked.bind="todo.done">
<span>
${todo.description}
</span>
<button click.trigger="removeTodo(todo)">
Remove
</button>
</li>
</ul>
</template>
Aurelia-specific dom event bindings
I stole this slide
Keep an eye out
Just install...
class App extends Component {
render() {
return (
<div>
<MyComponent />
</div>
);
}
}
No two-way binding at all!
Solutions?
"Weird License"
class Core extends Component {
render() {
return (
<div className='coreContainer'>
{this.props.children}
{
[1,2,3,4].map(i => <div key={i}>Counter: {i}</div>)
}
</div>
);
}
}
export default Core;
/krishnaglick on Github
@krishnaglick on Twitter
@prometheus on ODevs Slack