\documentclass[10pt,a4paper]{article} % Packages \usepackage{fancyhdr} % For header and footer \usepackage{multicol} % Allows multicols in tables \usepackage{tabularx} % Intelligent column widths \usepackage{tabulary} % Used in header and footer \usepackage{hhline} % Border under tables \usepackage{graphicx} % For images \usepackage{xcolor} % For hex colours %\usepackage[utf8x]{inputenc} % For unicode character support \usepackage[T1]{fontenc} % Without this we get weird character replacements \usepackage{colortbl} % For coloured tables \usepackage{setspace} % For line height \usepackage{lastpage} % Needed for total page number \usepackage{seqsplit} % Splits long words. %\usepackage{opensans} % Can't make this work so far. Shame. Would be lovely. \usepackage[normalem]{ulem} % For underlining links % Most of the following are not required for the majority % of cheat sheets but are needed for some symbol support. \usepackage{amsmath} % Symbols \usepackage{MnSymbol} % Symbols \usepackage{wasysym} % Symbols %\usepackage[english,german,french,spanish,italian]{babel} % Languages % Document Info \author{thorstenschaefer} \pdfinfo{ /Title (angular2.pdf) /Creator (Cheatography) /Author (thorstenschaefer) /Subject (Angular2 Cheat Sheet) } % Lengths and widths \addtolength{\textwidth}{6cm} \addtolength{\textheight}{-1cm} \addtolength{\hoffset}{-3cm} \addtolength{\voffset}{-2cm} \setlength{\tabcolsep}{0.2cm} % Space between columns \setlength{\headsep}{-12pt} % Reduce space between header and content \setlength{\headheight}{85pt} % If less, LaTeX automatically increases it \renewcommand{\footrulewidth}{0pt} % Remove footer line \renewcommand{\headrulewidth}{0pt} % Remove header line \renewcommand{\seqinsert}{\ifmmode\allowbreak\else\-\fi} % Hyphens in seqsplit % This two commands together give roughly % the right line height in the tables \renewcommand{\arraystretch}{1.3} \onehalfspacing % Commands \newcommand{\SetRowColor}[1]{\noalign{\gdef\RowColorName{#1}}\rowcolor{\RowColorName}} % Shortcut for row colour \newcommand{\mymulticolumn}[3]{\multicolumn{#1}{>{\columncolor{\RowColorName}}#2}{#3}} % For coloured multi-cols \newcolumntype{x}[1]{>{\raggedright}p{#1}} % New column types for ragged-right paragraph columns \newcommand{\tn}{\tabularnewline} % Required as custom column type in use % Font and Colours \definecolor{HeadBackground}{HTML}{333333} \definecolor{FootBackground}{HTML}{666666} \definecolor{TextColor}{HTML}{333333} \definecolor{DarkBackground}{HTML}{4083DB} \definecolor{LightBackground}{HTML}{F3F7FC} \renewcommand{\familydefault}{\sfdefault} \color{TextColor} % Header and Footer \pagestyle{fancy} \fancyhead{} % Set header to blank \fancyfoot{} % Set footer to blank \fancyhead[L]{ \noindent \begin{multicols}{3} \begin{tabulary}{5.8cm}{C} \SetRowColor{DarkBackground} \vspace{-7pt} {\parbox{\dimexpr\textwidth-2\fboxsep\relax}{\noindent \hspace*{-6pt}\includegraphics[width=5.8cm]{/web/www.cheatography.com/public/images/cheatography_logo.pdf}} } \end{tabulary} \columnbreak \begin{tabulary}{11cm}{L} \vspace{-2pt}\large{\bf{\textcolor{DarkBackground}{\textrm{Angular2 Cheat Sheet}}}} \\ \normalsize{by \textcolor{DarkBackground}{thorstenschaefer} via \textcolor{DarkBackground}{\uline{cheatography.com/27484/cs/7973/}}} \end{tabulary} \end{multicols}} \fancyfoot[L]{ \footnotesize \noindent \begin{multicols}{3} \begin{tabulary}{5.8cm}{LL} \SetRowColor{FootBackground} \mymulticolumn{2}{p{5.377cm}}{\bf\textcolor{white}{Cheatographer}} \\ \vspace{-2pt}thorstenschaefer \\ \uline{cheatography.com/thorstenschaefer} \\ \end{tabulary} \vfill \columnbreak \begin{tabulary}{5.8cm}{L} \SetRowColor{FootBackground} \mymulticolumn{1}{p{5.377cm}}{\bf\textcolor{white}{Cheat Sheet}} \\ \vspace{-2pt}Not Yet Published.\\ Updated 12th May, 2016.\\ Page {\thepage} of \pageref{LastPage}. \end{tabulary} \vfill \columnbreak \begin{tabulary}{5.8cm}{L} \SetRowColor{FootBackground} \mymulticolumn{1}{p{5.377cm}}{\bf\textcolor{white}{Sponsor}} \\ \SetRowColor{white} \vspace{-5pt} %\includegraphics[width=48px,height=48px]{dave.jpeg} Measure your website readability!\\ www.readability-score.com \end{tabulary} \end{multicols}} \begin{document} \raggedright \raggedcolumns % Set font size to small. Switch to any value % from this page to resize cheat sheet text: % www.emerson.emory.edu/services/latex/latex_169.html \footnotesize % Small font. \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Component creation}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{import \{Component, Input, EventEmitter\} from 'angular2/core' \newline @Component(\{ \newline selector: '{\bf{favorite}}', \newline template: `\textless{}div (click)="onClick()"\textgreater{} \newline {\bf{\{\{ favorite ? "I like it" : "I don't like it" \}\}}} \newline \textless{}/div\textgreater{} \newline ` \newline \}) \newline export class {\bf{Component}} \{ \newline {\bf{@Input() isFavorite = false;}} \newline {\bf{@Output() change = new EventEmitter();}} \newline \newline onClick() \{ \newline this.isFavorite = !this.isFavorite(); \newline {\bf{this.change.emit( \{ newValue : this.isFavorite \} );}} \newline \} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{Properties marked with {\bf{@Input()}} and {\bf{@Output()}} form the public API of our component. Users of our component can pass data to the component by setting the input properties and listening to its events. To fire an event, we use the {\bf{emit()}} method of our {\bf{EventEmitter}}, which can take an event object as parameter.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Component usage}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{{\bf{import \{FavoriteComponent\} from './favorite.component'}} \newline \newline @Component(\{ \newline selector: "componentUser" \newline template: '{\bf{\textless{}favorite {[}isFavorite{]}="true" (change)="onFavoriteChange(\$event)"\textgreater{}\textless{}/favorite \textgreater{}}}', \newline directives: {[}{\bf{FavoriteComponent}}{]} \newline \}) \newline export class ComponentUser \{ \newline {\bf{onFavoriteChange(\$event) \{}} \newline {\bf{console.log("Favorite component fired change event: " + \$event);}} \newline {\bf{\}}} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{To use a component, we need to import it, add it to our directives in order to let Angular know that it needs to render the component (otherwise, the tag is just output), and use it in our template. \newline \newline We can pass data to the component by setting its input properties and handle any event that are declared as outputs. For each event, we also have access to the event object via the variable {\bf{\$event}}.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Service creation}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{import \{Injectable\} from 'angular2/core'; \newline import \{Http, Response\} from 'angular2/http'; \newline import \{Observable\} from 'rxjs/Observable'; \newline import 'rxjs/add/operator/map'; \newline \newline import \{IUser\} from './iuser'; \newline \newline @Injectable() \newline export class UserService \{ \newline \newline private url = \seqsplit{'http://jsonplaceholder.typicode.com/users';} \newline \newline constructor(private http:Http) \{\} \newline \newline getUsers(): Observable\textless{}IUser{[}{]}\textgreater{} \{ \newline return this.http.get(this.url) \newline .map(response =\textgreater{} response.json()); \newline \} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{Services are just regular typescript classes. {\bf{@Injectable()}} is only required if the service itself depends on other services via dependency injection. However, it is a best practice to decorate all services with {\bf{@Injectable()}}.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Service usage}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{import \{Component, {\bf{OnInit}}\} from 'angular2/core'; \newline {\bf{import MyService from "./my-service.service";}} \newline \newline @Component(\{ \newline {\bf{providers: {[}UserService{]}}} \newline \}) \newline export class CourseComponent \{ \newline \newline users: Array\textless{}IUser\textgreater{} = undefined; \newline \newline constructor({\bf{userService: UserService}}) \{ \} \newline \newline ngOnInit() \{ \newline {\bf{this.userService.getUsers().subscribe(users =\textgreater{} \{ this.users = users; \} \}); }} \newline \} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{To use a service, we need to import it, reference it in our providers and pass a reference in a constructor, which lets Angular inject the service into our class.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Directive creation}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{import \{Directive\} from 'angular2/core'; \newline import \{ElementRef, Renderer\} from 'angular2/core'; \newline \newline @Directive(\{ \newline selector: {[}{\bf{myDirective}}{]}, \newline host: \{ \newline {\bf{'(onmouseenter)' : 'gettingFocus()',}} \newline {\bf{'(onmouseleave)' : 'leavingFocus()'}} \newline \} \}) \newline export class {\bf{MyDirective}} \{ \newline \newline {\bf{constructor(el: ElementRef, renderer: Renderer) \{ \}}} \newline \newline {\bf{gettingFocus() \{}} \newline {\bf{this.renderer.setElementStyle(this.el.nativeElement.style.color='red')}} \newline {\bf{\}}} \newline {\bf{leavingFocus() \{ ... \}}} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{The host section captures DOM events and maps them to methods in our directive class. \newline To access and modify the DOM element, we inject the element reference (which can be used to get the native DOM element) and the renderer.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{2.8679 cm} x{6.9167 cm} x{7.0854 cm} } \SetRowColor{DarkBackground} \mymulticolumn{3}{x{17.67cm}}{\bf\textcolor{white}{Bindings}} \tn % Row 0 \SetRowColor{LightBackground} \seqsplit{Interpolation} & \{\{ expression \}\} & \textless{}h1\textgreater{}\{\{ title \}\}\textless{}/h1\textgreater{} \tn % Row Count 3 (+ 3) % Row 1 \SetRowColor{white} Elvis \seqsplit{operator} & \{\{ \seqsplit{object?.nullableProperty} \}\} & \{\{ \seqsplit{book?.appendix?.pages} \}\} \tn % Row Count 6 (+ 3) % Row 2 \SetRowColor{LightBackground} \seqsplit{Property} \seqsplit{binding} & {[}{\emph{property}}{]}="expression" & \textless{}img {[}src{]}="imageUrl" /\textgreater{} \tn % Row Count 9 (+ 3) % Row 3 \SetRowColor{white} Class \seqsplit{binding} & {[}class.{\emph{className}}{]}="expression" & \textless{}li {[}class.active{]}="isActive" /\textgreater{} \tn % Row Count 12 (+ 3) % Row 4 \SetRowColor{LightBackground} \seqsplit{ngClass} \seqsplit{binding} & {[}ngClass{]}=\{'{\emph{className}}':expression, ...\} & li {[}ngClass{]}=\{\{\{nl\}\}'active':isActive, \{\{nl\}\}'passive':!isActive\{\{nl\}\}\} /\textgreater{} \tn % Row Count 17 (+ 5) % Row 5 \SetRowColor{white} Style \seqsplit{binding} & {[}style.{\emph{styleName}}{]}="expression" & \textless{}button {[}style.backgroundColor{]}="isActive ? 'blue' : 'gray'"\textgreater{} \tn % Row Count 22 (+ 5) % Row 6 \SetRowColor{LightBackground} \seqsplit{ngStyleBinding} & {[}ngStyle{]}=\{{\emph{styleName}}:expression, ...\} & \textless{}button {[}ngStyle{]}=\{\{\{nl\}\}backgroundColor:isActive ? blue : gray, \{\{nl\}\}color: canSave? 'white' : 'back'\{\{nl\}\} \}/\textgreater{} \tn % Row Count 30 (+ 8) \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{2.8679 cm} x{6.9167 cm} x{7.0854 cm} } \SetRowColor{DarkBackground} \mymulticolumn{3}{x{17.67cm}}{\bf\textcolor{white}{Bindings (cont)}} \tn % Row 7 \SetRowColor{LightBackground} Event \seqsplit{binding} & ({\emph{event}})="expression" & \textless{}button (click)="onClick(\$event)"\textgreater{} \tn % Row Count 3 (+ 3) % Row 8 \SetRowColor{white} \seqsplit{Two-way} \seqsplit{binding} & {[}(ngModel){]}="{\emph{property}}" & \textless{}input type="text" {[}(ngModel){]}="firstName"\textgreater{} \tn % Row Count 7 (+ 4) \hhline{>{\arrayrulecolor{DarkBackground}}---} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{4.5549 cm} x{6.2419 cm} x{6.0732 cm} } \SetRowColor{DarkBackground} \mymulticolumn{3}{x{17.67cm}}{\bf\textcolor{white}{Templates}} \tn % Row 0 \SetRowColor{LightBackground} Show/hide element & {[}hidden{]}="expression" & \textless{}div {[}hidden{]}="courses.length == 0"\textgreater{}\textless{}/div\textgreater{} \tn % Row Count 4 (+ 4) % Row 1 \SetRowColor{white} \seqsplit{Add/remove} element & \seqsplit{*ngIf="expression"} & \textless{}div \seqsplit{*ngIf="courses}.length \textgreater{} 0"\textgreater{}\textless{}/div\textgreater{} \tn % Row Count 7 (+ 3) % Row 2 \SetRowColor{LightBackground} \seqsplit{Add/remove} multiple cases & {[}ngSwitch{]}="expression"; \{\{nl\}\}{[}ngWhen{]}="expression"; \{\{nl\}\}ngSwitchDefault & \textless{}div {[}ngSwitch{]}="viewMode"\textgreater{}\{\{nl\}\} \textless{}template {[}ngSwitchWhen{]}="'map'" ngSwitchDefault\textgreater{}\{\{nl\}\} ... \{\{nl\}\}\textless{}/template\textgreater{}\{\{nl\}\} \textless{}template {[}ngSwitchWhen{]}="'list'"\textgreater{}\{\{nl\}\} ... \{\{nl\}\} \textless{}/template\textgreater{}\{\{nl\}\} \textless{}/div\textgreater{} \tn % Row Count 23 (+ 16) % Row 3 \SetRowColor{white} Creating element several times & \seqsplit{*ngFor="expression"} & \textless{}li *ngFor="let course of courses, \#i=index"\textgreater{}\{\{nl\}\}\{\{ (i+1) \}\} - \{\{ course \}\}\{\{nl\}\}\textless{}/li\textgreater{} \tn % Row Count 30 (+ 7) \hhline{>{\arrayrulecolor{DarkBackground}}---} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{3.1086 cm} x{14.1614 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{17.67cm}}{\bf\textcolor{white}{Built-in pipes}} \tn % Row 0 \SetRowColor{LightBackground} \seqsplit{uppercase} & \{\{ course.title | uppercase \}\} -\textgreater{} ANGULAR COURSE \tn % Row Count 2 (+ 2) % Row 1 \SetRowColor{white} \seqsplit{lowercase} & \{\{ course.title | lowercase \}\} -\textgreater{} angular course \tn % Row Count 4 (+ 2) % Row 2 \SetRowColor{LightBackground} number & \{\{ course.students | number \}\} -\textgreater{} 1,234\{\{nl\}\}\{\{ course.rating | number:'2.2-2' \}\} -\textgreater{} 04.97 \tn % Row Count 7 (+ 3) % Row 3 \SetRowColor{white} \seqsplit{currency} & \{\{ course.price | currency:'USD':true \}\} -\textgreater{} \$99.95 \tn % Row Count 9 (+ 2) % Row 4 \SetRowColor{LightBackground} date & \{\{ course.releaseDate | date:'MMM yyyy' \}\} -\textgreater{} Mar 2016 \tn % Row Count 11 (+ 2) % Row 5 \SetRowColor{white} json & \{\{ course | json \}\} -\textgreater{} \{ name : "Angular", author: "Mosh" \} \tn % Row Count 13 (+ 2) \hhline{>{\arrayrulecolor{DarkBackground}}--} \SetRowColor{LightBackground} \mymulticolumn{2}{x{17.67cm}}{TODO: add pipe parameters} \tn \hhline{>{\arrayrulecolor{DarkBackground}}--} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Pipe creation}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{import \{Pipe, PipeTransform\} from 'angular2/core'; \newline \newline {\bf{@Pipe(\{ name: 'shorten' \})}} \newline export class ShortenPipe {\bf{implements PipeTransform}} \{ \newline {\bf{transform(value: string, args: string{[}{]}) \{}} \newline var limit = (args \&\& args{[}0{]}) ? args{[}0{]} : 20; \newline if (value) \newline return value.substring(0, limit) + "..."; \newline {\bf{\}}} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{Pipes are typescript classes that implement the {\bf{PipeTransform}} interface and have an {\bf{@Pipe()}} decorator. Each pipe has a name provided through the decorator. We can access arguments to the pipe via the {\bf{args}} parameter in the {\bf{transform()}} method.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Pipe usage}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{import \{Component\} from 'angular2/core'; \newline {\bf{import \{ShortenPipe\} from './shorten.pipe';}} \newline \newline @Component(\{ \newline selector: 'my-app', \newline template: '\{\{ longText {\bf{| shorten:10}} \}\}, \newline {\bf{pipes: {[}ShortenPipe{]}}} \newline export class AppComponent \{ \newline longText = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua." \newline ... \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{To use a pipe, we need to import it, reference it in our pipes and then can apply it to any fields.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{10.362 cm} p{6.908 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{17.67cm}}{\bf\textcolor{white}{Todos}} \tn % Row 0 \SetRowColor{LightBackground} ngContent & vid 51 \tn % Row Count 1 (+ 1) \hhline{>{\arrayrulecolor{DarkBackground}}--} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{5.181 cm} x{12.089 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{17.67cm}}{\bf\textcolor{white}{Form Control/ControlGroup Properties}} \tn % Row 0 \SetRowColor{LightBackground} value & Value of the input field \tn % Row Count 1 (+ 1) % Row 1 \SetRowColor{white} \seqsplit{touched/untouched} & Whether the field has been activated once \tn % Row Count 3 (+ 2) % Row 2 \SetRowColor{LightBackground} \seqsplit{dirty/pristine} & Whether the field value has been changed \tn % Row Count 5 (+ 2) % Row 3 \SetRowColor{white} valid & Whether the field value passes validation \tn % Row Count 7 (+ 2) % Row 4 \SetRowColor{LightBackground} errors & Validation errors for the field. May be null. \tn % Row Count 9 (+ 2) \hhline{>{\arrayrulecolor{DarkBackground}}--} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Template-driven Form (implicit controls)}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{\textless{}form {\bf{\#f="ngForm" (ngSubmit)="onSubmit(f.form)"}}\textgreater{} \newline \textless{}div class="form-group"\textgreater{} \newline \textless{}label for="name"\textgreater{}Name\textless{}/label\textgreater{} \newline \newline \textless{}!-{}- Input field -{}-\textgreater{} \newline \textless{}input {\bf{ngControl="name" \#name="ngForm"}} \newline class="form-control" \newline name="name" type="text" \newline {\bf{required minlength="3"}} \newline /\textgreater{} \newline \newline \textless{}!-{}- Error messages -{}-\textgreater{} \newline \textless{}div {\bf{ {\emph{ngIf="name.touched \&\& name.errors"}}\textgreater{} \newline \textless{}div class="alert alert-danger" {\bf{ }}ngIf="name.errors.required"}}\textgreater{} \newline Name is required. \newline \textless{}/div\textgreater{} \newline \textless{}div class="alert alert-danger" {\bf{ *ngIf="name.errors.minlength"}}\textgreater{} \newline Name should be minimum \{\{ {\bf{name.errors.minlength.requiredLength}}\}\} characters. \newline \textless{}/div\textgreater{} \newline \textless{}/div\textgreater{} \newline \textless{}/div\textgreater{} \newline \newline \textless{}!-{}- More input elements -{}-\textgreater{} \newline \newline \textless{}button class="btn btn-primary" type="submit" {\bf{{[}disabled{]}="!f.valid"}}\textgreater{} \newline Submit \newline \textless{}/button\textgreater{} \newline \textless{}/form\textgreater{}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{We need to create a ControlGroup for the form and a Control for each input field. This is done by assigning the attribute {\bf{ngControl="{\emph{nameOfControl}}"}}. We can assign a local variable to the Control using {\bf{\#{\emph{nameOfControl}}="ngForm"}}. \newline Implicitly generated Control objects only offer three validation rules: {\bf{required}}, {\bf{minlength}}, and {\bf{maxlength}}. \newline Each input with an ngControl directive automatically gets CSS classes assigned, e.g., {\bf{ng-touched}}, {\bf{ng-dirty}}, {\bf{ng-invalid}}.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Model-driven Form (explicit controls)}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{\textless{}form {\bf{{[}ngFormModel{]}="form" (ngSubmit)="onSubmit(f.form)"}}\textgreater{} \newline \textless{}div class="form-group"\textgreater{} \newline \textless{}label for="name"\textgreater{}Name\textless{}/label\textgreater{} \newline \newline \textless{}!-{}- Input field -{}-\textgreater{} \newline \textless{}input {\bf{ngControl="name" \#name="ngForm"}} \newline class="form-control" \newline name="name" type="text" \newline /\textgreater{} \newline \newline \textless{}!-{}- Error messages -{}-\textgreater{} \newline \textless{}div class="alert alert-danger" {\bf{ *ngIf="!name.valid"}}\textgreater{} \newline Name is required. \newline \textless{}/div\textgreater{} \newline \textless{}/div\textgreater{} \newline \newline \textless{}!-{}- More input elements -{}-\textgreater{} \newline \newline \textless{}button class="btn btn-primary" type="submit" {\bf{{[}disabled{]}="!f.valid"}}\textgreater{} \newline Submit \newline \textless{}/button\textgreater{} \newline \textless{}/form\textgreater{} \newline \newline \newline The typescript file: \newline \newline import \{Component\} from 'angular2/core'; \newline {\bf{import \{ControlGroup, Control, Validators\} from 'angular2/common';}} \newline \newline @Component(\{ \newline selector: 'my-form', \newline templateUrl: 'my-form.component.html' \newline \}) \newline export class MyFormComponent \{ \newline \newline {\bf{form = new ControlGroup(\{}} \newline {\bf{ name : new Control('initial value', Validators.required)}} \newline // one control for each input \newline {\bf{\});}} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{Model-driven forms are similar to template-driven ones, but we need to create a {\bf{ControlGroup}} with a {\bf{Control}} for each input explicitly in the typescript class. Also, the form is bound through the directive {\bf{{[}ngFormModel{]}}}.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Creating custom validators}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{import \{Control\} from 'angular2/common'; \newline \newline export class MyValidators \{ \newline // synchronous validator \newline {\bf{static \seqsplit{cannotContainSpace(control:} Control) \{}} \newline if (control.value.indexOf(' ') \textless{} 0) \newline {\bf{return null; // valid}} \newline {\bf{return \{ cannotContainSpace: true \}; // invalid}} \newline \} \newline \newline // asynchronous validator \newline {\bf{static shouldBeUnique(control: Control) \{}} \newline {\bf{return new Promise((resolve, reject) =\textgreater{} \{}} \newline // simulating server call \newline setTimeout(function() \{ \newline if (control.value == "duplicate") \newline {\bf{resolve(\{ shouldBeUnique: true\}); // validation fails}} \newline else \newline {\bf{resolve null; // validation passes}} \newline \},1000); \newline \}); \newline \} \newline \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{Validators are static methods that return null in case of a passing validation and an object with the name of the validation rule as key and any additional information as value. Asynchronous validators return a promise instead of the object directly. In case validation depends on several inputs, we can pass the {\bf{ControlGroup}} instead of {\bf{Control}} and add the validator to the form.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Performing validation on submit}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{... \newline signUp() \{ \newline var result = \seqsplit{authService.login(this.form.value);} // call some authentication service \newline if (result.error) \{ \newline {\bf{this.form.find('username').setErrors(\{}} \newline {\bf{ invalidLogin: true}} \newline {\bf{\});}} \newline \} \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{17.67cm}}{\bf\textcolor{white}{Dirty checking}} \tn \SetRowColor{LightBackground} \mymulticolumn{1}{x{17.67cm}}{{\bf{import \{CanDeactivate, ComponentInstruction\} from 'angular2/router';}} \newline ... \newline export class MyComponent {\bf{implements CanDeactivate}} \{ \newline \newline form : ControlGroup; \newline \newline {\bf{routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : boolean \{}} \newline if (!this.form.dirty) \newline return true; \newline {\bf{return confirm('You have unsaved changes. Are you sure to leave?');}} \newline \} \newline \newline \}} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{8.4623 cm} x{8.8077 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{17.67cm}}{\bf\textcolor{white}{Reactive Extensions / Observables}} \tn % Row 0 \SetRowColor{LightBackground} Common imports & import \{Observable\} from 'rxjs/Rx';\{\{nl\}\}import \seqsplit{'rxjs/add/operator/map';} \tn % Row Count 4 (+ 4) % Row 1 \SetRowColor{white} Creating observable from control group & \seqsplit{this.form.valueChanges} \tn % Row Count 6 (+ 2) % Row 2 \SetRowColor{LightBackground} Creating observable from control & \seqsplit{this.form.find("inputField").valueChanges} \tn % Row Count 9 (+ 3) % Row 3 \SetRowColor{white} Creating empty observable & Observable.empty() \tn % Row Count 11 (+ 2) % Row 4 \SetRowColor{LightBackground} Creating observable from object & \seqsplit{Observable.of(object)} \tn % Row Count 13 (+ 2) % Row 5 \SetRowColor{white} Creating observable from array & Observable.fromArray({[}1,2,3{]}) \tn % Row Count 15 (+ 2) % Row 6 \SetRowColor{LightBackground} Creating observable from range & Observable.range(1,3) \tn % Row Count 17 (+ 2) % Row 7 \SetRowColor{white} Creating timer using observable & \seqsplit{Observable.interval(1000)} \tn % Row Count 19 (+ 2) % Row 8 \SetRowColor{LightBackground} Creating delay using observable & \seqsplit{Observable.delay(1000)} \tn % Row Count 21 (+ 2) % Row 9 \SetRowColor{white} Fork/Joining observables & let observable1 : Observable\textless{}any\textgreater{} = Observable.of(\{ user: 'user', pass: 'pass'\}).delay(1000);\{\{nl\}\}let observable2 : Observable\textless{}any\textgreater{} = Observable.of(\{ unreadMessages: 100\}).delay(2000);\{\{nl\}\}let combined : Observable\textless{}any\textgreater{} = \seqsplit{Observable.forkJoin(observable1}, observable2);\{\{nl\}\}// returns {[}\{user: "user", pass: "pass"\}, \{unreadMessages: 100\}{]} \tn % Row Count 38 (+ 17) \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{8.4623 cm} x{8.8077 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{17.67cm}}{\bf\textcolor{white}{Reactive Extensions / Observables (cont)}} \tn % Row 10 \SetRowColor{LightBackground} Error handling & observable.subscribe(\{\{nl\}\} x =\textgreater{} console.log(x), \{\{nl\}\} e =\textgreater{} console.error(e)\{\{nl\}\}) \tn % Row Count 5 (+ 5) % Row 11 \SetRowColor{white} Retry in case of error & observable.retry(3) \tn % Row Count 7 (+ 2) % Row 12 \SetRowColor{LightBackground} Catching errors & let failedObservable : Observable\textless{}any\textgreater{} = \seqsplit{Observable.throw(new} Error("Cannot reach server"));\{\{nl\}\} failedObservable\{\{nl\}\} .catch((err) =\textgreater{} \seqsplit{Observable.of("default} data"))\{\{nl\}\} .subscribe(x =\textgreater{} console.log(x)) \tn % Row Count 18 (+ 11) % Row 13 \SetRowColor{white} Setting timeout & \seqsplit{observable.timeout(200)} \tn % Row Count 20 (+ 2) % Row 14 \SetRowColor{LightBackground} Notification on completion & // pass callback as third argument when subscribing\{\{nl\}\}observable.subscribe(\{\{nl\}\} x =\textgreater{} console.log(x), \{\{nl\}\} e =\textgreater{} console.error(e), \{\{nl\}\}() =\textgreater{} console.log("finished")\{\{nl\}\}) \tn % Row Count 29 (+ 9) \hhline{>{\arrayrulecolor{DarkBackground}}--} \SetRowColor{LightBackground} \mymulticolumn{2}{x{17.67cm}}{Angular only ships with a minimum of Rx features for performance reasons. To use more functions (e.g. "map"), we have to import it additionally to the Observable (import \seqsplit{'rxjs/add/operator/map';)}.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}--} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{6.7353 cm} x{10.5347 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{17.67cm}}{\bf\textcolor{white}{Routing}} \tn % Row 0 \SetRowColor{LightBackground} Setting up the base URL & // in index.html, directly after \textless{}head\textgreater{} tag\{\{nl\}\}\textless{}base href="/"\textgreater{} \tn % Row Count 3 (+ 3) % Row 1 \SetRowColor{white} Implementing main router & import \{RouteConfig, ROUTER\_DIRECTIVES, ROUTER\_PROVIDERS\} from '@angular/router';\{\{nl\}\}...\{\{nl\}\} directives: {[}ROUTER\_DIRECTIVES, ...{]}\{\{nl\}\}...\{\{nl\}\} ...\{\{nl\}\}@RouteConfig({[}\{\{nl\}\} \{ path: '/home', component: HomeComponent \},\{\{nl\}\} \{ path: '/user/:userId', component: UserComponent \},\{\{nl\}\}...\{\{nl\}\}{]})\{\{nl\}\}\{\{nl\}\} constructor(private router: Router) \{\}\{\{nl\}\}\{\{nl\}\}ngOnInit() \{ // default route\{\{nl\}\} this.router.navigate({[}'/home'{]});\{\{nl\}\} \} \tn % Row Count 22 (+ 19) % Row 2 \SetRowColor{LightBackground} Catch-all route & \{ path: '*', redirectTo: {[}'/home'{]} \} \tn % Row Count 24 (+ 2) % Row 3 \SetRowColor{white} Use route & \textless{}router-outlet\textgreater{}\textless{}/router-outlet\textgreater{} \tn % Row Count 26 (+ 2) % Row 4 \SetRowColor{LightBackground} Create router links & import \{ROUTER\_DIRECTIVES\} from '@angular/router';\{\{nl\}\}...\{\{nl\}\}directives: {[}ROUTER\_DIRECTIVES{]}\{\{nl\}\}...\{\{nl\}\}\textless{}a {[}routerLink{]}="{[}'/home', params{]}"\textgreater{}Go Home\textless{}/a\textgreater{}\{\{nl\}\}\textless{}a {[}routerLink{]}="{[}'/user', \{ "userId": userId \} {]}"\textgreater{}Go to user page\textless{}/a\textgreater{} \tn % Row Count 36 (+ 10) \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{17.67cm}{x{6.7353 cm} x{10.5347 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{17.67cm}}{\bf\textcolor{white}{Routing (cont)}} \tn % Row 5 \SetRowColor{LightBackground} Manually trigger route & import \{Router\} from '@angular/router';\{\{nl\}\}...\{\{nl\}\}this.router.navigate({[}'/home'{]});\{\{nl\}\}this.router.navigate({[}'/user', \{userId : user.id \}{]}); \tn % Row Count 7 (+ 7) % Row 6 \SetRowColor{white} Using parameterized router & \textless{}a {[}routerLink{]}="{[}'/user', \{userId: user.id\}{]}"\textgreater{}\{\{nl\}\}\{\{nl\}\}constructor(..., routeParams: RouteParams) \{\{\{nl\}\} \seqsplit{this.userId=routeParams.get("userId");} \tn % Row Count 14 (+ 7) \hhline{>{\arrayrulecolor{DarkBackground}}--} \end{tabularx} \par\addvspace{1.3em} \end{document}