From Zero to Hero

 

Get ready folks!

@kokkisajee

In a nutshell

Communities

Social Developer

Recognitions

Cloud Solution Architect @Microsoft

Full-stack developer

 

I'm Sajeetharan Sinnathurai

www.sajeetharan.com

THE CHALLENGE

Create a scalable APP with Angular from scratch

Once upon a time...

Then

Now

Why Angular?

"HEROES DON'T ALWAYS WEAR CAPES

SOMETIMES THEY CODE ANGULAR"

Angular as a Framework

 

  •       Batteries Included
  •       Easy to learn
  •       Qualified
  •       Full stack for modern web app

Why Angular?

 

  •       Developer tools
  •       Angular for mobile
  •       Development kit
  •       Angular elements

Angular as a Platform

Why Angular?

Angular As an Ecosystem

Hero No 1 of the day

Angular vs Angular1.x

AngularX has been reimplemented, not an evolution of Angularjs

Component based UI

$scope

ng-if

ng-app

ng-model

mobile

oriented

better

performance

x7

Languages

ES5

ES6

You can use any language that transpiles your code to Javascript, but I recommend using TypeScript

Advantages

  • Programs are less prone to errors
  • IDEs and editors can: Autocomplete,Refactor, navigate to the definition ...
  • The types are optional
  • You can combine js and ts

{

export class EntrenadorPokemon {
    private nombre:string;
    private pokeballs:number;

    constructor(nombre: string, 
                pokeballs: number) {
        this.nombre = nombre;
        this.pokeballs = pokeballs;
    }
    
    getNombre() {
        return this.nombre;
    }

    toString() {
        return "Nombre: "+ this.nombre + 
               ", Pokeballs: " + this.pokeballs;
    }    
}
function EntrenadorPokemon(nombre, pokeballs) {
    this.nombre = nombre;
    this.pokeballs = pokeballs;
}

EntrenadorPokemon.prototype.getNombre = 
    function(){
        return this.nombre;
};

EntrenadorPokemon.prototype.toString = 
    function(){
        return "Nombre: "+ this.nombre + 
               ", Pokeballs: " + this. pokeballs;
};

ES5

TypeScript

VS

Class

import { EntrenadorPokemon } from "./EntrenadorPokemon";

let entrenadores = new Array<EntrenadorPokemon>();

entrenadores.push(new EntrenadorPokemon('Ash', 150);
entrenadores.push(new EntrenadorPokemon('Josh', 30);

for(let entrenador of entrenadores) {
    console.log(entrenador.getNombre());
}

entrenadores.forEach(entrenador => {
    console.log(entrenador);
});

Imports

  • In TS each file has to be imported, there are modules and components.
import { EntrenadorPokemon } from "./EntrenadorPokemon";

let entrenadores = new Array<EntrenadorPokemon>();

entrenadores.push(new EntrenadorPokemon('Ash', 150);
entrenadores.push(new EntrenadorPokemon('Josh', 30);

for(let entrenador of entrenadores) {
    console.log(entrenador.getNombre());
}

entrenadores.forEach(entrenador => {
    console.log(entrenador);
});

Variables

  • In TS the variables are declared with let and have block scope and can not be declared twice. You could use var (like JS), but the scope would be the function and could be redeclared
  • The type can be declared with : , it is optional, it can be inferred from the initialization, but it is advisable to use typing.

Get & Set

class Goomba {

    private life: number;

    get life(): number {
        return this.life;
    }

    set life(hearts: number) {
        this.life = hearts;    
    }
}

how to use it

let enemy = new Goomba();

if(enemy.life == 0) {
    console.log('Goomba KO');

    enemy.life = 100;
} 

Definition Attributes

class Goomba {

    private life: number;

    constructor(hearts: number) {
        this.life = hearts;
    }
}
class Goomba {
    constructor(private life: number) {
        ...
    }
}

World

1-1

x

1

  CLI. What is it?

ngular

Scaffold

Preview

Local build

Local Testing

Unit tests

E2E tests

  CLI vs WebPack?

ngular

. Wraps Webpack

. Simple to configure

. Handy commands for     generating classes,   components …

. Cannot do advance     configurations

. A bit slow

.Details configuration

.Faster and customizable

.Less buggy

.Understand workflow better

.For curios/expert users

.A lot of stuff to manage

Angular CLI

WebPack

  building blocks

ngular

 "Mathews is a Poor Captain,Runner of SriLanka in the Decade"

Module

Component

Pipes

Directives

Metadata

Services

Dependency Injection

Component

import { Component } from '@angular/core';

@Component({
  selector: 'world', // Name of the html tag
  providers: [], // Services
  styleUrls: [], // Url of the styles
  templateUrl: './world.component.html'
})
export class WorldComponent {

}

ngular

Basic building block of an UI in an Angular application

Module

Angular has at least one module, either root or functionality, it's a class with a decorator @ngModule

 

Highest level of abstraction

ngular

How are the components organized?

ngular

Module

Directive

Structure

Attribute

<li *ngFor="let enemy of enemies">
</li>
<enemy *ngIf="hasLife">
</enemy>

*ngFor

*ngIf

<div [ngClass]="['bold-text', 'green']"></div>
<div [ngClass]="'italic-text blue'"></div>
<div [ngClass]="{'small-text': true, 'red': true}"></div>

ngClass

ngStyle

You can create your own!

No more ng-show, ng-hide, ng-click but functionality is still available

...

...

ngular

ngular

Services

There is a single object of each service in the application (singleton)

 

That is, all the components share "the same" service

 

In this way the services maintain the status of the application

ngular

Services


You can make a service not shared among all the components of the application (not singleton)


You can create an exclusive service for a component and its children


Instead of declaring the service in @NgModule providers it is declared in the @Component


It can be shared by the parent component and by its children components (included in it)

import { Injectable } from '@angular/core';

@Injectable()
export class BlockService {

  getCoins() { 
    return 100; 
  }
}

ngular

Services

ngular

import { Pipe } from '@angular/core';
import { PipeTransform } from '@angular/core';
@Pipe({name: 'filterReviewByStatus'})
export class FilterReviewByStatusPipe implements PipeTransform {


}

Pipe 1

Data

Pipes

Pipe 2

Pipe 3

Pipe 4

Exclusive service for a component

import { Component } from '@angular/core';
import { BlockCoins } from './blockCoins.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    providers: 'BlockCoins'
})

export class AppComponent {
    constructor (private blockCoins: BlockCoins) {
    }

}

 ngular

Services

Exclusive service for a component

export class AppComponent {
    constructor (private blockCoins: BlockCoins) {
    }
}

 ngular

DI

Dependency Injection is a design pattern that passes an object as dependencies in different components across the application.​

 

It creates a new instance of class along with its required dependencies

  • ngOnChanges - called when an input binding value changes
  • ngOnInit - after the first ngOnChanges
  • ngDoCheck - after every run of change detection
  • ngAfterContentInit - after component content initialized
  • ngAfterContentChecked - after every check of component content
  • ngAfterViewInit - after component's view(s) are initialized
  • ngAfterViewChecked - after every check of a component's view(s)
  • ngOnDestroy - just before the component is destroyed

ngular

Life Cycle

Events

<button (click)="jump()"></button>

ngular

Attributes

import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})

export class AppComponent {
    name = 'Mario';
    imageUrl = 'assets/img/mario.png';
}

ngular

<h1>It is me {{name}}</h1>
<img [src]="imgUrl"/>

app.component.html

app.component.ts

Data Binding

DOM

Component

{{ value }}

[property] = *value*

(event) = *handler*

[(event)] = *handler*

ngular

Comunication

ngular

Configuration of Properties (Father -> Son)

<world [name]="worldName"></world>
export class AppComponent {
    worldName = 'World 1-1';
}
import {Component, Input} from '@angular/core';

export class WorldComponent {
    @Input()
    private name: string;
}
<h1>{{name}}</h1>

app.component.ts

app.component.html

world.component.ts

world.component.html

Sending Events ( Son -> Father)

<world [name]="worldName" (changeName)='changeWorld($event)'></world>
export class AppComponent {
    worldName:string = 'World 1-1';

    changeWorld(name: string) {
        this.worldName = name;        
    }
}
import {Component, Input, Output, EventEmitter} from '@angular/core';

export class WorldComponent {
    @Input()
    private name: string;

    @Output()
    changeName = new EventEmitter<string>();

    click(level) {
        this.changeName.next(level);
    }
}
<h1>{{name}}</h1>
<button (click)='click("World 1-2")'>Next level</button>

app.component.ts

app.component.html

world.component.ts

world.component.html

Comunication

ngular

Router

ngular

<router-outlet></router-outlet>

<a [routerLink]="/world1"></a>

Set the Route

This is the container where the component or module indicated by the router will be loaded

World

2-1

x

2

Architecture

ngular

Architecture

ngular

Application Source

Our application is divided in two parts. -Application itself & Application bootstrap

Angular App

Our modules, routes, components & services live here.

Angular Boostrap

We bootstrap our app depending on what platform were developing for, and add any required polyfills & vendors.

Configuration

Typescript config, npm packages, scripts, webpack config, express server, and so on...

World

3-1

x

3

Ready?

Download

Install

Run!

https://nodejs.org/en/download/
npm install -g @angular/cli@latest
ng new ngHero --routing --style=scss
cd ngHero
npm start

We are going to create these elements in Angular

Let's make something awesome!

World

Home

Logo

Home

Game

What's the target?

Welcome to DevFest 2019

The first step to address in this application is to identity patterns, what things are reused and what is not

Service

Character

Enemies

World

http://goo.gl/PfqFQX 

ngular

We will start by creating a new Module

AngularHero inside the folder app/modules/

ng g m AngularHero

ngular

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';


@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ]
})

export class AngularHeroModule {
}

app/modules/angular-Hero/angularHero.module.ts

 

ngular

Lets start the first component

world.component.ts

ng g c world

Component World

import { Component } from '@angular/core';

@Component({
  selector: 'world', 
  providers: [],
  styleUrls: [],
  templateUrl: './world.component.html'
})
export class WorldComponent {

}

ngular

Component Home

ngular

What we get:

  • Template HTML, the component view
  • SCSS/CSS a style file
  • SPEC.TS unit test for the component
  • TS the main Typescript file*
ng g c home

Component App

ngular

ng g c app

Let's add some style

Open index.html and add the following css link in the head section:

<link rel="stylesheet" 
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/css/materialize.min.css">

Component Goomba

ngular

Now it's your turn, create a Goomba component. Goomba is an enemy of the Super Mario game

ng g c goomba

Add a Goomba to the World module

ngular

<h1>World</h1>
<app-goomba></app-goomba>

world.component.html

Add the component to the module AngularHeroModule.module.ts in the declarations section

Hope things go smoothly...

ngular

Create 3 enemies goompa

Exercise 1

<app-goomba (removeGoomba)="removeGoomba($event)" *ngFor="let enemy of enemies">
</app-goomba>

enemies: Array<string> = ['0', '1', '2'];

Create the character component

Exercise  2

*Note that Mario and Luigi are 2 equally playable characters, so you'll have to make your component flexible to define the character's name

ng g c character

Add Mario and Luigi to the world

Exercise 3

<app-character name="mario" name="Mario" style="background-color:darkred;display:block"></app-character>
<app-character name="luigi"  name="Luigi" style="background-color:darkgreen;display:block"></app-character>

Exercise 4

Set Routing

Tell Angular which component to load when navigating

Open app-routing.module.ts

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from "./home/home.component";

const routes: Routes = [
    {path: 'home', component: HomeComponent},
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule {
}

Tell to load HomeComponent when navigating in the browser domain.com/home

Mario and Luigi can jumb. Create a button when clicking click on the console that mario or luigi has jumped

Exercise 5

We're going to crush those Goomba. Create a button that allows the goomba to be crushed with a click and as a consequence, the goomba dissapears from the world.

Exercise 6

button

We are going to get some coins.Lets create a service that will supply Mario and Lugi with some coings when they are hit. Make it to show the total coins on each character.

Exercise 7

Let's make the character be the one who crushed the Goomba. As a benefit, each goomba that you crush will recieve 15 more coins

Exercise 8

ngular

All are solved

Otherwise

https://github.com/sajeetharan/DevFestLK2018-ngZeroToHero

Q&A

Rate the session

General App Performance

  • Make overall bundle size smaller

  • Split bundle and download only what we need for the starting-up

  • Cache network responses for the future usage

Build the app using prod

$ ng build --prod
  • Using Ahead of Time compilation

  • Using Build Optimizer

  • Executes enableProdMode() via setting prod environment

Tip #1

$ ng build --prod  --build-optimizer=true

How to do?

$ ng build --prod --source-map
$ >npm i -g source-map-explorer
$> source-map-explorer dist/angular-workshop/main.bundle.js

Use lazy loading

  • Download the only code needed to start the app

  • Use CanLoad guard to mediate navigation

  • Preload all the modules (except the ones protected by CanLoad) by using PreloadAllModules strategy

  • 100% flexibility with your custom PreloadingStrategy

Tip #2

How to

const appRoutes: Routes = [{
  path: 'tweets',
  loadChildren: 'tweets/tweets.module#TweetsModule'
}]
const tweetsRoutes: Routes = [{
  path: '',
  component: TweetFeedsComponent
}];

app-routing.module.ts

tweets/tweets-routing.module.ts

Preloading strategy

@NgModule({
  imports: [RouterModule.forRoot(appRoutes, {
    preloadingStrategy: PreloadAllModules
  })],
  exports: [RouterModule]
})

app-routing.module.ts

Use pure pipes instead of methods

<span>{{ relativeDate(tweet.createdAt) }}</span>

Calculated on every change detection

Tip #3

<span>{{ tweet.createdAt | relativeDate }}</span>

Calculated only if the value was changed

Use trackBy in ngFor loops

  • DOM manipulations are expensive

  • Immutable practices generate a new DOM collection

  • Smaller bundles

  • Template and CSS are inline, which save bunch of server roundtrip

  • Detect template error earlier build time

  • Better security

Tip #4

How to

export class TweetListComponent implements OnInit {
  ...

  trackById(index, tweet) {
      return tweet.id;
  }
}
<div *ngFor="let tweet of tweets; trackBy: trackById">

Recommended to Use CLI

Angular CLI takes care of tree shaking

 

Angular 4 has AOT by default Prod mode enabled on production mode CLI

Tip #5

 Clear observables / cleanup async code in ngOnDestroy lifecycle events.

In case of observable you could think of using async pipe using

Tip #6

Import specific

Don't forget to remove unnecessary  if you're not using it.

Tip #6

Tip #7

5 Simple Rules for Components


Should have Single Responsibility

Should be Simple

Should be Small

Should be Encapsulated

Should use Composition

5 Simple Rules for Components

  • Should have Single Responsibility

  • Should be Simple

  • Should be Small

  • Should be Encapsulated

  • Should use Composition

USER INTERFACE DISSECTION EXCERCISE

ngular Styleguide

Tip #7

"The ability of the system to undergo changes with a degree of ease"

LIFT

Tip #8

LOCATE

IDENTIFY

FLAT

TRY DRY

Don't Repeat Yourself

How do I modularize my code?

Special
Modules

Tip #9

Singleton

Shared

Code patterns

camelCaseForVariablesAndFunctions

dash-case-for-files-and-folders

TitleCaseForClassesAndInterfaces

Tip #10

Think in architecture

Zero-config ...always!

Choose carefully

Automate everything

Quick Recap

 

...complex systems evolve from simple systems much more rapidly when there are stable intermediate forms...

 

Herbert A. Simon

Q&A

Thank you!

Where to go from here?

- Build Applications

- Send your queries @kokkisajee

- Be a part of Ng-SriLanka

- Join Stackoverflowers-SriLanka

Made with Slides.com