Angular

André Werlang

@awerlang

The Developer's Conference 2017 - Porto Alegre

Today's Mission

  • Remove barrier to TypeScript
  • Get an app running is easy
  • Understand how it works

Agenda

  • Myths & Facts
  • Getting Started
  • Features
  • Elements
  • Final Remarks

Angular 2 myths

  • Requires TypeScript
  • Doesn't support two-way binding
  • Requires a master's degree on bundling tools
  • View code is VM friendly
  • Has its own module loading system
  • Run side by side with Angular 1.x

Facts

  • ~30k stars on GitHub
  • ~7.5k forks on GitHub
  • ~2.5k watchers on GitHub
  • > 80k questions on StackOverflow
  • > 14k users on gitter

Getting Started

Powered By

JavaScript
TypeScript
RxJS

TypeScript

https://www.typescriptlang.org/

Compiler (tsc)

  • Targets ES5, ES2015, ES2016...
  • Module generation: ES2015, CommonJS, System...
  • Emits decorator metadata
  • Many static checks
  • Watch mode

Language

  • Type annotations
  • Interfaces
  • Enums
  • Visibility modifiers
  • Auto-properties on constructors
  • Structural compatibility

Data Types

  • any
  • string
  • number
  • boolean
  • null
  • undefined
  • void
  • never

Migrate from JS

  • Declare external definitions
  • Add types to every declaration
  • Create classes for implicit structures
  • Convert constructor functions to classes
  • Declare implicit members
  • (Optional) Convert anonymous functions to arrow syntax
  • (Optional) Use block-scoped bindings (const, let)

https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html

Angular CLI

A command line interface for Angular projects

https://github.com/angular/angular-cli

Angular CLI

Commands

Create component
ng g c <component-name>
Serve
ng serve
Build production, offline compiler
ng build --prod --aot
Linter
ng lint
Test
ng test

Features

Change Detection

Loading...

It's interactive! Click on any element!

Takeaways

  • Change detection happens top-down
  • Needs to stabilize in a single round
  • Shared, mutable structures is a no-go
  • On Push performs better (and is not that hard!)

Zones

https://domenic.github.io/zones/

Zones

No more:

  • $q
  • $timeout
  • $scope.$apply (well, almost)
  • $scope.$$phase!!

Decorators

They augment:

  • Classes
  • Properties
  • Methods
  • Parameters

@frozen class Foo {
  @configurable(false) @enumerable(true) method() {}
}
                

https://tc39.github.io/proposal-decorators/ https://www.typescriptlang.org/docs/handbook/decorators.html

Elements

Components

Provides a context for data and events,
supports template, styling,
can have services injected
and is change detected

* A directive is a component with no template.

Components


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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  topics = ['commits', 'branches', 'remotes'];
  actions = ['list', 'create', 'delete'];

  onGoClick() {
    // TODO
  }
}
                    

Components

Inputs & Outputs


import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'my-component',
  templateUrl: './my.component.html',
  styleUrls: ['./my.component.css']
})
export class MyComponent {
  @Input() input: DataType;

  @Output() event = new EventEmitter<DataType>(false);

  onEvent(value) {
      this.event.emit(value);
  }
}
                    

Templates

Composes the view with an HTML-like syntax,
interpolates text and data, binds events,
and includes other components.

Templates


<md-chip-list>
  <md-chip *ngFor="let topic of topics">{{topic}}</md-chip>
</md-chip-list>

<button md-button color="primary" (click)="onGoClick()">Go!</button>
                    

Templates

Inputs & Outputs


                        <input #myInput [value]="input" (change)="myInput.value">
                    

                        <input [(ngModel)]="field">
                    

Styling

Styles a component view, supports view encapsulation.

Styling


:host {
    display: block;
    max-width: 500px;
    font-family: Roboto,"Helvetica Neue",sans-serif;
}

.go {
    margin-top: 8px;
    float: right;
}

md-divider {
    clear: both;
}
                    

Animations

Declarative transitions and animations,
with state triggers and synchornization support.

Animations


animations: [
  trigger('flyInOut', [
    state('in', style({transform: 'translateX(0)'})),
    transition('void => *', [
      style({transform: 'translateX(-100%)'}),
      animate(100)
    ]),
    transition('* => void', [
      animate(100, style({transform: 'translateX(100%)'}))
    ])
  ])
]
                    

                        <md-chip *ngFor="let topic of topics" [@flyInOut]="'in'">...</md-chip>
                    

Services

Encapsulates business logic
and shares data among components

Services


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

@Injectable()
export class TipsService {
    match(topic, action) {
        // TODO
    }
}
                    

import { TipsService } from './tips.service';

export class AppComponent {
  constructor(private tips: TipsService) { }

  onGoClick() {
    const matchingTips = this.tips.match(this.topic, this.action);
  }
}
                    

NgModules

Organizes elements and creates reusable modules.

NgModules


import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MaterialModule } from '@angular/material';
import { AppComponent } from './app.component';
import { TipsService } from './tips.service';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    MaterialModule.forRoot(),
  ],
  providers: [TipsService],
  bootstrap: [AppComponent]
})
export class AppModule { }
                    

Testing

Components


beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [
      MaterialModule.forRoot(),
    ],
    declarations: [
      AppComponent
    ],
    providers: [{ provide: TipsService, useValue: tipsService }],
  });
  TestBed.compileComponents();
});
                    

Components


it('should render results', async(() => {
  const topicChip: DebugElement = fixture.debugElement
    .query(By.css('.topics')).query(By.directive(MdChip));
  const actionChip: DebugElement = fixture.debugElement
    .query(By.css('.actions')).query(By.directive(MdChip));

  topicChip.triggerEventHandler('click', null);
  actionChip.triggerEventHandler('click', null);

  goBtn.triggerEventHandler('click', null);
  fixture.detectChanges();

  expect(el.querySelector('h4').textContent).toEqual('One tip found');
}));
                    

Services


let service = new TipsService();
beforeEach(() => {
    service = new TipsService();
});

describe('getTopics', () => {
    it('should work', () => {
        expect(service.getTopics())
            .toEqual(['changes', 'branches', 'commits', 'remotes']);
    });
});
                    

Standard Modules

  • Http
  • Forms
  • Router

Final Remarks

Platforms

  • Progressive Web Apps
  • Angular Universal
  • Ionic
  • NativeScript
  • ReactNative

https://angular.io/resources/

UI Components

  • Material
  • Bootstrap
  • Lightning
  • Semantic UI
  • PrimeNG
  • Kendo UI
  • wijmo

https://angular.io/resources/

State Containers

Recommendations

  • Employ a redux architecture
  • Use unidirectional data flow (OnPush strategy)
  • Learn about containers & presentational components
  • Turn on static checks for TypeScript

Obrigado!

@awerlang
https://github.com/awerlang/angular-show-off