Angular4
Building blocks ⌘
An Angular application consists of the following parts:
- Modules
- Components
- Templates
- Metadata
- Data binding
- Directives
- Services
- Dependency injection
The Core Concept 1 ⌘
NgModule is a decorator function that takes a single metadata object whose properties describe the module. The most important properties are: declarations - the view classes that belong to this module. Angular has three kinds of view classes: components, directives, and pipes. exports - the subset of declarations that should be visible and usable in the component templates of other modules. imports - other modules whose exported classes are needed by component templates declared in this module. providers - creators of services that this module contributes to the global collection of services; bootstrap - the main application view, called the root component, that hosts all other app views
The Core Concept 2 ⌘
- Javascript modules vs. angular modules
These are two different and complementary module systems. Use them both to write your apps. import { BrowserModule } from '@angular/platform-browser'; imports: [ BrowserModule ],
Angular(2) ⌘
- https://angular.io
- New Features
- Binding
- Directives, Validation, Pipes
- Data Flow
- State Management
- Angular 2
- Has a mobile-first design
- Engineered for a small footprint
- Data that flows from the server to the browser is minimized as much as possible
- Has been broken into a collection of modules
- Only the code needed to run the application is loaded
- Syntax has been simplified and made more coherent
- Easier to learn
- Better support for tooling and automation
Intro Con't 1 ⌘
To accomplish these goals
- Web Components
- Apps are built out of reusable building blocks hat encapsulate their internal logic
- ES2015 provides
- Classes and a solid system for loading Angular modules
- TypeScript
- Brings types that enable a simpler and more robust syntax
- Abillity to build large-scale applications
Intro Con't 2 ⌘
- Angular2, along with Typescript
- Allows to write code in both ES5 and ES2015
- It's own team uses TypeScript to build the framework
- Code written in TypeScript is far terser than the alternatives
- IDEs can provide better IntelliSense and code completion support
Bootstrap Angular 2 app ⌘
- Loading the modules
- App initialization process (bootstrapping)
Loading the modules ⌘
ES2015 introduced a new syntax for module loading
- It allows for modules to be loaded selectively and asynchronously
- TypeScript supports the ES2015 module loading syntax
- SystemJS allows to add module loading to applications that run ES5
- Combination of the two above gives
- TypeScript will transpile (compile) the application's components to ES5
- SystemJS will load them as ES5 modules
- Each of TypeScript files will be compiled to a SystemJS module
- SystemJS will then load all the related dependencies and when requested the module itself
- Example
<script src="https://unpkg.com/systemjs@0.19.27/dist/system.js"></script>
<script src="systemjs.config.js"></script>
Loading the modules con't ⌘
- Not limited to SystemJS module loader or pure TypeScript compiler
- Webpack (https://angular.io/guide/webpack)
- Babel (https://babeljs.io/)
Bootstrapping ⌘
Bootstrapping process:
- Angular scans component definition
- Imports the modules identified in the import statement of the component along with its related dependencies
- It compiles the HTML view
- Starts from where the my-app tag is declared.
- Traverses the template
- Looks for all interpolations
- Sets up the binding between the view and the class
- Post compilation links the view and the component class
- changes are synced across the model and viewed in real time as we interact with the app
- Example
Components in Angular 2 ⌘
- Component Pattern instead of MVC
- Constructs
- Interpolation, expressions, data binding syntax
- Change detection
Component pattern ⌘
- In general, involves combining smaller, discrete building blocks into larger finished products
- In software development, logical units that can be combined into larger applications
- Tend to have internal logic and properties that are shielded or hidden from the larger application
- The larger application consumes these building-blocks through specific gateways (interfaces)
- That expose only what is needed to make use of the component
- Component's internal logic can be modified without affecting the larger application
- As long as the interfaces are not changed
Component pattern Con't ⌘
In web applications
- No messes of spaghetti code in applications
- Reasoning about specific parts of the application in isolation from the other parts
- Maintenance costs are less
- Each component's internal logic can be managed separately
- No affecting the other parts of the application
- Self-describing components
- Makes the application easier to understand at a higher level of abstraction
Constructs ⌘
- Usually they live in the HTML template that is inside the @Component decorator
- They are linking the view HTML and component code
- Similar to standard HTML with new symbols:
[ ] property bindings ( ) event bindings {{ }} interpolation
Interpolation ⌘
- Replaces the content of the markup with the value of the expression (howManyTries)
- The value of the component property will be displayed as the contents inside the interpolation tags
- Declaration syntax:
{{expression}}
- Similar to a JavaScript expression
- Is always evaluated in the context of the component
- Interpolation tags read the value of the property directly from the component without any need for additional code
- Changes made to component properties are automatically synchronized with the view
- Easier debugging when we need to see the state of the model
- No need to put a breakpoint in code for the value of a component property or method call
- Example
<p class="text-info">No of tries :
<span class="badge">{{howManyTries}}</span>
</p>
Expressions ⌘
- Pieces of plain JavaScript code
- Evaluated in the context of the component instance
- Associated with the template instance in which they are used
- Should be kept simple (readability)
- When become complex, should be moved into a method in the component
- New meanings for operators | and ?.
Expressions Con't ⌘
Restrictions
- Assignment is prohibited, except in event bindings
- The new operator is prohibited
- ++, -- and bitwise operators are not supported
- No referring to anything in the global namespace
- No referring to a window or document
- No calling console.log
?. checks for null values in lengthy property paths
- Example
{{ invoice?.item }}
- If null value (invoice), it stops processing the path
- But lets the application continue running
- Good for data loaded asynchronously
- Because it might not be immediately available to the view
- Prevents the application from crashing
- Loads the data when it is available
Binding data ⌘
- Property binding
- Event binding
- Example
Property binding ⌘
[ ]
- Binding works by linking the value of the property in component class to the value of some element in the view
- The binding is dynamic
- As the value of the property changes
- The value of the element will be synchronized to the same value
- No need to write any code to do that
<input type="string" [value]="findJewel" (input)="findJewel = $event.target.value" />
Event binding ⌘
( )
- Event of element is bound to an expression
- The expression sets the property in component class to $event.target.value
- The value being entered by the user
- Angular sets up an event handler for the event that we are binding to
<button (click)="verifyTheTry()" class="btn btn-primary btn-sm">Verify</button>
<button (click)="initializeGame()" class="btn btn-warning btn-sm">Restart</button>
Change detection ⌘
- State maintenance
- Change detection
State maintenance ⌘
- Angular apps are dynamic
- Dynamic values are kept up-to-date as the data in an application gets updated
- Component is the container for the state
- all the properties in the component instance and their values are available for the template instance that is referenced in the component
- we can use these values directly in expressions and bindings in the template without having to write any plumbing code to wire them up
Change detection ⌘
Angular keeps track of changes in the component as it runs
- Is reacting to events in the application
- Uses change detectors
- Go through every component to determine whether anything has changed that affects the view
- Event triggers the change detection cycle
- Identifies that the property that is being used in the view has changed
- Updates the element in the view that is bound to property with the new value of it
Change detection Con't ⌘
- Multi-step process where Angular
- First updates the components and domain objects in response to an event
- Then runs change detection
- Lastly re-renders elements in the view that have changed
- This is done on every browser event
- Also other asynchronous events (XHR requests, timers, etc)
- one-way data binding
- Change detection in Angular is reactive and one way
- Makes just one pass through the change detection graph
- It vastly improves the performance of Angular
Web components ⌘
Standards for web browsers
- Custom elements
- Shadow DOM
- Templates
- HTML imports
Custom elements ⌘
Enable new types of element to be created
- Other than the standard HTML tag names (div, p, etc)
- Custom tags provides a location on the screen that can be reserved for binding a component
- Separation of component from the rest of the page
- Makes it possible to become truly self-contained
Shadow DOM ⌘
Provides a hidden area on the page for scripts, CSS, and HTML
- Markup and styles in it
- Will not affect the rest of the page
- Will not be affected by the markup and styles on other parts of the page
- Component can use it to render its display
Templates ⌘
Repeatable chunks of HTML
- Have tags that can be replaced with dynamic content at runtime using JavaScript
- Web Components standardize templating
- Provide direct support for it in the browser
- Can be used to make the HTML and CSS inside the Shadow DOM used by the component dynamic
HTML imports ⌘
Provide a way to load resources (HTML, CSS, JS) in a single bundle
- Angular does not use HTML imports
- It relies on JavaScript module loading instead
Module loading ⌘
Module provides a way for JavaScript files to be encapsulated
- Do not pollute the global namespace
- Can interact with other modules in a controlled manner
- Have to be loaded into application for execution
- ES2015
- export (or default export)
- import to consume them elsewhere in application
- SystemJS, etc
- ES2015
Transpilation ⌘
Convertion from ES2015 to ES5
- Similar to compilation
- Transfers one source code into the other
- Transpilers
- Traceur, Babel, TypeScript
Angular modules ⌘
Organise components into complete apps
- Combine the components into reusable groups of functionality
- Can be exported and imported throughout the application
- Modules can do: authentication, common utilities, external service calls, etc
- lazy loading
- Can be loaded on demand
- NgModule
- Conveniently specify the components that make up a module
- Every Angular app must have at least one root module
Angular modules con't ⌘
An Angular module defines:
- The components/directives/pipes it owns
- The components/directives/pipes it makes public for other modules to consume
- Other modules that it depends on
- Services that the module wants to make available application wide
Angular CLI, etc ⌘
- Tools
- Resources
Tools ⌘
- Browser's developer console - a lot of errors with code can be detected just by looking at it
- put in breakpoints, add a watch, etc
- Augury (https://augury.angular.io/)
- Helps visualise the application through component trees, and visual debugging tools
- Gives insight into application structure, change detection and performance characteristics
- IDE extensions: Visual Studio Code, JetBrains WebStorm, Sublime Text, Atom, etc
- JSFiddle and Plunker
- playgrounds for trying out HTML, CSS, and JavaScript code
- with versioning and sharing capabilities (http://jsfiddle.net/, http://plnkr.co/)
- Angular CLI - from the initial project setup all the way to the final deployment
Resources ⌘
- Angular source code, documentation and blog
- Awesome Angular https://github.com/AngularClass/awesome-angular
- Communities
- Built with Angular - http://builtwithangular2.com/
New Feature - AOT ⌘
- Ahead-Of-Time(AOT) compiler improvements (60% on component) (Used by Angular-CLI)
AOT vs. JIT ⌘
- Why bad for JIT(Just-in-Time) (dev)
- run-time penalty on performance
- rendering view takes time
- size bigger as it includes compiler itself and library code
- bigger app just slow to transmit and load
- found error at runtime
- Why AOT
- smaller & faster to render - no need to compile to js, done already
- fewer async requests - inlining CSS and HTML templates
- smaller to download - no compiler ( half the size of angular4 )
- detect error when build step
- better security - no template to read, no client-side html or js evalation
Other New Features ⌘
- Move animation out of the @angular/core package into its own package
- Angular Universal (server-side rendering) part of the core now
- TypeScript 2.1/2.2 compatible now, has better type checking
Syntax Improvements - ngIf, email ⌘
- ngIf.. else..
<div *ngIf="machines.length > 0; else empty">
<h2>Machines</h2>
</div>
<ng-template #empty>
<h2>No machines</h2>
</ng-template>
- new validator: email
// old way
<form #frm="ngForm">
<label>Email</label>
<input
type="email"
ngModel
name="email"
required
style="width:300px"
pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$"/>
<button [disabled]=!frm.valid>Submit</button>
</form>
// new way
<form #frm="ngForm">
<label>Email</label>
<input
type="email"
ngModel
name="email"
required
style="width:300px"
email/>
<button [disabled]=!frm.valid>Submit</button>
</form>
Bindings ⌘
- https://angular.io/guide/template-syntax#binding-targets
- property - one way in
- event - one way out
- two way
- attribute
- class
- style
//app.component.ts
<hero-detail [hero]="currentHero" (deleteRequest)="deleteHero()"></hero-detail>
// Data: currentHero ---- down ---> target element
// Event: deleteRequest ---- up ----> parent component ( app component in this case )
// this is also how the data flows in and out
Pipe Example ⌘
- DecimalPipe
{{ xxxxx | number: {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits} }}
// defaults: 1.0-3
Directive ⌘
About directive, all these are true:
- An Angular class, it adds behavior to HTML element or its attribute
- often refer to the HTML element or its attribute as the directive like
<my-component>, <div [ngClass].., <div [ngStyle]..
- When Angular finds a directive in an HTML template, it creates the matching directive class instance and gives the instance control over that portion of the browser DOM.
- You can invent custom HTML markup (for example, <my-directive>) to associate with your custom directives, a component for example.
Directive most of the time can fall into 3 categories ⌘
- Components - technically a directive with a template.
- Attribute directives - appear as attribute on html elements to decorate and add behavior to elements
- Structural directives - manipulating html layout and elements.
Directives and Pipes ⌘
Angular directives
- Custom tag directives - component directives - components
- Come with their own view
- Property and event binding - [ ], ( )
- Attribute directives
- Structural directives
- Directives (custom or platform), like components, have to be registered on a module before they can be used
Attributes directives and Structural directives ⌘
- Do not have their own view
- Binding data
- Attribute binding
- For HTML attributes that do not have a backing DOM property (colspan, aria, etc)
- Syntax
[attr.attribute-name]="expression"
- Class binding
- Set and remove a specific class based on the component state
- Syntax
[class.class-name]="expression"
- Style binding
- Set inline styles based on the component state
- Syntax
[style.style-name]="expression"
- Attribute binding
Attributes directives ⌘
- Enhance the appearance and/or behavior of existing elements/components
- Examples ngStyle, ngClass, ngValue, ngModel, ngSelectOptions, ngControl, ngFormControl, etc
- ngStyle
<div [ngStyle]= "{ 'width':componentWidth, 'height':componentHeight, 'font-size': 'larger', 'font-weight': ifRequired ? 'bold': 'normal' }"></div>
- ngClass
<div [ngClass]= "{'required':inputRequired, 'email':whenEmail}"></div>
Structural directives ⌘
- Looks similar to data binding
- Allow to manipulate the structure of DOM elements
- Example ngIf
- Removes or adds DOM elements based on the result of an expression that is assigned to it
<p *ngIf="hinting===false" class="alert alert-warning">Nope, not that one.. )-:</p> <p *ngIf="hinting===true" class="alert alert-success">Yes! That's it.</p>
- Removes or adds DOM elements based on the result of an expression that is assigned to it
- Example ngFor
<ul> <li *ngFor="let elementOnTheList of theList"> {{ elementOnTheList }} </li> </ul>
Exercises ⌘
1. Make better hinting (same starting letter, same ending letter) 2. Show all jewels in a nice lavender bootstrap grid, as the last element in the "no body, no crime" (=
Pipes ⌘
- Provide a mechanism to format view content
- Format the value of an expression displayed in the view
- Predefined pipes - date, currency, lowercase, uppercase, currency, json, etc
- Syntax (in a view):
{{expression | pipeName:inputParam1}}
- Can be chained
- Output from one pipe can serve as the input to another pipe
- Examples
{{ someString | slice:0:10 }} //renders first 10 characters {{ dateObj | date:'shortTime' }} // output is '9:43 PM' {{ 22.15 | currency:"USD" }} <!-Renders USD 22.15 --> {{ fullName | slice:0:10 | uppercase }}
Observables ⌘
- Core Reactive Extensions features
- Enhance the application so that users can
- edit existing objects in the model
- create new ones
- Distribute updates throughout an application
- immediate updates to the application state
- Observer - the mechanism by which updates are created
- Observable - represents an observable sequence of events
- An object such as a component can subscribe to an Observable
- will receive a notification each time an event occurs
- allowing it to respond only when the event has been observed
- instead of every time there is a change anywhere in the application
- An object such as a component can subscribe to an Observable
- Subject - class, which implements both the Observer and Observable functionality
- Easy to create a service that allows events to be produced and consumed with a single object
Dependency injection ⌘
Allows components and other building blocks
- To receive services by declaring dependencies on them using constructor parameters
- To share objects throughout an application
- To avoid the need to distribute shared objects manually
Forms ⌘
Angular provides set of constructs that make standard form-based operations easier
- Allowing user inputs
- two-way bindings between the form input elements and the underlying model
- hence avoiding any boilerplate code that we may have to write for model input synchronization
- two-way bindings between the form input elements and the underlying model
- Validating those inputs against business rules
- Submitting the data to the back-end server
Template Driven Forms ⌘
Template-driven forms develops a form within an HTML template
- handling most of the logic for the form-inputs, data validation, saving, and updating-in form directives placed within the template
- very little form-related code is required in the component class that is associated with the form's template
- make heavy use of the ngModel form directive
- It provides two-way data binding for form controls
- It allows us to write much less boilerplate code to implement a form
- It also helps us to manage the state of the form
- whether the form controls have changed and whether these changes have been saved
- Ability to easily construct messages that display if the validation requirements for a form control have not been met
Form Builder ⌘
Model-driven forms
- start with a model that is constructed in a component class
- form builder API creates a form in code and associate it with a model
- to create form controls dynamically based on data we are retrieving from the server
- for complicated validation, it is often easier to handle it in code
- keep complicated logic out of the HTML template, making the template syntax simpler
- make unit-testing the form possible
- New form directives - FormGroup, FormControl, and FormArray
- allow the form object that is constructed in code to be tied directly to the HTML markup in the template
- cleaner and less cluttered template with more focus on the code that drives the form
Angular 4 services ⌘
- provide and inject into module scope
- provide and inject into component scope
- singleton in the context of injector
- app component
- app module
- parent component context
Prepare ⌘
apt-get install nodejs
apt-get install npm
apt-get install nodejs-legacy
node -v
npm -v
npm install -g n
n
npm install -g @angular/cli
ng --version
add-apt-repository ppa:webupd8team/sublime-text-3
apt-get update
apt-get install sublime-text-installer
subl
Prepare: FormsModule ⌘
- Because we want to develop template-driven forms so we import FormsModule
- To develop Model-driven forms, you can import ReactiveFormsModule as another approach
//app.module.ts
import { FormsModule } from '@angular/forms';
..
imports: [
BrowserModule,
FormsModule
..
Prepare: Create Demo Page ⌘
ng g component demo-page
<div class="row">
<div class="col-md-2">
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="#">topic 1</a></li>
<li>topic 2</li>
<li>topic 3</li>
</ul>
</div>
<div class="col-md-10">
topic detail
</div>
</div>
Prepare: Topics ⌘
topics : string[] = ["Validation", "Pipe", "Data Flow", "State"];
Prepare: Create playground ⌘
ng g component playground
Prepare: playground template ⌘
<div [ngSwitch]="topicName" class="container">
<ng-container *ngSwitchCase="'Validation'">
Validation..
</ng-container>
<ng-container *ngSwitchCase="'Data Flow'">
Data Flow..
</ng-container>
<ng-container *ngSwitchCase="'State Management'">
State Management..
</ng-container>
</div>
Validation 1 ⌘
hero: Hero = new Hero();
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
<div class="row">
<div class="col-sm-4 col-sm-offset-4">
<form #heroForm="ngForm" (ngSubmit)="onSubmit()">
<button type="submit" class="btn btn-default"
[disabled]="!heroForm.form.valid">Submit</button>
</form>
</div>
</div>
Validation 2 ⌘
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" class="form-control"
required minlength="4" maxlength="24"
name="name" [(ngModel)]="hero.name"
#name="ngModel" >
<div *ngIf="name.errors && (name.dirty || name.touched)"
class="alert alert-danger">
<div [hidden]="!name.errors.required">
Name is required
</div>
<div [hidden]="!name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div [hidden]="!name.errors.maxlength">
Name cannot be more than 24 characters long.
</div>
</div>
</div>
Validation 3 ⌘
<div class="form-group">
<label for="email">Hero Email</label>
<input type="email" id="email" class="form-control"
required email
name="email" [(ngModel)]="hero.email"
#email="ngModel" >
<div *ngIf="email.errors && email.touched" class="alert alert-danger">
<div [hidden]="!email.errors.required">Email is required</div>
<div [hidden]="email.errors.required || !email.errors.email">Email is not valid</div>
</div>
</div>
Validation 4 ⌘
<div class="form-group">
<label for="power">Hero Power</label>
<select id="power" class="form-control"
name="power"
[(ngModel)]="hero.power" required
#power="ngModel" >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>
<div *ngIf="power.errors && power.touched" class="alert alert-danger">
<div [hidden]="!power.errors.required">Power is required</div>
</div>
</div>
Data Flow 1 ⌘
Data Flow 2 ⌘
- create 5 component, namely comp1, comp2, comp3, comp4, comp5
- comp1 contains 3 and 4
- comp2 contains 5
- Data flow rules:(data is presented as input element)
- app data flow to comp1
- comp1 data flow within itself
- comp5 flow to app
- exercise. comp5 flow to comp3
.comp1,
.comp2{
width:400px;
height:auto;
}
.comp1 {background-color: lightblue;}
.comp2 {background-color: yellow;}
.comp3,
.comp4,
.comp5{
width:200px;
height:200px;
}
State Management 1 ⌘
State Management 2 ⌘
Overview of ECMAScript 6 (ES6) and TypeScript ⌘
- ECMAScript:一个由 ECMA International 进行标准化,TC39 委员会进行监督的语言。通常用于指代标准本身。
- JavaScript:ECMAScript 标准的各种实现的最常用称呼。这个术语并不局限于某个特定版本的 ECMAScript 规范,并且可能被用于任何不同程度的任意版本的 ECMAScript 的实现。
- ECMAScript 5 (ES5):ECMAScript 的第五版修订,于 2009 年完成标准化。这个规范在所有现代浏览器中都相当完全的实现了。
- ECMAScript 6 (ES6) / ECMAScript 2015 (ES2015):ECMAScript 的第六版修订,于 2015 年完成标准化。这个标准被部分实现于大部分现代浏览器。可以查阅这张兼容性表来查看不同浏览器和工具的实现情况。
- ECMAScript 2016:预计的第七版 ECMAScript 修订,计划于明年夏季发布。这份规范具体将包含哪些特性还没有最终确定
- ECMAScript Proposals:被考虑加入未来版本 ECMAScript 标准的特性与语法提案,他们需要经历五个阶段:Strawman(稻草人),Proposal(提议),Draft(草案),Candidate(候选)以及 Finished (完成)。
Building reactivity into your applications ⌘
- Completing our service with observable
- Reactive Forms
Reactive Form ⌘
- Angular reactive forms facilitate a reactive style of programming to get data in and out of the form from where it is been defined in the component to the template visa versa through the use of Form Model and Form Directives. Reactive forms offer the ease of using reactive patterns, testing, and validation.
- Form Model
- The form model is a UI-independent representation of a form. It consists of three building blocks: FormControl, FormGroup, and FormArray.
- Form Directives
- These are the directives connecting the form model to the DOM (e.g., NgModel). FormsModule and ReactiveFormsModule provide different sets of these directives.
Status of a group ⌘
- The status of a group is calculated as follows:
- If one of its children is invalid, the group is invalid.
- If all of its children are valid, but the group itself has errors, the group is invalid.
- If all of its children are valid, and the group has no errors, the group is valid.
Loading data via HTTP ⌘
Asynchronous HTTP requests
- HTTP requests sent by the browser on behalf of the application
- asynchronous - the application continues to operate while the browser is waiting for the server to respond
- allow Angular to interact with web services
- persistent data can be loaded into the application and changes can be sent to the server and saved
- Requests are made using the Http class, delivered as a service through dependency injection
- This class provides an Angular-friendly wrapper around the browser’s XMLHttpRequest feature
Angular 4 modules ⌘
- Code that can be managed
- Address performance concerns and team working
- eager loading
- lazy loading
- pre-loading
- import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
- imports: [RouterModule.forRoot(appRoutes, {preloadingStrategy: PreloadAllModules})]
state management library ⌘
Unit Testing ⌘
- This is sometimes also called Isolated testing. It’s the practice of testing small isolated pieces of code. If your test uses some external resource, like the network or a database, it’s not a unit test.
- Jasmine test framework
- Karma test runner
Example ⌘
- For example if we wanted to test this function:
function helloWorld() { return 'Hello world!'; }
Test Code ⌘
- We would write a jasmine test spec like so:
describe('Hello world', () => { it('says hello', () => { expect(helloWorld()) .toEqual('Hello world!'); }); });
- The describe(string, function) function defines what we call a Test Suite, a collection of individual Test Specs.
- The it(string, function) function defines an individual Test Spec, this contains one or more Test Expectations.
- The expect(actual) expression is what we call an Expectation. In conjunction with a Matcher it describes an expected piece of behaviour in the application.
- The matcher(expected) expression is what we call a Matcher. It does a boolean comparison with the expected value passed in vs. the actual value passed to the expect function, if they are false the spec fails.
Jasmine Built-in Matchers ⌘
expect(array).toContain(member); expect(fn).toThrow(string); expect(fn).toThrowError(string); expect(instance).toBe(instance); expect(mixed).toBeDefined(); expect(mixed).toBeFalsy(); expect(mixed).toBeNull(); expect(mixed).toBeTruthy(); expect(mixed).toBeUndefined(); expect(mixed).toEqual(mixed); expect(mixed).toMatch(pattern); expect(number).toBeCloseTo(number, decimalPlaces); expect(number).toBeGreaterThan(number); expect(number).toBeLessThan(number); expect(number).toBeNaN(); expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledTimes(number); expect(spy).toHaveBeenCalledWith(...arguments);
A few useful functions ⌘
- beforeAll
- This function is called once, before all the specs in describe test suite are run.
- afterAll
- This function is called once after all the specs in a test suite are finished.
- beforeEach
- This function is called before each test specification, it function, has been run.
- afterEach
- This function is called after each test specification has been run.
You might write function like so ⌘
describe('Hello world', () => {
let expected = "";
beforeEach(() => {
expected = "Hello World";
});
afterEach(() => {
expected = "";
});
it('says hello', () => {
expect(helloWorld())
.toEqual(expected);
});
});
Karma ⌘
- Manually running Jasmine tests by refreshing a browser tab repeatedly in different browsers every-time we edit some code can become tiresome.
- Karma is a tool which lets us spawn browsers and run jasmine tests inside of them all from the command line. The results of the tests are also displayed on the command line.
- Karma can also watch your development files for changes and re-run the tests automatically.
- Karma lets us run jasmine tests as part of a development tool chain which requires tests to be runnable and results inspectable via the command line.
- It’s not necessary to know the internals of how Karma works. When using the Angular CLI it handles the configuration for us and for the rest of this section we are going to run the tests using only Jasmine.
x and f ⌘
- x: disables tests
- f: focused tests
xdescribe('Hello world', () => {
xit('says hello', () => {
expect(helloWorld())
.toEqual('Hello world!');
});
});
fdescribe('Hello world', () => {
fit('says hello', () => {
expect(helloWorld())
.toEqual('Hello world!');
});
});
APP_INITIALIZER ⌘
export function userServiceFactory(userService: UserService) { return () => userService.loadUser(); }
providers: [ UserService, { provide: APP_INITIALIZER, useFactory: userServiceFactory, deps: [UserService], multi: true },---------------------
Angular coding and architecture best practices ⌘
- Be specific about naming, variable names, class name etc
- 200 lines per component, 70 lines per function
- Modularize early
- Avoid impure Pipe if you can, so sort, filter in component
- Module loading strategies impact UX