Lead Frontend Developer - Toumetis
http://slides.com/alex-jones/deck
npm install -g @angular/cli
ng new robot-army-management
Understand what Angular is and use cases
Develop a Robot Army Management (RAM) app
Be armed with what the next steps are
alert('INTRUDER');
A full feature, cross platform, performant, component based and developer focused framework.
https://www.madewithangular.com
Core.js
RXJS
Zones.js
Jasmine/Protractor
Typescript (ES6)
Webpack
Karma
Angular CLI
Tough learning curve
Fantastic tooling
Easy setup
Observables, steep learning but great
Typescript is π
Community/Tutorials
Angular vs React vs Elm vs Vue Interest Over the Last Year
https://trends.google.co.uk/trends/explore?cat=31&q=Angular,React,Elm,Vue
Β Most Wanted Frameworks, Libraries and Other TechnologiesΒ
https://insights.stackoverflow.com/survey/2017
Setup using the Angular CLI
Create robot component
Add inputs, outputs and bind some data
Add some styling
Fetch data from API
Hook up event handlers and emitters
npm install -g @angular/cli
ng new robot-army-management
cd robot-army-management
ng serve --open
RUN IN THE TERMINAL
src
βββ app
β βββ app.component.css
β βββ app.component.html
β βββ app.component.spec.ts
β βββ app.component.ts
β βββ app.module.ts
βββ assets
βββ environments
β βββ environment.prod.ts
β βββ environment.ts
βββ favicon.ico
βββ index.html
βββ main.ts
βββ polyfills.ts
βββ styles.css
βββ test.ts
βββ tsconfig.app.json
βββ tsconfig.spec.json
βββ typings.d.ts
ng generate component robot
PRETTY NEAT
src
βββ app
Β Β βββ app.component.css
Β Β βββ app.component.html
Β Β βββ app.component.spec.ts
Β Β βββ app.component.ts
Β Β βββ app.module.ts <---
Β Β βββ robot <---
Β Β βββ robot.component.css
Β Β βββ robot.component.html
Β Β βββ robot.component.spec.ts
Β Β βββ robot.component.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { RobotComponent } from './robot/robot.component';
@NgModule({
declarations: [
AppComponent,
RobotComponent <---
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-robot',
templateUrl: './robot.component.html',
styleUrls: ['./robot.component.css']
})
export class RobotComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
// robot.component.ts
import {Component, Input, OnInit} from '@angular/core';
@Component({
selector: 'app-robot',
templateUrl: './robot.component.html',
styleUrls: ['./robot.component.css']
})
export class RobotComponent implements OnInit {
@Input('details') details: {
name: string,
type: string,
active: boolean
};
constructor() {}
ngOnInit() {
}
}
<!--robot.component.html-->
<h2>
{{details.name}}
</h2>
<p>
{{details.type}}
</p>
<!--src/app/app.component.html-->
<app-robot [details]="{name: 'BEEP', type: 'attack-bot', active: true}"></app-robot>
WATCH OUT FOR THOSE ATTACK BOTS
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-robot',
templateUrl: './robot.component.html',
styleUrls: ['./robot.component.css']
})
export class RobotComponent implements OnInit {
@Input('details') details: {
name: string,
type: string,
active: boolean
};
baseImageUrl = 'https://robohash.org/';
constructor() { }
ngOnInit() {
}
}
<!--robot.component.html-->
<h2>
Name: {{details.name}}
</h2>
<p>
Type: {{details.type}}
</p>
<img [src]="baseImageUrl + details.name">
HEY, I RECOGNIZE HIM
<!--robot.component.html-->
<h2>
Name: {{details.name}}
</h2>
<p>
Type: {{details.type}}
</p>
<img [src]="baseImageUrl + details.name">
<p>
<label for="override">Name Override:</label>
<input type="text" id="override" [(ngModel)]="details.name">
</p>
WAIT ... IS THAT ME?
/*
src/app/robot/robot.component.css
*/
:host {
display: inline-block;
padding: 20px;
background-color: black;
color: white;
margin: 10px;
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
font-family: monospace;
}
ng g service robotics-centre
src
βββ app.component.css
βββ app.component.html
βββ app.component.spec.ts
βββ app.component.ts
βββ app.module.ts
βββ robot
βΒ Β βββ robot.component.css
βΒ Β βββ robot.component.html
βΒ Β βββ robot.component.spec.ts
βΒ Β βββ robot.component.ts
βββ robotics-centre.service.spec.ts
βββ robotics-centre.service.ts
import { Injectable } from '@angular/core';
@Injectable()
export class RoboticsCentreService {
constructor() { }
}
// src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { RobotComponent } from './robot/robot.component';
import { RoboticsCentreService } from './robotics-centre.service';
@NgModule({
declarations: [
AppComponent,
RobotComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [RoboticsCentreService], <---
bootstrap: [AppComponent]
})
export class AppModule { }
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class RoboticsCentreService {
constructor(private http: Http) { }
getRobotMood() {
const url = 'https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h';
return this.http.get(url)
.map(res => res.text());
}
}
import { Component, Input, OnInit } from '@angular/core';
import { RoboticsCentreService } from '../robotics-centre.service';
@Component({
selector: 'app-robot',
templateUrl: './robot.component.html',
styleUrls: ['./robot.component.css']
})
export class RobotComponent implements OnInit {
@Input('details') details: {
name: string,
type: string,
active: boolean,
mood?: string
};
baseImageUrl = 'https://robohash.org/';
constructor(private roboticsCentre: RoboticsCentreService) { }
ngOnInit() {
this.roboticsCentre.getRobotMood()
.subscribe(mood => this.details.mood = mood);
}
}
<!--robot.component.html-->
<h2>
Name: {{details.name}}
</h2>
<p>
Type: {{details.type}}
</p>
<p>
Mood: {{details.mood}}
</p>
<img [src]="baseImageUrl + details.name">
<p>
<label for="override">Name Override:</label>
<input type="text" id="override" [(ngModel)]="details.name">
</p>
LOOKING GOOD!
// src/app/app.component
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
robots = [
{name: 'JoBloop', type: 'loving-friend', active: true},
{name: 'FS4Dv', type: 'chatty', active: true},
{name: 'Bruce', type: 'attack-bot', active: false},
{name: 'DAS@423', type: 'cat-loving', active: true}
];
}
<!--src/app/app.component.html-->
<app-robot *ngFor="let robot of robots" [details]="robot"></app-robot>
<!--robot.component.html-->
<div class="active" *ngIf="details.active"></div>
<h2>
Name: {{details.name}}
</h2>
<p>
Type: {{details.type}}
</p>
<p>
Mood: {{details.mood}}
</p>
<img [src]="baseImageUrl + details.name">
<p>
<label for="override">Name Override:</label>
<input type="text" id="override" [(ngModel)]="details.name">
</p>
/*
src/app/robot/robot.component.css
*/
:host {
display: inline-block;
padding: 20px;
background-color: black;
color: white;
margin: 10px;
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
font-family: monospace;
width: 20%;
}
.active {
height: 10px;
width: 10px;
border-radius: 6px;
background-color: green;
float: right;
border: 1px #CCC solid
}
<!--robot.component.html-->
<div class="active" *ngIf="details.active"></div>
<h2>
Name: {{details.name}}
</h2>
<p>
Type: {{details.type}}
</p>
<p>
Mood: {{details.mood}}
</p>
<img [src]="baseImageUrl + details.name">
<p>
<label for="override">Name Override:</label>
<input type="text" id="override" [(ngModel)]="details.name">
</p>
<button (click)="deactive()">Deactivate</button>
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { RoboticsCentreService } from '../robotics-centre.service';
@Component({
selector: 'app-robot',
templateUrl: './robot.component.html',
styleUrls: ['./robot.component.css']
})
export class RobotComponent implements OnInit {
@Input('details') details: {
name: string,
type: string,
active: boolean,
mood?: string
};
@Output() deactiveEmitter = new EventEmitter();
baseImageUrl = 'https://robohash.org/';
constructor(private roboticsCentre: RoboticsCentreService) { }
ngOnInit() {
this.roboticsCentre.getRobotMood()
.subscribe(mood => this.details.mood = mood);
}
deactive() {
this.deactiveEmitter.emit('KILL');
}
}
<!--src/app/app.component.html-->
<app-robot *ngFor="let robot of robots; let idx = index" [details]="robot"
(deactiveEmitter)="robots.splice(idx, 1)">
FIN
Used Angular CLI
Created component
Hooked up app module
Input, output, event handlers, event emitter
Template directives
Connecting to APIs (observables)
Single/Two way data binding
Styled app
Routing
Animation
Pipes
Async as pipe
Lazy loading modules
Directives
Typescript
Observables