docs(style-guide): revisions for New World (repack)

closes #1260
This commit is contained in:
Foxandxss 2016-05-02 09:58:30 -07:00 committed by Ward Bell
parent cadd6c9823
commit 3f50248940
77 changed files with 271 additions and 322 deletions

View File

@ -1,5 +1,4 @@
// #docregion
/* recommended */
// app.component.ts
import { Component } from '@angular/core';

View File

@ -1,5 +1,4 @@
// #docregion
/* recommended */
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';

View File

@ -1,93 +0,0 @@
// #docplaster
// #docregion 01-01-1
/* avoid */
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<pre>{{heroes | json}}</pre>
`,
styleUrls: ['app/app.component.css']
})
export class AppComponent implements OnInit{
title = 'Tour of Heroes';
heroes: Hero[] = [];
ngOnInit() {
getHeroes().then(heroes => this.heroes = heroes);
}
}
bootstrap(AppComponent, []);
function getHeroes() {
return // some promise of data;
}
// #enddocregion 01-01-1
// #docregion 01-01-2
/* recommended */
// main.ts
import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
bootstrap(AppComponent, []);
/* recommended */
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
@Component({
selector: 'my-app',
template: `
<pre>{{heroes | json}}</pre>
`,
styleUrls: ['app/app.component.css'],
providers: [HeroService]
})
export class AppComponent implements OnInit{
heroes: Hero[] = [];
constructor(private heroService: HeroService) {}
ngOnInit() {
this.heroService.getHeroes()
.then(heroes => this.heroes = heroes);
}
}
// #enddocregion 01-01-2
// #docregion 01-01-3
/* recommended */
// hero.service.ts
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
@Injectable()
export class HeroService {
getHeroes() {
return Promise.resolve(HEROES);
}
}
// #enddocregion 01-01-3
// #docregion 01-01-4
/* recommended */
// hero.ts
export class Hero {
id: number;
name: string;
}
// #enddocregion 01-01-4

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import { Directive } from 'angular2/core';
import { Directive } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
// #docregion example

View File

@ -1,5 +1,5 @@
// #docregion
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
// #docregion example

View File

@ -2,7 +2,7 @@
// #docregion example
/* avoid */
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
import { IHero } from './hero.model.avoid';

View File

@ -1,6 +1,6 @@
// #docregion
// #docregion example
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
import { Hero } from './hero.model';

View File

@ -2,7 +2,7 @@
// #docregion example
/* avoid */
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ToastService {

View File

@ -1,6 +1,6 @@
// #docregion
// #docregion example
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ToastService {

View File

@ -2,8 +2,8 @@
// #docregion example
/* avoid */
import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Injectable} from '@angular/core';
import {Http, Response} from '@angular/http';
import {Hero} from './hero.model';
import {ExceptionService, SpinnerService, ToastService} from '../../shared';

View File

@ -1,7 +1,7 @@
// #docregion
// #docregion example
import { Injectable } from 'angular2/core';
import { Http, Response } from 'angular2/http';
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Hero } from './hero.model';
import { ExceptionService, SpinnerService, ToastService } from '../../shared';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ExceptionService { }

View File

@ -1,4 +1,4 @@
import {Component, OnDestroy, OnInit} from 'angular2/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { SpinnerService } from './spinner.service';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
export interface ISpinnerState { }

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { ToastService } from './toast.service';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ToastService {

View File

@ -2,9 +2,9 @@
// #docregion example
/* avoid */
import { ExceptionService, SpinnerService, ToastService } from '../../../app/shared';
import { Http, Response } from 'angular2/http';
import { Injectable } from 'angular2/core';
import { ExceptionService, SpinnerService, ToastService } from '../../shared';
import { Http, Response } from '@angular/http';
import { Injectable } from '@angular/core';
import { Hero } from './hero.model';
// #enddocregion example

View File

@ -1,10 +1,10 @@
// #docregion
// #docregion example
import { Injectable } from 'angular2/core';
import { Http, Response } from 'angular2/http';
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Hero } from './hero.model';
import { ExceptionService, SpinnerService, ToastService } from '../../../app/shared';
import { ExceptionService, SpinnerService, ToastService } from '../../shared';
// #enddocregion example
@Injectable()

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ExceptionService { }

View File

@ -1,4 +1,4 @@
import {Component, OnDestroy, OnInit} from 'angular2/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { SpinnerService } from './spinner.service';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
export interface ISpinnerState { }

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { ToastService } from './toast.service';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ToastService {

View File

@ -2,7 +2,7 @@
// #docregion example
/* avoid */
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { CONFIG } from '../shared/config';
import { EntityService } from '../shared/entity.service';

View File

@ -1,7 +1,7 @@
// #docplaster
// #docregion
// #docregion example
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import {
CONFIG,

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
import { HeroesComponent } from './+heroes/index';

View File

@ -1,4 +1,4 @@
import {Injectable} from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class EntityService { }

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ExceptionService { }

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Output } from 'angular2/core';
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
moduleId: module.id,

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class FilterService {

View File

@ -1,4 +1,4 @@
import { Pipe, PipeTransform } from 'angular2/core';
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'initCaps' })
export class InitCapsPipe implements PipeTransform {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { ModalService } from './modal.service';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ModalService {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { ModalService } from '../';

View File

@ -1,4 +1,4 @@
import {Component, OnDestroy, OnInit} from 'angular2/core';
import {Component, OnDestroy, OnInit} from '@angular/core';
import { SpinnerService } from './spinner.service';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
export interface ISpinnerState { }

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { ToastService } from './toast.service';

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class ToastService {

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
import { HeroesComponent } from './+heroes';

View File

@ -1,5 +1,5 @@
// #docregion
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { Hero } from './shared/hero.model';
// #docregion example

View File

@ -1,5 +1,5 @@
// #docregion
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class Logger {

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
import { HeroesComponent } from './+heroes';

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
import { HeroesComponent } from './+heroes';

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,3 +1,4 @@
<!-- #docregion -->
<!-- avoid -->
<div tohHeroButton></div>

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,6 @@
// #docregion
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
import { Hero } from './shared/hero.model';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import { Component, EventEmitter } from 'angular2/core';
import { Component, EventEmitter } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Component, EventEmitter, Input, Output } from '@angular/core';
// #docregion example
@Component({

View File

@ -1,4 +1,5 @@
<!-- #docregion -->
<!-- avoid -->
<toh-hero-button labelAttribute="OK" (changeEvent)="doSomething()">
</toh-hero-button>

View File

@ -1,5 +1,5 @@
// #docregion
import { Component, Input, Output, EventEmitter } from 'angular2/core';
import { Component, EventEmitter, Input, Output } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Component, EventEmitter, Input, Output } from '@angular/core';
// #docregion example
@Component({

View File

@ -1,7 +1,8 @@
// #docregion
import { OnInit } from 'angular2/core';
import { OnInit } from '@angular/core';
// #docregion example
/* avoid */
export class ToastComponent implements OnInit {
private defaults = {

View File

@ -42,4 +42,4 @@ export class ToastComponent implements OnInit {
window.setTimeout(() => this.hide(), 2500);
}
}
// #endregion example
// #enddocregion example

View File

@ -1,8 +1,8 @@
// #docregion
/* avoid */
import { OnInit } from 'angular2/core';
import { Http, Response } from 'angular2/http';
import { OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Hero } from '../shared/hero.model';
@ -18,7 +18,7 @@ export class HeroListComponent implements OnInit {
.map((response: Response) => <Hero[]>response.json().data)
.catch(this.catchBadResponse)
.finally(() => this.hideSpinner())
.subscribe(heroes => this.heroes = heroes);
.subscribe((heroes: Hero[]) => this.heroes = heroes);
}
ngOnInit() {
this.getHeroes();

View File

@ -1,3 +1,4 @@
<!-- #docregion -->
<!-- avoid -->
<toh-hero (onSavedTheDay)="onSavedTheDay($event)"></toh-hero>

View File

@ -1,5 +1,5 @@
// #docregion
import { Component, Output, EventEmitter } from 'angular2/core';
import { Component, EventEmitter, Output } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import { Component, Output, EventEmitter } from '@angular/core';
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'toh-hero',

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
import { Hero } from '../shared/hero.model';
// #docregion example

View File

@ -0,0 +1,2 @@
<!-- #docregion -->
<div [tohHightlight]>Bombasta</div>

View File

@ -0,0 +1,13 @@
// #docregion
import { Directive, HostListener } from '@angular/core';
// #docregion example
@Directive({
selector: '[tohHighlight]'
})
export class HighlightDirective {
@HostListener('mouseover') onMouseEnter() {
// do highlight work
}
}
// #enddocregion example

View File

@ -1,5 +1,5 @@
// #docregion
import { Directive, HostBinding, HostListener } from 'angular2/core';
import { Directive, HostBinding, HostListener } from '@angular/core';
// #docregion example
/* avoid */
@ -17,5 +17,4 @@ export class ValidatorDirective {
// do work
}
}
export class ValidateDirective { }
// #enddocregion example

View File

@ -1,5 +1,5 @@
// #docregion
import { Directive, HostBinding, HostListener } from 'angular2/core';
import { Directive, HostBinding, HostListener } from '@angular/core';
// #docregion example
@Directive({
@ -11,5 +11,4 @@ export class ValidatorDirective {
// do work
}
}
export class ValidateDirective { }
// #enddocregion example

View File

@ -1,6 +1,6 @@
// #docregion
import { Inject } from 'angular2/core';
import { Http } from 'angular2/http';
import { Inject } from '@angular/core';
import { Http } from '@angular/http';
import { HeroService } from './hero.service';
// #docregion example

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from 'angular2/core';
import { Component } from '@angular/core';
// #docregion example
/* avoid */

View File

@ -1,5 +1,5 @@
// #docregion
import {Component, OnInit} from '@angular/core';
import { Component, OnInit } from '@angular/core';
// #docregion example
@Component({

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'toh-dashboard',

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'toh-heroes',

View File

@ -1,4 +1,4 @@
import { Injectable } from 'angular2/core';
import { Injectable } from '@angular/core';
@Injectable()
export class HeroService {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from 'angular2/core';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'toh-nav',

View File

@ -56,7 +56,13 @@
"nextable": true,
"basics": true
},
"style-guide": {
"title": "Style Guide",
"intro": "Write Angular 2 with style.",
"basics": true
},
"attribute-directives": {
"title": "Attribute Directives",
"intro": "Attribute directives attach behavior to elements."
@ -66,7 +72,7 @@
"title": "Component Styles",
"intro": "Learn how to apply CSS styles to components."
},
"hierarchical-dependency-injection": {
"title": "Hierarchical Dependency Injectors",
"navTitle": "Hierarchical Injectors",
@ -103,13 +109,7 @@
"title": "Structural Directives",
"intro": "Angular has a powerful template engine that lets us easily manipulate the DOM structure of our elements."
},
"style-guide": {
"title": "Style Guide",
"intro": "Write Angular 2 with style.",
"hide": true
},
"testing": {
"title": "Testing",
"intro": "Techniques and practices for testing an Angular 2 app",
@ -121,7 +121,7 @@
"intro": "TypeScript configuration for Angular 2 developers",
"hide": true
},
"upgrade": {
"title": "Upgrading from 1.x",
"intro": "Angular 1 applications can be incrementally upgraded to Angular 2.",

View File

@ -56,7 +56,13 @@
"nextable": true,
"basics": true
},
"style-guide": {
"title": "Style Guide",
"intro": "Write Angular 2 with style.",
"basics": true
},
"attribute-directives": {
"title": "Attribute Directives",
"intro": "Attribute directives attach behavior to elements."
@ -66,7 +72,7 @@
"title": "Component Styles",
"intro": "Learn how to apply CSS styles to components."
},
"hierarchical-dependency-injection": {
"title": "Hierarchical Dependency Injectors",
"navTitle": "Hierarchical Injectors",
@ -102,13 +108,7 @@
"title": "Structural Directives",
"intro": "Angular has a powerful template engine that lets us easily manipulate the DOM structure of our elements."
},
"style-guide": {
"title": "Style Guide",
"intro": "Write Angular 2 with style.",
"hide": true
},
"testing": {
"title": "Testing",
"intro": "Techniques and practices for testing an Angular 2 app",
@ -120,7 +120,7 @@
"intro": "TypeScript configuration for Angular 2 developers",
"hide": true
},
"upgrade": {
"title": "Upgrading from 1.x",
"intro": "Angular 1 applications can be incrementally upgraded to Angular 2."

View File

@ -57,6 +57,12 @@
"basics": true
},
"style-guide": {
"title": "Style Guide",
"intro": "Write Angular 2 with style.",
"basics": true
},
"attribute-directives": {
"title": "Attribute Directives",
"intro": "Attribute directives attach behavior to elements."
@ -103,12 +109,6 @@
"intro": "Angular has a powerful template engine that lets us easily manipulate the DOM structure of our elements."
},
"style-guide": {
"title": "Style Guide",
"intro": "Write Angular 2 with style.",
"hide": true
},
"testing": {
"title": "Testing",
"intro": "Techniques and practices for testing an Angular 2 app"

View File

@ -1,7 +1,7 @@
include ../_util-fns
:marked
Welcome to the Angular 2 Guide of Style (version 6)
Welcome to the Angular 2 Style Guide
## Purpose
@ -14,33 +14,33 @@ include ../_util-fns
## Style Vocabulary
Each guideline describes either a good or bad practice, and all have a consistent presentation.
The wording of each guideline indicates how strong the recommendation is.
.s-rule.do
:marked
**Do** is one that should always be followed.
_Always_ might be a bit too strong a word.
Guidelines that literally should always be followed are extremely rare.
**Do** is one that should always be followed.
_Always_ might be a bit too strong of a word.
Guidelines that literally should always be followed are extremely rare.
On the other hand, we need a really unusual case for breaking a *Do* guideline.
.s-rule.consider
:marked
**Consider** guidelines should generally be followed.
**Consider** guidelines should generally be followed.
If you fully understand the meaning behind the guideline and have a good reason to deviate, then do so. Please strive to be consistent.
.s-rule.avoid
:marked
**Avoid** indicates something we should almost never do. Code examples to *avoid* have an unmistakeable red header.
.l-main-section
:marked
## File Structure Conventions
Some code examples display a file that has one or more similarly named companion files. (e.g. hero.component.ts and hero.component.html).
The guideline will use the shortcut `hero.component.ts|html|css|spec` to represent that various files. This makes this guide's file structures easier to read and more terse.
Some code examples display a file that has one or more similarly named companion files. (e.g. hero.component.ts and hero.component.html).
The guideline will use the shortcut `hero.component.ts|html|css|spec` to represent those various files. Using this shortcut makes this guide's file structures easier to read and more terse.
.l-main-section
a(id='toc')
@ -63,7 +63,7 @@ a(id='toc')
:marked
## Single Responsibility
We apply the [Single Responsibility Principle](https:\/\/en.wikipedia.org/wiki/Single_responsibility_principle) to all Components, Services, and other symbols we create. This helps make our app cleaner, easier to read and maintain, and more testable.
We apply the [Single Responsibility Principle](https:\/\/en.wikipedia.org/wiki/Single_responsibility_principle) to all Components, Services, and other symbols we create. This helps make our app cleaner, easier to read and maintain, and more testable.
### Rule of One
<a id="01-01"></a>
@ -89,7 +89,7 @@ a(id='toc')
**Why?** A single component can be the default export for its file which facilitates lazy loading with the Component Router.
:marked
The key is to make the code more reusable, easier to read, and less mistake prone.
The following *negative* example defines the `AppComponent`, bootstraps the app, defines the `Hero` model object, and loads heroes from the server ... all in the same file. *Don't do this*.
+makeExample('style-guide/ts/01-01/app/heroes/hero.component.avoid.ts', '', 'app/heroes/hero.component.ts')(avoid=1)
@ -101,13 +101,13 @@ a(id='toc')
style-guide/ts/01-01/app/app.component.ts,
style-guide/ts/01-01/app/heroes/heroes.component.ts,
style-guide/ts/01-01/app/heroes/shared/hero.service.ts,
style-guide/ts/01-01/app/heroes/shared/hero.model.ts,
style-guide/ts/01-01/app/heroes/shared/hero.model.ts,
style-guide/ts/01-01/app/heroes/shared/mock-heroes.ts`,
'',
`app/main.ts,
app/app.component.ts,
app/heroes/heroes.component.ts,
app/heroes/shared/hero.service.ts,
`app/main.ts,
app/app.component.ts,
app/heroes/heroes.component.ts,
app/heroes/shared/hero.service.ts,
app/heroes/shared/hero.model.ts,
app/heroes/shared/mock-heroes.ts`)
@ -124,7 +124,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** define small functions
.s-rule.consider
:marked
**Consider** limiting to no more than 75 lines.
@ -155,7 +155,7 @@ a(href="#toc") Back to top
:marked
## Naming
Naming conventions are hugely important to maintainbility and readability. This guide will recommend naming conventions for the file name and the symbol name.
Naming conventions are hugely important to maintainability and readability. This guide recommends naming conventions for the file name and the symbol name.
.l-main-section
:marked
@ -166,7 +166,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use consistent names for all symbols.
.s-rule.do
:marked
**Do** follow a pattern that describes the symbol's feature then its type. The recommended pattern is `feature.type.ts`.
@ -177,7 +177,7 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** The naming conventions should simply help we find our code faster and make it easier to understand.
**Why?** The naming conventions should simply help us find our code faster and make it easier to understand.
.s-why.s-why-last
:marked
@ -193,7 +193,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use dashes to separate words.
**Do** use dashes to separate words.
.s-rule.do
:marked
@ -245,7 +245,7 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** Upper camel case is conventional for identifying object that can be instantiated using a constructor.
**Why?** Upper camel case is conventional for identifying objects that can be instantiated using a constructor.
.s-why.s-why-last
:marked
@ -254,7 +254,7 @@ a(href="#toc") Back to top
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
@ -310,12 +310,12 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use consistent names for all services named after their feature.
**Do** use consistent names for all services named after their feature.
.s-rule.do
:marked
**Do** use upper camel case for services.
**Do** use upper camel case for services.
.s-rule.do
:marked
**Do** suffix services with `Service` when it is not clear what they are (e.g. when they are nouns).
@ -335,7 +335,7 @@ a(href="#toc") Back to top
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
@ -387,13 +387,13 @@ a(href="#toc") Back to top
.s-why.s-why-last
:marked
**Why?** Follows a familar convention from other technology platforms.
**Why?** Follows a familiar convention from other technology platforms.
a(href="#toc") Back to top
.l-main-section
:marked
### Use lower camel case for Directive Selectors
### Directive Selectors
<a id="02-06"></a>
#### Style 02-06
@ -420,18 +420,18 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use a custom prefix for the selector of our components. For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the prefix `admin` represents an admin feature area.
.s-rule.do
:marked
**Do** use a prefix that identifies the feature area or the app itself.
**Do** use a prefix that identifies the feature area or the app itself.
.s-why
:marked
**Why?** Prevents name collisions.
.s-why
:marked
**Why?** Makes it easier to promote and share our feature in other apps.
**Why?** Makes it easier to promote and share our feature in other apps.
.s-why.s-why-last
:marked
@ -456,7 +456,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use a custom prefix for the selector of our directives (for instance below is used the prefix `toh` from **T**our **o**f **H**eroes).
**Do** use a custom prefix for the selector of our directives (for instance below we use the prefix `toh` from **T**our **o**f **H**eroes).
.s-why
:marked
@ -491,7 +491,7 @@ a(href="#toc") Back to top
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
@ -524,7 +524,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** name test specification files the same as the component they test.
.s-rule.do
:marked
**Do** name test specification files with a suffix of `.spec`.
@ -541,7 +541,7 @@ a(href="#toc") Back to top
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
@ -603,7 +603,7 @@ a(href="#toc") Back to top
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
@ -634,8 +634,8 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use upper camel case when naming classes.
**Do** use upper camel case when naming classes.
.s-why
:marked
**Why?** Follows conventional thinking for class names.
@ -660,8 +660,8 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use uppercase with underscores when naming constants.
**Do** use uppercase with underscores when naming constants.
.s-why
:marked
**Why?** Follows conventional thinking for constants.
@ -686,15 +686,15 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** name an interface using upper camel case.
**Do** name an interface using upper camel case.
.s-rule.do
:marked
**Consider** naming an interface without an `I` prefix.
**Consider** naming an interface without an `I` prefix.
.s-why.s-why-last
:marked
**Why?** When we use types, we can often simply use the class as the type.
**Why?** When we use types, we can often simply use the class as the type.
+makeExample('style-guide/ts/03-03/app/shared/hero-collector.service.avoid.ts', 'example', 'app/shared/hero-collector.service.ts')(avoid=1)
:marked
@ -712,23 +712,23 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use lower camel case to name properties and methods.
**Do** use lower camel case to name properties and methods.
.s-rule.avoid
:marked
**Avoid** prefixing private properties and methods with an underscore.
**Avoid** prefixing private properties and methods with an underscore.
.s-why
:marked
**Why?** Follows conventional thinking for properties and methods.
.s-why
:marked
**Why?** JavaScript lacks a true private property or method.
**Why?** JavaScript lacks a true private property or method.
.s-why.s-why-last
:marked
**Why?** TypeScript tooling makes it easy to identify private vs public properties and methods.
**Why?** TypeScript tooling makes it easy to identify private vs public properties and methods.
+makeExample('style-guide/ts/03-04/app/shared/toast/toast.service.avoid.ts', 'example', 'app/shared/toast/toast.service.ts')(avoid=1)
:marked
@ -746,11 +746,11 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** leave one whitespace character inside of the `import` statements' curly braces when destructuring.
**Do** leave one whitespace character inside of the `import` statements' curly braces when destructuring.
.s-why.s-why-last
:marked
**Why?** Whitespace makes it easier to read the imports.
**Why?** Whitespace makes it easier to read the imports.
+makeExample('style-guide/ts/03-05/app/+heroes/shared/hero.service.avoid.ts', 'example', 'app/+heroes/shared/hero.service.ts')(avoid=1)
:marked
@ -768,19 +768,19 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** leave one empty line between third party imports and imports of code we created.
.s-rule.do
:marked
**Do** list import lines alphabetized by the module.
**Do** leave one empty line between third party imports and imports of code we created.
.s-rule.do
:marked
**Do** list destructured imported assets alphabetized.
**Do** list import lines alphabetized by the module.
.s-rule.do
:marked
**Do** list destructured imported assets alphabetically.
.s-why
:marked
**Why?** The empty line makes it easy to read and locate imports.
**Why?** The empty line makes it easy to read and locate imports.
.s-why.s-why-last
:marked
@ -798,9 +798,9 @@ a(href="#toc") Back to top
:marked
## Application Structure
Have a near term view of implementation and a long term vision. Start small but keep in mind on where the app is heading down the road.
All of the app's code goes in a root folder named `app`. All content is 1 feature per file. Each component, service, pipe is in its own file. All 3rd party vendor scripts are stored in another root folder and not in the `app` folder. We didn't write them and we don't want them cluttering our app. Use the naming conventions for file in this guide.
Have a near term view of implementation and a long term vision. Start small but keep in mind where the app is heading down the road.
All of the app's code goes in a folder named `app`. All content is 1 feature per file. Each component, service, and pipe is in its own file. All 3rd party vendor scripts are stored in another folder and not in the `app` folder. We didn't write them and we don't want them cluttering our app. Use the naming conventions for files in this guide.
a(href="#toc") Back to top
@ -812,8 +812,8 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** structure the app such that we can `L`ocate our code quickly, `I`dentify the code at a glance, keep the `F`lattest structure we can, and `T`ry to stay DRY.
**Do** structure the app such that we can `L`ocate our code quickly, `I`dentify the code at a glance, keep the `F`lattest structure we can, and `T`ry to be DRY.
.s-rule.do
:marked
**Do** define the structure to follow these four basic guidelines, listed in order of importance.
@ -853,11 +853,11 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** be descriptive with file names and keeping the contents of the file to exactly one component.
.s-rule.avoid
:marked
**Avoid** files with multiple components, multiple services, or a mixture.
**Avoid** files with multiple components, multiple services, or a mixture.
.s-why.s-why-last
:marked
**Why?** We spend less time hunting and pecking for code, and become more efficient. If this means we want longer file names, then so be it.
@ -876,28 +876,28 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** keep a flat folder structure as long as possible.
**Do** keep a flat folder structure as long as possible.
.s-rule.consider
:marked
**Consider** creating fodlers when we get to seven or more files.
.s-why.s-why-last
:marked
**Why?** Nobody wants to search 7 levels of folders to find a file. In a folder structure there is no hard and fast number rule, but when a folder has 7-10 files, that may be time to create subfolders. We base it on our comfort level. Use a flatter structure until there is an obvious value (to help the rest of LIFT) in creating a new folder.
**Why?** Nobody wants to search seven levels of folders to find a file. In a folder structure there is no hard and fast number rule, but when a folder has seven to ten files, that may be time to create subfolders. We base it on our comfort level. Use a flatter structure until there is an obvious value (to help the rest of LIFT) in creating a new folder.
a(href="#toc") Back to top
.l-main-section
:marked
### T-DRY (Try to Stick to DRY)
### T-DRY (Try to be DRY)
<a id="04-05"></a>
#### Style 04-05
.s-rule.do
:marked
**Do** be DRY
**Do** be DRY (Don't Repeat Yourself)
.s-rule.avoid
:marked
**Avoid** being so DRY that we sacrifice readability.
@ -916,23 +916,23 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** start small but keep in mind where the app is heading down the road.
**Do** start small but keep in mind where the app is heading down the road.
.s-rule.do
:marked
**Do** have a near term view of implementation and a long term vision.
**Do** have a near term view of implementation and a long term vision.
.s-rule.do
:marked
**Do** put all of the app's code in a root folder named `app`.
**Do** put all of the app's code in a folder named `app`.
.s-rule.consider
:marked
**Consider** creating a folder for each component including its `.ts`, `.html`, `.css` and `.spec` file.
**Consider** creating a folder for each component including its `.ts`, `.html`, `.css` and `.spec` file.
.s-why
:marked
**Why?** Helps keep the app small and easy to maintain in the early stages, while being easy to evolve as the app grows.
**Why?** Helps us keep the app structure small and easy to maintain in the early stages, while being easy to evolve as the app grows.
.s-why.s-why-last
:marked
@ -962,7 +962,7 @@ a(href="#toc") Back to top
.file heroes.component.ts|html|css|spec.ts
.file index.ts
.file shared
.children
.children
.file ...
.file app.component.ts|html|css|spec.ts
.file main.ts
@ -984,11 +984,11 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** put all shared files within a component feature in a `shared` folder.
**Do** put all shared files within a component feature in a `shared` folder.
.s-rule.consider
:marked
**Consider** creating a folder for each component including its `.ts`, `.html`, `.css` and `.spec` file.
**Consider** creating a folder for each component including its `.ts`, `.html`, `.css` and `.spec` file.
.s-why
:marked
@ -1023,11 +1023,11 @@ a(href="#toc") Back to top
.file heroes.component.ts|html|css|spec.ts
.file index.ts
.file shared
.children
.children
.file exception.service.ts|spec.ts
.file index.ts
.file nav
.children
.children
.file ...
.file app.component.ts|html|css|spec.ts
.file main.ts
@ -1045,8 +1045,8 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** create folders named for the feature they represent.
**Do** create folders named for the feature they represent.
.s-why
:marked
**Why?** A developer can locate the code, identify what each file represents at a glance, the structure is as flat as it can be, and there is no repetitive nor redundant names.
@ -1064,7 +1064,7 @@ a(href="#toc") Back to top
**Why?** When there are a lot of files (e.g. 10+) locating them is easier with a consistent folder structures and more difficult in flat structures.
:marked
Below is an example of a small app with folders per component.
Below is an example of a small app with folders per component.
.example-title Folders per Component
.filetree
@ -1099,7 +1099,7 @@ a(href="#toc") Back to top
.file villains.component.ts|html|css|spec.ts
.file index.ts
.file shared
.children
.children
.file nav
.children
.file ...
@ -1124,11 +1124,11 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** put shared layout components in their own folder, under the `shared` folder.
**Do** put shared layout components in their own folder, under the `shared` folder.
.s-why
:marked
**Why?** We need a place to host our layout for our app. Our navigation bar, footer, and other aspects of the app that are needed for the entire app.
**Why?** We need a place to host our layout for our app. Our navigation bar, footer, and other aspects of the app that are needed for the entire app.
.s-why.s-why-last
:marked
@ -1144,7 +1144,7 @@ a(href="#toc") Back to top
.children
.file ...
.file shared
.children
.children
.file nav
.children
.file index.ts
@ -1176,7 +1176,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** name this barrel file `index.ts`.
.s-why
:marked
**Why?** A barrel aggregates many imports into a single import.
@ -1254,7 +1254,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** put the contents of lazy loaded features in a *lazy loaded folder*.
**Do** put the contents of lazy loaded features in a *lazy loaded folder*.
A typical *lazy loaded folder* contains a *routing component*, its child components, and their related assets and modules.
.s-why.s-why-last
@ -1296,7 +1296,7 @@ a(href="#toc") Back to top
.file dashboard.component.ts|html|css|spec.ts
.file index.ts
:marked
a(href="#toc") Back to top
.l-main-section
@ -1376,7 +1376,7 @@ a(href="#toc") Back to top
`style-guide/ts/05-02/app/heroes/shared/hero-button/hero-button.component.ts,
style-guide/ts/05-02/app/app.component.html`,
'example,',
`app/heroes/shared/hero-button/hero-button.component.ts,
`app/heroes/shared/hero-button/hero-button.component.ts,
app/app.component.html`)
:marked
@ -1414,7 +1414,7 @@ a(href="#toc") Back to top
`style-guide/ts/05-03/app/heroes/shared/hero-button/hero-button.component.ts,
style-guide/ts/05-03/app/app.component.html`,
'example,',
`app/heroes/shared/hero-button/hero-button.component.ts,
`app/heroes/shared/hero-button/hero-button.component.ts,
app/app.component.html`)
:marked
@ -1454,8 +1454,8 @@ a(href="#toc") Back to top
style-guide/ts/05-04/app/heroes/heroes.component.html,
style-guide/ts/05-04/app/heroes/heroes.component.css`,
'example,,',
`app/heroes/heroes.component.ts,
app/heroes/heroes.component.html,
`app/heroes/heroes.component.ts,
app/heroes/heroes.component.html,
app/heroes/heroes.component.css`)
:marked
@ -1481,7 +1481,7 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** If we ever need to rename the name of the property, or event name associated to [`@Input`](https://angular.io/docs/ts/latest/api/core/Input-var.html) or respectively [`@Output`](https://angular.io/docs/ts/latest/api/core/Output-var.html) we can modify it on a single place.
**Why?** If we ever need to rename the property or event name associated to [`@Input`](https://angular.io/docs/ts/latest/api/core/Input-var.html) or [`@Output`](https://angular.io/docs/ts/latest/api/core/Output-var.html) we can modify it on a single place.
.s-why
:marked
@ -1523,7 +1523,7 @@ a(href="#toc") Back to top
`style-guide/ts/05-13/app/heroes/shared/hero-button/hero-button.component.ts,
style-guide/ts/05-13/app/app.component.html`,
'example,',
`app/heroes/shared/hero-button/hero-button.component.ts,
`app/heroes/shared/hero-button/hero-button.component.ts,
app/app.component.html`)
:marked
@ -1557,13 +1557,13 @@ a(href="#toc") Back to top
.l-main-section
:marked
### Defer Logic to Services
### Put Logic in Services
<a id="05-15"></a>
#### Style 05-15
.s-rule.do
:marked
**Do** defer logic in a component by delegating to services.
**Do** limit logic in a component to only that required for the view. All other logic should be delegated to services.
.s-rule.do
:marked
@ -1625,7 +1625,7 @@ a(href="#toc") Back to top
`style-guide/ts/05-16/app/heroes/hero.component.ts,
style-guide/ts/05-16/app/app.component.html`,
'example,',
`app/heroes/hero.component.ts,
`app/heroes/hero.component.ts,
app/app.component.html`)
:marked
@ -1647,7 +1647,7 @@ a(href="#toc") Back to top
.s-why.s-why-last
:marked
**Why?** Keeping the logic of the components in their controller, instead of template will improve testability, maintability, reusability.
**Why?** Keeping the component's presentation logic in the class instead of the template improves testability, maintainability, and reusability.
+makeExample('style-guide/ts/05-17/app/heroes/hero-list/hero-list.component.avoid.ts', 'example', 'app/heroes/hero-list/hero-list.component.ts')(avoid=1)
:marked
@ -1663,6 +1663,32 @@ a(href="#toc") Back to top
a(href="#toc") Back to top
.l-main-section
:marked
### Use Directives to Enhance an Existing Element
<a id="06-01"></a>
#### Style 06-01
.s-rule.do
:marked
**Do** use attribute directives when you have presentation logic without a template.
.s-why
:marked
**Why?** Attributes directives don't have an associated template.
.s-why.s-why-last
:marked
**Why?** An element may have more than one attribute directive applied.
+makeExample('style-guide/ts/06-01/app/shared/highlight.directive.ts', 'example', 'app/shared/highlight.directive.ts')
:marked
+makeExample('style-guide/ts/06-01/app/app.component.html', null, 'app/app.component.html')
:marked
a(href="#toc") Back to top
.l-main-section
:marked
### Use HostListener and HostBinding Class Decorators
@ -1675,7 +1701,7 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** The name of the property, or method name associated to @HostBinding or respectively @HostListener should be modified only in a single place - in the directive's controller. In contrast if we use host we need to modify both the property declaration inside the controller, and the metadata associated to the directive.
**Why?** The property or method name associated with @HostBinding or respectively @HostListener should be modified only in a single place - in the directive's class. In contrast if we use host we need to modify both the property declaration inside the controller, and the metadata associated to the directive.
.s-why.s-why-last
:marked
@ -1700,7 +1726,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use services as singletons within the same injector. Use them for sharing data and functionality.
.s-why
:marked
**Why?** Services are ideal for sharing methods across a feature area or an app.
@ -1722,12 +1748,12 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** create services with a single responsibility that is encapsulated by its context.
**Do** create services with a single responsibility that is encapsulated by its context.
.s-rule.do
:marked
**Do** create a new service once the service begins to exceed that singular purpose.
.s-why
:marked
**Why?** When a service has multiple responsibilities, it becomes difficult to test.
@ -1758,7 +1784,7 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** This is ideal when a service is sharing methods and has no state, or state that must be shared.
**Why?** This is ideal when a service is sharing methods or state.
.s-why.s-why-last
:marked
@ -1768,7 +1794,7 @@ a(href="#toc") Back to top
`style-guide/ts/07-03/app/app.component.ts,
style-guide/ts/07-03/app/heroes/hero-list/hero-list.component.ts`,
'',
`app/app.component.ts,
`app/app.component.ts,
app/heroes/hero-list/hero-list.component.ts`)
:marked
@ -1782,7 +1808,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use the `@Injectable` class decorator instead of the `@Inject` parameter decorator when we are using types as tokens for the dependencies of a service.
**Do** use the `@Injectable` class decorator instead of the `@Inject` parameter decorator when using types as tokens for the dependencies of a service.
.s-why
:marked
@ -1810,8 +1836,8 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** refactor logic for making data operations and interacting with data to a service.
**Do** refactor logic for making data operations and interacting with data to a service.
.s-rule.do
:marked
**Do** make data services responsible for XHR calls, local storage, stashing in memory, or any other data operations.
@ -1850,7 +1876,7 @@ a(href="#toc") Back to top
.s-why.s-why-last
:marked
**Why?** We will avoid unintentionally not calling the hook if we misspell the method.
**Why?** We avoid unintentionally not calling the hook if we misspell the method.
+makeExample('style-guide/ts/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
:marked
@ -1863,7 +1889,7 @@ a(href="#toc") Back to top
.l-main-section
:marked
## Routing
Client-side routing is important for creating a navigation flow between a component tree hierarchy, and composing components that are made of many other child components.
a(href="#toc") Back to top
@ -1884,7 +1910,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** focus the logic in the component router to the routing aspects and its target components.
**Do** focus the logic in the component router to the routing aspects and its target components.
.s-rule.do
:marked
@ -1943,7 +1969,7 @@ a(href="#toc") Back to top
.s-rule.consider
:marked
**Consider** using [snippets](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2) for [Visual Studio Code](https://code.visualstudio.com/) that follow these styles and guidelines.
**Consider** using [snippets](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2) for [Visual Studio Code](https://code.visualstudio.com/) that follow these styles and guidelines.
:marked
[![Use Extension](https://github.com/johnpapa/vscode-angular2-snippets/raw/master/images/use-extension.gif)](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2)