Angular For Java
Angular For Java
Developers
Yakov Fain, Farata Systems
March 10, 2016
Angular 2
Component-based
Better performance
No controllers, scopes
Integrated RxJS
HTML
HTML
A TypeScript class
Importing
modules
Class annotations
Project Structure
App code
App dependencies
Config files
Project Structure
SystemJS
transpiles
TS and
loads JS
bootstrap(ApplicationComponent)
Project Structure
bootstrap(ApplicationComponent)
HomeComponent
import
import
import
import
import
@Component({
selector: 'auction-home-page',
directives: [
CarouselComponent,
ProductItemComponent
],
styleUrls: ['app/components/home/home.css'],
template: `
<div class="row carousel-holder">
<div class="col-md-12">
<auction-carousel></auction-carousel>
</div>
</div>
<div class="row">
<div *ngFor="#product of products" class="col-sm-4 col-lg-4 col
<auction-product-item [product]="product"></auction-product-i
</div>
</div>
`
})
export default class HomeComponent {
products: Product[] = [];
Importing
Modules
Exporing a
module
HomeComponent
import
import
import
import
import
Dependency
Injection
@Component({
selector: 'auction-home-page',
directives: [
CarouselComponent,
ProductItemComponent
],
styleUrls: ['app/components/home/home.css'],
template: `
<div class="row carousel-holder">
<div class="col-md-12">
<auction-carousel></auction-carousel>
</div>
</div>
<div class="row">
<div *ngFor="#product of products" class="col-sm-4 col-lg-4 col
<auction-product-item [product]="product"></auction-product-i
</div>
</div>
`
})
export default class HomeComponent {
products: Product[] = [];
@Component({
selector: 'auction-home-page',
directives: [
CarouselComponent,
ProductItemComponent
],
styleUrls: ['app/components/home/home.css'],
template: `
<div class="row carousel-holder">
<div class="col-md-12">
<auction-carousel></auction-carousel>
</div>
</div>
<div class="row">
<div *ngFor="#product of products" class="col-sm-4 col-lg-4 col
<auction-product-item [product]="product"></auction-product-i
</div>
</div>
`
})
export default class HomeComponent {
products: Product[] = [];
A Sample Toolbox
Intro to TypeScript
http://www.typescriptlang.org
Whats TypeScript?
A superset of JavaScript
TypeScript
JavaScript (E5)
Classes
TypeScript
JavaScript (E5)
JavaScript (E5)
Inheritance
Classical syntax
Prototypal
Generics
Error
No Errors
tsc -w *.ts
HelloWorldComponent in Angular
import {bootstrap} from 'angular2/platform/browser';
import {Component} from 'angular2/core';
@Component({
selector: 'hello-world',
template: '<h1>Hello {{ name }}!</h1>'
})
class HelloWorldComponent {
name: string;
constructor() {
this.name = World!';
}
}
bootstrap(HelloWorldComponent);
In HTML:
<hello-world></hello-world>
Index.html Take 1
<!DOCTYPE html>
<html>
<head>
<script src="//npmcdn.com/[email protected]/bundles/angular2-polyfills.js"></script>
<script src="//npmcdn.com/[email protected]/lib/typescript.js"></script>
<script src="//npmcdn.com/[email protected]/dist/system.src.js"></script>
<script src="//npmcdn.com/[email protected]/bundles/Rx.js"></script>
<script src="//npmcdn.com/[email protected]/bundles/angular2.dev.js"></script>
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: {emitDecoratorMetadata: true}
});
System.import('main.ts');
</script>
SystemJS
</head>
<body>
<hello-world></hello-world>
</body>
</html>
HelloWorldComponent
package.json
{
"name": "walkthrough5",
"version": "1.0.0",
"description": A sample package.json for the Angular app,
"scripts": {
"start": "live-server"
},
"dependencies": {
"es6-shim": "0.33.13",
"es6-promise": "^3.0.2",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.2",
"systemjs": "0.19.23",
"zone.js": "0.5.15",
"angular2": "2.0.0-beta.9"
},
"devDependencies": {
"live-server": "^0.9.0",
"typescript": "^1.7.5"
}
}
Index.html Take 2
<!DOCTYPE html>
Angulars local (after npm install)
<html>
<head>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/typescript/lib/typescript.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: {emitDecoratorMetadata: true}
});
System.import('main.ts');
</script>
</head>
<body>
<hello-world></hello-world>
</body>
</html>
Templates
Angular team works with Telerik on rendering for iOS and Android using NativeScript
@Component({
selector: 'auction-home-page',
styleUrls: ['app/components/home/home.css'],
template: `
<div class="row carousel-holder">
<div class="col-md-12">
<auction-carousel></auction-carousel>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<input placeholder="Filter products by title type="text">
</div>
</div>
</div>
`
})
Unidirectional Binding
From code to template:
<h1>Hello {{ name }}!</h1>
<span [hidden]=isZipcodeValid>Zip code is not valid</span>
Two-way Binding
Synchronizing Model and View:
<input [value]="myComponentProperty"
(input)=onInputEvent($event)>
Dependency Injection
product-service.ts
Injecting ProductService
import {Component, bind} from 'angular2/core';
import {ProductService, Product} from "../services/product-service";
@Component({
selector: 'di-product-page',
template: `<div>
<h1>Product Details</h1>
<h2>Title: {{product.title}}</h2>
<h2>Description: {{product.description}}</h2>
<h2>Price: \${{product.price}}</h2>
</div>`,
A provider can be a
providers:[ProductService]
class, factory, or a value
})
Injection
this.product = productService.getProduct();
Basic Routing
@Component({
selector: basic-routing',
@RouteConfig([
{path: '/',
component: HomeComponent, as: 'Home'},
{path: '/product', component: ProductDetailComponent, as: 'ProductDetail'}
])
class RootComponent{
}
@Component({
selector: 'basic-routing',
template: `<a [routerLink]="['/Home']">Home</a>
<a [routerLink]="['/ProductDetail',
{id:1234}]">Product Details</a>
<router-outlet></router-outlet>`,
directives: [ ROUTER_DIRECTIVES]
})
@RouteConfig([
{path: '/',
component: HomeComponent, as: 'Home'},
])
class RootComponent{}
bootstrap(RootComponent, [ROUTER_PROVIDERS,
provide(LocationStrategy, {useClass: HashLocationStrategy})]);
constructor(params: RouteParams){
2
}
this.productID = params.get('id');
}
Reactive Programming
Stream samples:
- UI events
- HTTP responses
- Data arriving over websockets
Observable Streams
An observable stream can:
Throw an error
Observers
An observer provides:
Error handling
End-of-stream handling
Observables vs Promises
Observable Events
@Component({
selector: "app",
template: `
<h2>Observable events demo</h2>
<input type="text" placeholder="Enter stock" [ngFormControl]="searchInput">
`
})
class AppComponent {
searchInput: Control;
constructor(){
this.searchInput = new Control('');
Observable
this.searchInput.valueChanges
.debounceTime(500)
.subscribe(stock => this.getStockQuoteFromServer(stock));
}
getStockQuoteFromServer(stock) {
class AppComponent {
DI
this.http.get(http://localhost:8080/products')
.map(res => res.json())
.subscribe(
data => {
O
b
s
e
r
v
e
r
this.products=data;
},
err =>
console.log("Can't get products. Error code: %s, URL: %s ",
err.status, err.url),
() => console.log('Product(s) are retrieved')
);
}
}
Deployment
The app
index.html
Frameworks
webpack.config.js
module.exports = {
debug: false,
devtool: 'source-map',
entry: {
'main' : './src/main.ts',
'vendor': './src/vendor.ts'
},
metadata: metadata,
module: {
loaders: [
{test: /\.css$/, loader: 'to-string!css'},
{test: /\.html$/, loader: 'raw'},
{test: /\.ts$/,
loader: 'ts'}
],
noParse: [path.join(__dirname, 'node_modules', 'angular2', 'bundles')]
},
output: {
path
: './dist',
filename: 'bundle.js'
},
plugins: [
new CommonsChunkPlugin({name: 'vendor', filename: 'vendor.bundle.js', minChunks: Infinity}),
new CompressionPlugin({regExp: /\.css$|\.html$|\.js$|\.map$/, threshold: 1500}),
new CopyWebpackPlugin([{from: './src/index.html', to: 'index.html'}]),
new DedupePlugin(),
new DefinePlugin({'webpack': {'ENV': JSON.stringify(metadata.ENV)}}),
new OccurenceOrderPlugin(true),
new UglifyJsPlugin({
compress : {screw_ie8 : true},
mangle: {
screw_ie8 : true,
except: ['RouterLink'] // TODO: Remove after #6678 fixed
}
})
],
resolve: {
extensions: ['', '.ts', '.js']
}
npm start
or
Links
Blog: yakovfain.com