docs(style-guide): add style-guide - v.6

This commit is contained in:
John Papa 2016-04-30 23:11:33 -07:00 committed by Ward Bell
parent f4223c7049
commit bbd7d79a76
15 changed files with 363 additions and 176 deletions

View File

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

View File

@ -4,11 +4,12 @@ import { Injectable } from 'angular2/core';
import { Http, Response } from 'angular2/http';
import { Hero } from './hero.model';
import { ExceptionService, SpinnerService, ToastService } from '../../../app/shared';
import { ExceptionService, SpinnerService, ToastService } from '../../shared';
// #enddocregion example
@Injectable()
export class HeroService {
cachedHeroes: Hero[];
constructor(
private exceptionService: ExceptionService,

View File

@ -9,6 +9,7 @@ import { ExceptionService, SpinnerService, ToastService } from '../../../app/sha
@Injectable()
export class HeroService {
cachedHeroes: Hero[];
constructor(
private exceptionService: ExceptionService,

View File

@ -1,3 +1,4 @@
// #docplaster
// #docregion
// #docregion example
import { Component, OnInit } from 'angular2/core';
@ -10,13 +11,21 @@ import {
InitCapsPipe,
SpinnerService,
ToastService
} from '../../app/shared';
} from '../shared';
@Component({
// #enddocregion example
providers: [EntityService, ExceptionService, SpinnerService, ToastService],
directives: [FilterTextComponent],
pipes: [InitCapsPipe],
// #docregion example
selector: 'toh-heroes',
templateUrl: 'app/+heroes/heroes.component.html'
})
export class HeroesComponent implements OnInit {
// #enddocregion example
urls = CONFIG.baseUrls;
// #docregion example
constructor() { }
ngOnInit() { }

View File

@ -7,6 +7,7 @@ import { HeroesComponent } from './+heroes/index';
@Component({
selector: 'toh-app',
template: '<div>app</div>'
template: '<div>app</div>',
directives: [HeroesComponent]
})
export class AppComponent { }

View File

@ -9,7 +9,8 @@ import { Logger } from '../shared/logger.service';
@Component({
selector: 'toh-heroes',
templateUrl: 'heroes.component.html',
styleUrls: ['heroes.component.css']
styleUrls: ['heroes.component.css'],
providers: [Logger]
})
export class HeroesComponent implements OnInit {
heroes: Hero[];

View File

@ -12,7 +12,6 @@ export class ToastComponent implements OnInit {
title: string;
private toastElement: any;
ngOnInit() {
this.toastElement = document.getElementById('toh-toast');
}

View File

@ -10,26 +10,31 @@ export class ToastComponent implements OnInit {
// public properties
message: string;
title: string;
// private fields
private defaults = {
title: '',
message: 'May the Force be with You'
};
private toastElement: any;
// public methods
activate(message = this.defaults.message, title = this.defaults.title) {
this.title = title;
this.message = message;
this.show();
}
ngOnInit() {
this.toastElement = document.getElementById('toh-toast');
}
// private methods
private hide() {
this.toastElement.style.opacity = 0;
window.setTimeout(() => this.toastElement.style.zIndex = 0, 400);
}
private show() {
console.log(this.message);
this.toastElement.style.opacity = 1;

View File

@ -6,7 +6,7 @@ import { Hero } from '../shared/hero.model';
/* avoid */
@Component({
selector: 'toh-heroes-list',
selector: 'toh-hero-list',
template: `
<section>
Our list of heroes:
@ -17,7 +17,7 @@ import { Hero } from '../shared/hero.model';
</section>
`
})
export class HeroesListComponent {
export class HeroListComponent {
heroes: Hero[];
totalPowers: number;
}

View File

@ -5,7 +5,7 @@ import { Hero } from '../shared/hero.model.ts';
// #docregion example
@Component({
selector: 'toh-heroes-list',
selector: 'toh-hero-list',
template: `
<section>
Our list of heroes:
@ -16,9 +16,12 @@ import { Hero } from '../shared/hero.model.ts';
</section>
`
})
export class HeroesListComponent {
export class HeroListComponent {
heroes: Hero[];
totalPowers: number;
avgPower: number;
get avgPower() {
return this.totalPowers / this.heroes.length;
}
}
// #enddocregion example

View File

@ -2,15 +2,20 @@
import { Directive, HostBinding, HostListener } from 'angular2/core';
// #docregion example
/* avoid */
@Directive({
selector: '[tohValidator]'
selector: '[tohValidator]',
host: {
'(mouseenter)': 'onMouseEnter()',
'attr.role': 'button'
}
})
export class ValidatorDirective {
@HostBinding('attr.role') role = 'button';
@HostListener('mouseenter') onMouseEnter() {
role = 'button';
onMouseEnter() {
// do work
}
}
export class ValidateDirective { }
// #enddocregion example

View File

@ -2,18 +2,12 @@
import { Directive, HostBinding, HostListener } from 'angular2/core';
// #docregion example
/* avoid */
@Directive({
selector: '[tohValidator]',
host: {
'(mouseenter)': 'onMouseEnter()',
'attr.role': 'button'
}
selector: '[tohValidator]'
})
export class ValidatorDirective {
role = 'button';
onMouseEnter() {
@HostBinding('attr.role') role = 'button';
@HostListener('mouseenter') onMouseEnter() {
// do work
}
}

View File

@ -1,7 +1,7 @@
include ../_util-fns
:marked
Welcome to the Angular 2 Guide of Style (version 5)
Welcome to the Angular 2 Guide of Style (version 6)
## Purpose
@ -49,12 +49,13 @@ a(id='toc')
1. [Single Responsibility](#single-responsibility)
1. [Naming](#naming)
1. [Coding Conventions](#coding-conventions)
1. [Application Structure](#application-structure)
1. [Components](#components)
1. [Directives](#directives)
1. [Lifecycle Hooks](#lifecycle-hooks)
1. [Services](#services)
1. [Data Services](#data-services)
1. [Lifecycle Hooks](#lifecycle-hooks)
1. [Routing](#routing)
1. [Appendix](#appendix)
@ -83,7 +84,7 @@ a(id='toc')
:marked
**Why?** One component per file avoids hidden bugs that often arise when combining components in a file where they may share variables, create unwanted closures, or unwanted coupling with dependencies.
.s-why
.s-why.s-why-last
:marked
**Why?** A single component can be the default export for its file which facilitates lazy loading with the Component Router.
:marked
@ -132,12 +133,20 @@ a(href="#toc") Back to top
:marked
**Why?** Small functions are easier to test, especially when they do one thing and serve one purpose.
.s-why
:marked
**Why?** Small functions promote reuse.
.s-why
:marked
**Why?** Small functions are easier to read.
.s-why
:marked
**Why?** Small functions are easier to maintain.
.s-why.s-why-last
:marked
**Why?** Small functions help avoid hidden bugs that come with large functions that share variables with external scope, create unwanted closures, or unwanted coupling with dependencies.
a(href="#toc") Back to top
@ -148,7 +157,6 @@ a(href="#toc") Back to top
Naming conventions are hugely important to maintainbility and readability. This guide will recommend naming conventions for the file name and the symbol name.
.l-main-section
:marked
### General Naming Guidelines
@ -171,7 +179,7 @@ a(href="#toc") Back to top
:marked
**Why?** The naming conventions should simply help we find our code faster and make it easier to understand.
.s-why
.s-why.s-why-last
:marked
**Why?** Names of folders and files should clearly convey their intent. For example, `app/heroes/hero-list.component.ts` may contain a component that manages a list of heroes.
@ -197,7 +205,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use conventional suffixes for the types including `*.service.ts`, `*.component.ts`, `*.pipe.ts`. Invent other suffixes where desired for our team, but take care in having too many.
**Do** use conventional suffixes for the types including `*.service.ts`, `*.component.ts`, `*.pipe.ts`. Invent other suffixes where desired, but take care in having too many.
.s-why
:marked
@ -207,7 +215,7 @@ a(href="#toc") Back to top
:marked
**Why?** Provides a consistent way to quickly find a specific file using an editor or IDE's fuzzy search techniques.
.s-why
.s-why.s-why-last
:marked
**Why?** Provides pattern matching for any automated tasks.
@ -225,7 +233,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use UpperCamelCase for symbols. Match the name of the symbol to the naming of the file.
**Do** use upper camel case for symbols. Match the name of the symbol to the naming of the file.
.s-rule.do
:marked
@ -237,23 +245,60 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** UpperCamelCase is conventional for identifying object that can be instantiated using a constructor.
**Why?** Upper camel case is conventional for identifying object that can be instantiated using a constructor.
.s-why
.s-why.s-why-last
:marked
**Why?** The `Component` suffix is more commonly used and is more explicitly descriptive.
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
tr(style=top)
td
code-example.
@Component({ ... })
export class AppComponent {}
td
:marked
app.component.ts
tr(style=top)
td
code-example.
@Component({ ... })
export class HeroesComponent
td
:marked
heroes.component.ts
tr(style=top)
td
code-example.
@Component({ ... })
export class HeroListComponent
td
:marked
hero-list.component.ts
tr(style=top)
td
code-example.
@Component({ ... })
export class HeroDetailComponent
td
:marked
hero-detail.component.ts
tr(style=top)
td
code-example.
@Directive({ ... })
export class ValidationDirective
td
:marked
validation.directive.ts
:marked
```
/* recommended */
AppComponent // app.component.ts
HeroesComponent // heroes.component.ts
HeroListComponent // hero-list.component.ts
HeroDetailComponent // hero-detail.component.ts
/* recommended */
ValidationDirective // validation.directive.ts
```
a(href="#toc") Back to top
@ -269,7 +314,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** use UpperCamelCase for services.
**Do** use upper camel case for services.
.s-rule.do
:marked
@ -283,16 +328,42 @@ a(href="#toc") Back to top
:marked
**Why?** Clear service names such as `logger` do not require a suffix.
.s-why
.s-why.s-why-last
:marked
**Why?** Service names such as `Credit` are nouns and require a suffix and should be named with a suffix when it is not obvious if it is a service or something else.
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
tr(style=top)
td
code-example.
@Injectable()
export class HeroDataService {}
td
:marked
hero-data.service.ts
tr(style=top)
td
code-example.
@Injectable()
export class CreditService {}
td
:marked
credit.service.ts
tr(style=top)
td
code-example.
@Injectable()
export class LoggerService {}
td
:marked
logger.service.ts
:marked
```
HeroDataService // hero-data.service.ts
CreditService // credit.service.ts
LoggerService // logger.service.ts
```
a(href="#toc") Back to top
@ -314,7 +385,7 @@ a(href="#toc") Back to top
:marked
**Why?** Follows a consistent convention for the startup logic of an app.
.s-why
.s-why.s-why-last
:marked
**Why?** Follows a familar convention from other technology platforms.
@ -322,21 +393,21 @@ a(href="#toc") Back to top
.l-main-section
:marked
### Use lowerCamelCase for Directive Selectors
### Use lower camel case for Directive Selectors
<a id="02-06"></a>
#### Style 02-06
.s-rule.do
:marked
**Do** Use lowerCamelCase for naming the selectors of our directives.
**Do** Use lower camel case for naming the selectors of our directives.
.s-why
:marked
**Why?** Keeps the names of the properties defined in the directives that are bound to the view consistent with the attribute names.
.s-why
.s-why.s-why-last
:marked
**Why?** The Angular 2 HTML parser is case sensitive and will recognize lowerCamelCase
**Why?** The Angular 2 HTML parser is case sensitive and will recognize lower camel case.
a(href="#toc") Back to top
@ -356,20 +427,25 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** Prevents name collisions
**Why?** Prevents name collisions.
.s-why
:marked
**Why?** Our Components and elements are easily identified
<<<<<<< HEAD
**Why?** Our Components and elements are easily identified.
.s-why
=======
:marked
**Why?** Makes it easier to promoted and share our feature in other apps.
**Why?** Makes it easier to promote and share our feature in other apps.
+makeExample('style-guide/ts/02-07/app/heroes/hero.component.avoid.ts', '', 'app/heroes/hero.component.ts')(avoid=1)
>>>>>>> d76f358... merge conflict fixes
.s-why.s-why-last
:marked
**Why?** Our Components and elements are easily identified.
+makeExample('style-guide/ts/02-07/app/heroes/hero.component.avoid.ts', 'example', 'app/heroes/hero.component.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/02-07/app/users/users.component.avoid.ts', '', 'app/users/users.component.ts')(avoid=1)
+makeExample('style-guide/ts/02-07/app/users/users.component.avoid.ts', 'example', 'app/users/users.component.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/02-07/app/heroes/hero.component.ts', 'example', 'app/heroes/hero.component.ts')
@ -389,13 +465,13 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** Prevents name collisions
**Why?** Prevents name collisions.
.s-why
.s-why.s-why-last
:marked
**Why?** Our Directives are easily identified
**Why?** Our Directives are easily identified.
+makeExample('style-guide/ts/02-08/app/shared/validate.directive.avoid.ts', '', 'app/shared/validate.directive.ts')(avoid=1)
+makeExample('style-guide/ts/02-08/app/shared/validate.directive.avoid.ts', 'example', 'app/shared/validate.directive.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/02-08/app/shared/validate.directive.ts', 'example', 'app/shared/validate.directive.ts')
@ -413,15 +489,34 @@ a(href="#toc") Back to top
:marked
**Do** use consistent names for all pipes, named after their feature.
.s-why
.s-why.s-why-last
:marked
**Why?** Provides a consistent way to quickly identify and reference pipes.
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
tr(style=top)
td
code-example.
@Pipe({ name: 'ellipsis' })
export class EllipsisPipe implements PipeTransform { }
td
:marked
ellipsis.pipe.ts
tr(style=top)
td
code-example.
@Pipe({ name: 'initCaps' })
export class InitCapsPipe implements PipeTransform { }
td
:marked
init-caps.pipe.ts
:marked
```
EllipsisPipe // ellipsis.pipe.ts
InitCapsPipe // init-caps.pipe.ts
```
a(href="#toc") Back to top
@ -433,7 +528,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** name test specification files the same as the component they test
**Do** name test specification files the same as the component they test.
.s-rule.do
:marked
@ -443,29 +538,50 @@ a(href="#toc") Back to top
:marked
**Why?** Provides a consistent way to quickly identify tests.
.s-why
.s-why.s-why-last
:marked
**Why?** Provides pattern matching for [karma](http://karma-runner.github.io/) or other test runners.
:marked
```
// recommended
// Components
heroes.component.spec.ts
hero-list.component.spec.ts
hero-detail.component.spec.ts
// Services
logger.service.spec.ts
hero.service.spec.ts
exception.service.spec.ts
filter-text.service.spec.ts
// Pipes
ellipsis.pipe.spec.ts
init-caps.pipe.spec.ts
```
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
tr(style=top)
td
:marked
Components
td
:marked
heroes.component.spec.ts
:marked
hero-list.component.spec.ts
:marked
hero-detail.component.spec.ts
tr(style=top)
td
:marked
Services
td
:marked
logger.service.spec.ts
:marked
hero.service.spec.ts
:marked
filter-text.service.spec.ts
tr(style=top)
td
:marked
Pipes
td
:marked
ellipsis.pipe.spec.ts
:marked
init-caps.pipe.spec.ts
:marked
a(href="#toc") Back to top
@ -483,22 +599,35 @@ a(href="#toc") Back to top
:marked
**Why?** Provides a consistent way to quickly identify end-to-end tests.
.s-why
.s-why.s-why-last
:marked
**Why?** Provides pattern matching for test runners and build automation.
:marked
```
// recommended
app.e2e-spec.ts
heroes.e2e-spec.ts
```
:marked
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th Symbol Name
th File Name
tr(style=top)
td
:marked
End to End Tests
td
:marked
app.e2e-spec.ts
:marked
heroes.e2e-spec.ts
:marked
a(href="#toc") Back to top
.l-main-section
:marked
## TypeScript Conventions
## Coding Conventions
Have consistent set of coding, naming, and whitespace conventions.
@ -516,9 +645,9 @@ a(href="#toc") Back to top
:marked
**Why?** Follows conventional thinking for class names.
.s-why
.s-why.s-why-last
:marked
**Why?** Classes can be instantiated and construct an instance. We often use UpperCamelCase to indicate a constructable asset.
**Why?** Classes can be instantiated and construct an instance. We often use upper camel case to indicate a constructable asset.
+makeExample('style-guide/ts/03-01/app/shared/exception.service.avoid.ts', 'example', 'app/shared/exception.service.ts')(avoid=1)
:marked
@ -542,7 +671,7 @@ a(href="#toc") Back to top
:marked
**Why?** Follows conventional thinking for constants.
.s-why
.s-why.s-why-last
:marked
**Why?** Constants can easily be identified.
@ -568,7 +697,7 @@ a(href="#toc") Back to top
:marked
**Consider** naming an interface without an `I` prefix.
.s-why
.s-why.s-why-last
:marked
**Why?** When we use types, we can often simply use the class as the type.
@ -602,7 +731,7 @@ a(href="#toc") Back to top
:marked
**Why?** JavaScript lacks a true private property or method.
.s-why
.s-why.s-why-last
:marked
**Why?** TypeScript tooling makes it easy to identify private vs public properties and methods.
@ -624,7 +753,7 @@ a(href="#toc") Back to top
:marked
**Do** leave one whitespace character inside of the `import` statements' curly braces when destructuring.
.s-why
.s-why.s-why-last
:marked
**Why?** Whitespace makes it easier to read the imports.
@ -658,7 +787,7 @@ a(href="#toc") Back to top
:marked
**Why?** The empty line makes it easy to read and locate imports.
.s-why
.s-why.s-why-last
:marked
**Why?** Alphabetizing makes it easier to read and locate imports.
@ -694,7 +823,7 @@ a(href="#toc") Back to top
:marked
**Do** define the structure to follow these four basic guidelines, listed in order of importance.
.s-why
.s-why.s-why-last
:marked
**Why?** LIFT Provides a consistent structure that scales well, is modular, and makes it easier to increase developer efficiency by finding code quickly. Another way to check our app structure is to ask ourselves: How quickly can we open and work in all of the related files for a feature?
@ -710,9 +839,9 @@ a(href="#toc") Back to top
:marked
**Do** make locating our code intuitive, simple and fast.
.s-why
.s-why.s-why-last
:marked
**Why?** We find this to be super important for a project. If our team cannot find the files we need to work on quickly, we will not be able to work as efficiently as possible, and the structure needs to change. We may not know the file name or where its related files are, so putting them in the most intuitive locations and near each other saves a ton of time. A descriptive folder structure can help with this.
**Why?** We find this to be super important for a project. If we cannot find the files we need to work on quickly, we will not be able to work as efficiently as possible, and the structure needs to change. We may not know the file name or where its related files are, so putting them in the most intuitive locations and near each other saves a ton of time. A descriptive folder structure can help with this.
a(href="#toc") Back to top
@ -734,7 +863,7 @@ a(href="#toc") Back to top
:marked
**Avoid** files with multiple components, multiple services, or a mixture.
.s-why
.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.
@ -758,7 +887,7 @@ a(href="#toc") Back to top
:marked
**Consider** creating fodlers when we get to seven or more files.
.s-why
.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.
@ -778,7 +907,7 @@ a(href="#toc") Back to top
:marked
**Avoid** being so DRY that we sacrifice readability.
.s-why
.s-why.s-why-last
:marked
**Why?** Being DRY is important, but not crucial if it sacrifices the others in LIFT, which is why we call it T-DRY. We dont want to type `hero-view.component.html` for a view because, well, its obviously a view. If it is not obvious or by convention, then we name it.
@ -810,10 +939,11 @@ a(href="#toc") Back to top
:marked
**Why?** Helps keep the app small and easy to maintain in the early stages, while being easy to evolve as the app grows.
.s-why
.s-why.s-why-last
:marked
**Why?** Components often have four files (e.g. `*.html`, `*.css`, `*.ts`, and `*.spec.ts`) and can clutter a folder quickly.
.example-title Overall Folder and File Structure
.filetree
.file src
.children
@ -869,10 +999,11 @@ a(href="#toc") Back to top
:marked
**Why?** Separates shared files from the components within a feature.
.s-why
.s-why.s-why-last
:marked
**Why?** Makes it easier to locate shared files within a component feature.
.example-title Shared Folder
.filetree
.file src
.children
@ -923,7 +1054,7 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** A developer can locate the code, identify what each file represents at a glance, the structure is flat as can be, and there is no repetitive nor redundant names.
**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.
.s-why
:marked
@ -933,13 +1064,14 @@ a(href="#toc") Back to top
:marked
**Why?** Helps reduce the app from becoming cluttered through organizing the content and keeping them aligned with the LIFT guidelines.
.s-why
.s-why.s-why-last
:marked
**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.
.example-title Folders per Component
.filetree
.file src
.children
@ -1003,10 +1135,11 @@ a(href="#toc") Back to top
: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.
.s-why
.s-why.s-why-last
:marked
**Why?** Organizes all layout in a consistent place re-used throughout the application.
.example-title Folder for Layout Components
.filetree
.file src
.children
@ -1047,7 +1180,7 @@ a(href="#toc") Back to top
.s-rule.do
:marked
**Do** name this barrel file `index.ts`
**Do** name this barrel file `index.ts`.
.s-why
:marked
@ -1057,7 +1190,7 @@ a(href="#toc") Back to top
:marked
**Why?** A barrel reduces the number of imports a file may need.
.s-why
.s-why.s-why-last
:marked
**Why?** A barrel shortens import statements.
@ -1069,14 +1202,15 @@ a(href="#toc") Back to top
style-guide/ts/04-10/app/shared/spinner/index.ts,
style-guide/ts/04-10/app/shared/toast/index.ts`,
`example,,,,,`,
`app/heroes/shared/index.ts,
app/heroes/shared/filter-text/index.ts,
app/heroes/shared/modal/index.ts,
app/heroes/shared/nav/index.ts,
app/heroes/shared/spinner/index.ts,
app/heroes/shared/toast/index.ts`)
`app/shared/index.ts,
app/shared/filter-text/index.ts,
app/shared/modal/index.ts,
app/shared/nav/index.ts,
app/shared/spinner/index.ts,
app/shared/toast/index.ts`)
:marked
.example-title Folder Barrels
.filetree
.file src
.children
@ -1128,7 +1262,7 @@ a(href="#toc") Back to top
**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.s-why-last
:marked
**Why?** The folder makes it easy to identify and isolate the feature content.
@ -1152,10 +1286,11 @@ a(href="#toc") Back to top
:marked
**Why?** Lazy loaded code paths are easily distinguishable from non lazy loaded paths.
.s-why
.s-why.s-why-last
:marked
**Why?** If we see an `import` path that contains a `+`, we can quickly refactor to use lazy loading.
.example-title Lazy Loaded Folders
.filetree
.file src
.children
@ -1179,7 +1314,7 @@ a(href="#toc") Back to top
:marked
**Avoid** allowing modules in sibling and parent folders to directly import a module in a *lazy loaded feature*.
.s-why
.s-why.s-why-last
:marked
**Why?** Directly importing a module loads it immediately when our intention is to load it on demand.
@ -1198,14 +1333,13 @@ a(href="#toc") Back to top
:marked
**Do** allow lazy loaded modules to import a module from a parent folder.
.s-why
.s-why.s-why-last
:marked
**Why?** A parent module has already been loaded by the time the lazy loaded module imports it.
+makeExample('style-guide/ts/04-14/app/heroes/heroes.component.ts', 'example', 'app/heroes/heroes.component.ts')
:marked
a(href="#toc") Back to top
.l-main-section
@ -1218,7 +1352,7 @@ a(href="#toc") Back to top
:marked
**Do** use the Component Router to lazy load routable features.
.s-why
.s-why.s-why-last
:marked
**Why?** That's the easiest way to load a module on demand.
@ -1236,11 +1370,11 @@ a(href="#toc") Back to top
:marked
**Do** use `kebab-case` for naming the element selectors of our components.
.s-why
.s-why.s-why-last
:marked
**Why?** Keeps the element names consistent with the specification for [Custom Elements](https://www.w3.org/TR/custom-elements/).
+makeExample('style-guide/ts/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts', '', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
+makeExample('style-guide/ts/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
:marked
+makeTabs(
@ -1271,11 +1405,11 @@ a(href="#toc") Back to top
:marked
**Why?** Components are derived from Directives, and thus their selectors can be elements, attributes, or other selectors. Defining the selector as an element provides consistency for components that represent content with a template.
.s-why
.s-why.s-why-last
:marked
**Why?** It is easier to recognize that a symbol is a component vs a directive by looking at the template's html.
+makeExample('style-guide/ts/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts', '', 'app/heroes/hero-button/hero-button.component.ts')(avoid=1)
+makeExample('style-guide/ts/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/hero-button/hero-button.component.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.html', '', 'app/heroes/hero-button/hero-button.component.html')(avoid=1)
@ -1313,11 +1447,11 @@ a(href="#toc") Back to top
:marked
**Why?** Syntax hints for inline templates in (*.js and *.ts) code files are not supported by some editors.
.s-why
.s-why.s-why-last
:marked
**Why?** A component file's logic is easier to read when not mixed with inline template and styles.
+makeExample('style-guide/ts/05-04/app/heroes/heroes.component.avoid.ts', '', 'app/heroes/heroes.component.ts')(avoid=1)
+makeExample('style-guide/ts/05-04/app/heroes/heroes.component.avoid.ts', 'example', 'app/heroes/heroes.component.ts')(avoid=1)
:marked
+makeTabs(
@ -1348,7 +1482,7 @@ a(href="#toc") Back to top
.s-why
:marked
**Why?** It is easier and more readable to idnetify which properties in a class are inputs or outputs.
**Why?** It is easier and more readable to identify which properties in a class are inputs or outputs.
.s-why
:marked
@ -1358,11 +1492,11 @@ a(href="#toc") Back to top
:marked
**Why?** The metadata declaration attached to the directive is shorter and thus more readable.
.s-why
.s-why.s-why-last
:marked
**Why?** Placing the decorator on the same line makes for shorter code and still easily identifies the property as an input or output.
+makeExample('style-guide/ts/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts', '', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
+makeExample('style-guide/ts/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/05-12/app/heroes/shared/hero-button/hero-button.component.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')
@ -1380,14 +1514,14 @@ a(href="#toc") Back to top
:marked
**Avoid** renaming inputs and outputs, when possible.
.s-why
.s-why.s-why-last
:marked
**Why?** May lead to confusion when the output or the input properties of a given directive are named a given way but exported differently as a public API.
+makeExample('style-guide/ts/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts', '', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
+makeExample('style-guide/ts/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/05-13/app/app.component.avoid.html', '', 'app.component.html')(avoid=1)
+makeExample('style-guide/ts/05-13/app/app.component.avoid.html', '', 'app/app.component.html')(avoid=1)
:marked
+makeTabs(
@ -1414,11 +1548,11 @@ a(href="#toc") Back to top
:marked
**Do** place private members after public members, alphabetized.
.s-why
.s-why.s-why-last
:marked
**Why?** Placing members in a consistent sequence makes it easy to read and helps we instantly identify which members of the component serve which purpose.
+makeExample('style-guide/ts/05-14/app/shared/toast/toast.component.avoid.ts', '', 'app/shared/toast/toast.component.ts')(avoid=1)
+makeExample('style-guide/ts/05-14/app/shared/toast/toast.component.avoid.ts', 'example', 'app/shared/toast/toast.component.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/05-14/app/shared/toast/toast.component.ts', 'example', 'app/shared/toast/toast.component.ts')
@ -1452,7 +1586,7 @@ a(href="#toc") Back to top
:marked
**Why?** Removes dependencies and hides implementation details from the component.
.s-why
.s-why.s-why-last
:marked
**Why?** Keeps the component slim, trim, and focused.
@ -1482,11 +1616,11 @@ a(href="#toc") Back to top
:marked
**Why?** This is consistent with built-in events such as button clicks.
.s-why
.s-why.s-why-last
:marked
**Why?** Angular allows for an [alternative syntax](https://angular.io/docs/ts/latest/guide/template-syntax.html#!#binding-syntax) `on-*`. If the event itself was prefixed with `on` this would result in an `on-onEvent` binding expression.
+makeExample('style-guide/ts/05-16/app/heroes/hero.component.avoid.ts', '', 'app/heroes/hero.component.ts')(avoid=1)
+makeExample('style-guide/ts/05-16/app/heroes/hero.component.avoid.ts', 'example', 'app/heroes/hero.component.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/05-16/app/app.component.avoid.html', '', 'app/app.component.html')(avoid=1)
@ -1516,14 +1650,14 @@ a(href="#toc") Back to top
:marked
**Why?** Logic will be contained in one place (the Component class) instead of being spread in two places.
.s-why
.s-why.s-why-last
:marked
**Why?** Keeping the logic of the components in their controller, instead of template will improve testability, maintability, reusability.
+makeExample('style-guide/ts/05-17/app/heroes/hero-list/heroes-list.component.avoid.ts', '', 'app/heroes/hero-list/heroes-list.component.ts')(avoid=1)
+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
+makeExample('style-guide/ts/05-17/app/heroes/hero-list/heroes-list.component.ts', 'example', 'app/heroes/hero-list/heroes-list.component.ts')
+makeExample('style-guide/ts/05-17/app/heroes/hero-list/hero-list.component.ts', 'example', 'app/heroes/hero-list/hero-list.component.ts')
:marked
a(href="#toc") Back to top
@ -1548,11 +1682,11 @@ a(href="#toc") Back to top
: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.
.s-why
.s-why.s-why-last
:marked
**Why?** The metadata declaration attached to the directive is shorter and thus more readable.
+makeExample('style-guide/ts/06-03/app/shared/validate.directive.ts', 'example', 'app/shared/validate.directive.ts')(avoid=1)
+makeExample('style-guide/ts/06-03/app/shared/validate.directive.avoid.ts', 'example', 'app/shared/validate.directive.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/06-03/app/shared/validate.directive.ts', 'example', 'app/shared/validate.directive.ts')
@ -1576,7 +1710,7 @@ a(href="#toc") Back to top
:marked
**Why?** Services are ideal for sharing methods across a feature area or an app.
.s-why
.s-why.s-why-last
:marked
**Why?** Services are ideal for sharing stateful in-memory data.
@ -1603,7 +1737,7 @@ a(href="#toc") Back to top
:marked
**Why?** When a service has multiple responsibilities, it becomes difficult to test.
.s-why
.s-why.s-why-last
:marked
**Why?** When a service has multiple responsibilities, every Component or Service that injects it now carries the weight of them all.
@ -1631,7 +1765,7 @@ a(href="#toc") Back to top
:marked
**Why?** This is ideal when a service is sharing methods and has no state, or state that must be shared.
.s-why
.s-why.s-why-last
:marked
**Why?** This is not ideal when two different components need different instances of a service. In this scenario it would be better to provide the service at the component level that needs the new and separate instance.
@ -1659,11 +1793,11 @@ a(href="#toc") Back to top
:marked
**Why?** The Angular DI mechanism resolves all the dependencies of our services based on their types declared with the services' constructors.
.s-why
.s-why.s-why-last
:marked
**Why?** When a service accepts only dependencies associated with type tokens, the `@Injectable()` syntax is much less verbose compared to using `@Inject()` on each individual constructor parameter.
+makeExample('style-guide/ts/07-04/app/heroes/shared/hero-arena.service.avoid.ts', '', 'app/heroes/shared/hero-arena.service.ts')(avoid=1)
+makeExample('style-guide/ts/07-04/app/heroes/shared/hero-arena.service.avoid.ts', 'example', 'app/heroes/shared/hero-arena.service.ts')(avoid=1)
:marked
+makeExample('style-guide/ts/07-04/app/heroes/shared/hero-arena.service.ts', 'example', 'app/heroes/shared/hero-arena.service.ts')
@ -1695,7 +1829,7 @@ a(href="#toc") Back to top
:marked
**Why?** This makes it easier to test (mock or real) the data calls when testing a component that uses a data service.
.s-why
.s-why.s-why-last
:marked
**Why?** Data service implementation may have very specific code to handle the data repository. This may include headers, how to talk to the data, or other services such as `Http`. Separating the logic into a data service encapsulates this logic in a single place hiding the implementation from the outside consumers (perhaps a component), also making it easier to change the implementation.
@ -1719,11 +1853,11 @@ a(href="#toc") Back to top
:marked
**Do** implement the lifecycle hook interfaces.
.s-why
.s-why.s-why-last
:marked
**Why?** We will 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', '', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1)
+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
+makeExample('style-guide/ts/09-01/app/heroes/shared/hero-button/hero-button.component.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')
@ -1769,7 +1903,7 @@ a(href="#toc") Back to top
:marked
**Why?** A component that handles routing is known as the componenter router.
.s-why
.s-why.s-why-last
:marked
**Why?** The `<router-outlet>` indicates where the template should be displayed for the target route.
@ -1782,15 +1916,41 @@ a(href="#toc") Back to top
:marked
## Appendix
### File Templates and Snippets
Use file templates or snippets to help follow consistent styles and patterns. Here are templates and/or snippets for some of the web development editors and IDEs.
### Visual Studio Code
[Visual Studio Code](https://code.visualstudio.com/) snippets that follow these styles and guidelines.
[Snippets for VS Code](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2)
[![Use Extension](https://github.com/johnpapa/vscode-angular2-snippets/raw/master/images/use-extension.gif)](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2)
Useful tools and tips for Angular 2.
a(href="#toc") Back to top
.l-main-section
:marked
### Codelyzer
<a id="A-01"></a>
#### Style A-01
.s-rule.do
:marked
**Do** use [codelyzer](https://www.npmjs.com/package/codelyzer) to follow this guide.
.s-rule.consider
:marked
**Consider** adjusting the rules in codelyzer to suit your needs.
a(href="#toc") Back to top
.l-main-section
:marked
### File Templates and Snippets
<a id="A-02"></a>
#### Style A-02
.s-rule.do
:marked
**Do** use file templates or snippets to help follow consistent styles and patterns. Here are templates and/or snippets for some of the web development editors and IDEs.
.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.
:marked
[![Use Extension](https://github.com/johnpapa/vscode-angular2-snippets/raw/master/images/use-extension.gif)](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2)
a(href="#toc") Back to top

View File

@ -37,6 +37,16 @@
border-left-color: #EEE;
}
.filetree {
margin: 32px 0;
.s-why.s-why-last {
margin-bottom:32px;
}
.filetree {
margin-bottom: 32px;
background-color: #FFF;
border:1px solid #1976D2;
}
table tr code-example .prettyprint {
margin-bottom: 0;
}

View File

@ -94,8 +94,6 @@
"component-selector-name": [true, "kebab-case"],
"directive-selector-type": [true, "attribute"],
"component-selector-type": [true, "element"],
"directive-selector-prefix": [true, "toh"],
"component-selector-prefix": [true, "toh"],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,