From d59b05adde36bc91c1489c6ea52b6d9856eb381e Mon Sep 17 00:00:00 2001 From: Ward Bell Date: Fri, 12 Feb 2016 17:54:22 -0800 Subject: [PATCH] docs(quickstart): quickstart revised with verbose mode toggle button --- public/_includes/_util-fns.jade | 58 ++ .../docs/_examples/quickstart/ts/index.html | 2 - public/docs/_examples/styles.css | 2 +- public/docs/ts/latest/guide/_data.json | 5 + .../guide/typescript-configuration.jade | 151 +++ public/docs/ts/latest/quickstart.jade | 929 +++++++----------- public/resources/css/layout/_layout.scss | 22 + 7 files changed, 595 insertions(+), 574 deletions(-) create mode 100644 public/docs/ts/latest/guide/typescript-configuration.jade diff --git a/public/_includes/_util-fns.jade b/public/_includes/_util-fns.jade index 7a3c7268d9..d5274d903e 100644 --- a/public/_includes/_util-fns.jade +++ b/public/_includes/_util-fns.jade @@ -46,7 +46,64 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns) else != styleString(jsonExtract, stylePatterns) +- // Open (and close) an explanation
. See QuickStart +script. + function why(id, backTo) { + var id = "#"+id; + var el = document.querySelector(id); + el.hidden=el.hidden=!el.hidden; + if (el.hidden && backTo){ + // the next line is required to work around a bug in WebKit (Chrome / Safari) + location.href = "#"; + location.href = "#" + backTo; + } + } +script. + function verbose(isVerbose) { + isVerbose = !! isVerbose; + var el = document.querySelector('button.verbose.off'); + el.style.display = isVerbose ? 'block' : 'none'; + var el = document.querySelector('button.verbose.on'); + el.style.display = isVerbose ? 'none' : 'block'; + + CCSStylesheetRuleStyle('main','.l-verbose-section', 'display', + isVerbose ? 'block' : 'none'); + } + +script. + function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){ + /* returns the value of the element style of the rule in the stylesheet + * If no value is given, reads the value + * If value is given, the value is changed and returned + * If '' (empty string) is given, erases the value. + * The browser will apply the default one + * + * string stylesheet: part of the .css name to be recognized, e.g. 'default' + * string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td' + * string style: camelCase element style, e.g. 'fontSize' + * string value optional : the new value + */ + var CCSstyle = undefined, rules, sheet; + for(var m in document.styleSheets){ + sheet = document.styleSheets[m]; + if(sheet.href && sheet.href.indexOf(stylesheet) != -1){ + rules = sheet[document.all ? 'rules' : 'cssRules']; + for(var n in rules){ + console.log(rules[n].selectorText); + if(rules[n].selectorText == selectorText){ + CCSstyle = rules[n].style; + break; + } + } + break; + } + } + if(value == undefined) + return CCSstyle[style] + else + return CCSstyle[style] = value + } //--------------------------------------------------------------------------------------------------------- - var translatePath = function(filePath, region) { - filePath = filePath.trim(); @@ -134,6 +191,7 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns) - return source; - } + - var getFragFilePath = function (filePath, region) { - filePath = filePath.trim(); - var extn = getExtn(filePath); diff --git a/public/docs/_examples/quickstart/ts/index.html b/public/docs/_examples/quickstart/ts/index.html index 40c8b29dd5..21b3a60713 100644 --- a/public/docs/_examples/quickstart/ts/index.html +++ b/public/docs/_examples/quickstart/ts/index.html @@ -36,7 +36,6 @@ .then(null, console.error.bind(console)); - @@ -45,5 +44,4 @@ Loading... - diff --git a/public/docs/_examples/styles.css b/public/docs/_examples/styles.css index 6162a3e76f..b5fddefe30 100644 --- a/public/docs/_examples/styles.css +++ b/public/docs/_examples/styles.css @@ -81,7 +81,7 @@ nav a.router-link-active { left: .1em; } .items li.selected:hover { - background-color: #BBD8DC !important; + background-color: #BBD8DC; color: white; } .items .text { diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index 84963feb59..8eb6c3eabc 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -78,6 +78,11 @@ "intro": "Angular 1 applications can be incrementally upgraded to Angular 2." }, + "typescript-configuration": { + "title": "TypeScript Configuration", + "intro": "TypeScript configuration for Angular 2 developers" + }, + "glossary": { "title": "Glossary", "intro": "Brief definitions of the most important words in the Angular 2 vocabulary" diff --git a/public/docs/ts/latest/guide/typescript-configuration.jade b/public/docs/ts/latest/guide/typescript-configuration.jade new file mode 100644 index 0000000000..8f4f8df039 --- /dev/null +++ b/public/docs/ts/latest/guide/typescript-configuration.jade @@ -0,0 +1,151 @@ +include ../../../../_includes/_util-fns + +:marked + TypeScript is a primary language for Angular application development. + + TypeScript is a dialect of JavaScript with design-time support for type-safety and tooling. + + Browsers can't execute TypeScript directly. It has to be "transpiled" into JavaScript with the *tsc* compiler + and that effort requires some configuration. + + This chapter covers some aspects of TypeScript configuration and the TypeScript environment + that are important to Angular developers. + +a(id="tsconfig") +.l-main-section +:marked + ## *tsconfig.json* + We typically add a TypeScript configuration file (`tsconfig.json`) to our project to + guide the compiler as it generates JavaScript files. +.l-sub-section + :marked + Get details about `tsconfig.json` from the official + [TypeScript wiki](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json). +:marked + We created the following `tsconfig.json` for the [QuickStart](../quickstart.html): ++makeJson('quickstart/ts/tsconfig.1.json', null, 'tsconfig.json')(format=".") +:marked + The options and flags in this file are essential for Angular 2 applications. + + + ### *noImplicitAny* and *suppressImplicitAnyIndexErrors* + + TypeScript developers disagree about whether the `noImplicitAny` flag should be `true` or `false`. + There is no correct answer and we can change the flag later. + But our choice now can make a difference in larger projects so it merits discussion. + + When the `noImplicitAny` flag is `false` (the default), + the compiler silently defaults the type of a variable to `any` if it cannot infer + the type based on how the variable is used. That's what we mean by *implicit `any`*. + + We initialized the `noImplicitAny` flag to `false` in the QuickStart + to make learning TypeScript development easier. + + When the `noImplicitAny` flag is `true` and the TypeScript compiler cannot infer + the type, it still generates the JavaScript files. But it also **reports an error**. + Many seasoned developers prefer this stricter setting because type checking catches more + unintentional errors at compile time. + + We can set a variable's type to `any` even when the `noImplicitAny` flag is `true`. + We do so when that seems like the best choice for the situation, + deliberately and explicitly, after giving the matter some thought. + + If we set the `noImplicitAny` flag to `true`, we may get *implicit index errors* as well. + Most developers feel that *this particular error* is more annoying than helpful. + We can suppress them with the following additional flag. +code-example(format="."). + "suppressImplicitAnyIndexErrors":true + + +a(id="typings") +.l-main-section +:marked + ## TypeScript Typings + Many JavaScript libraries such as jQuery, the Jasmine testing library, and Angular itself, + extend the JavaScript environment with features and syntax + that the TypeScript compiler doesn't recognize natively. + When the compiler doesn't recognize something, it throws an error. + + We use [TypeScript type definition files](http://www.typescriptlang.org/Handbook#writing-dts-files) + — *d.ts files* — to tell the compiler about the libraries we load. + + TypeScript-aware editors leverage these same definition files to display type information about library features. + + Many libraries include their definition files in their npm packages where both the TypeScript compiler and editors + can find them. Angular is one such library. + Peek into the `node_modules/angular2/` folder of any Angular application to see several `...d.ts` files that describe parts of Angular. + + **We do nothing to get *typings* files for library packages with bundled *d.ts* files.** + + ### Manual typings + Sadly, many libraries — jQuery, Jasmine, and Lodash among them — do *not* include `d.ts` files in their npm packages. + Fortunately, either their authors or community contributors have created separate *d.ts* files for these libraries and + published them in well-known locations. + The *typings* tool can find and fetch these files for us. + + We installed the [typings](https://github.com/typings/typings/blob/master/README.md) tool + with npm (it's listed among the *devDependencies* in the `package.json`) and added an npm script + to run that tool automatically after *npm* installation completes. ++makeJson('quickstart/ts/package.1.json', {paths: 'scripts.postinstall'}, 'package.json (postinstall)')(format=".") +:marked + This *typings* tool command installs the *d.ts* files that we identify in a `typings.json` file + such as this one from the [QuickStart](../quickstart.html): ++makeJson('quickstart/ts/typings.1.json', null, 'typings.json')(format=".") +:marked + We identified only one *typings* file in the QuickStart, the *d.ts* file for + [es6-shim](https://github.com/paulmillr/es6-shim/blob/master/README.md) that brings ES2015/ES6 + capabilities to our ES5 browsers. + QuickStart itself doesn't need this shim but many of the documentation samples do + and most of us would be disappointed if typical ES2015 features didn't work out-of-the-box. + + We can also run the *typings* tool ourselves. The following command lists the locally installed typings files. +code-example(format=""). + npm run typings -- list +:marked + The following command installs the typings file for the Jasmine test library and updates the `typings.config` + so we that we get it automatically the next time. +code-example(format=""). + npm run typings -- install jasmine --ambient --save +.l-sub-section + :marked + The [–– option](https://docs.npmjs.com/cli/run-script) is important; + it tells npm to pass all arguments to the right of `--` to the *typings* command. + + Learn about the features of the *typings* tool at its [site on github](https://github.com/typings/typings/blob/master/README.md). +:marked + #### Typing file collisions + + The TypeScript compiler does not tolerate redefinition of a type. For example, it throws an error if it's given two definitions for + the `Promise` type. + + Double definitions are common. In fact, the `typings` tool deliberately creates + duplicate sets of typings (for reasons best explained elsewhere). + Look in the project structure for the *typings folder* where we should find something like: +.filetree + .file typings + .children + .file browser + .children + .file ambient + .children + .file es6-shim + .children + .file es6-shim.d.ts + .children + .file main + .children + .file ambient + .children + .file es6-shim + .children + .file es6-shim.d.ts + .children + .file browser.d.ts + .file main.d.ts +:marked + The `es6-shim` typings are duplicated and the `browser.d.ts` and `main.d.ts` have overlapping content. + + We must tell the compiler to ignore one or the other. + We removed the `main` set from consideration in the `exclude` section of our `tsconfig.json` file: ++makeJson('quickstart/ts/tsconfig.1.json', {paths: 'exclude'}, 'tsconfig.json (exclude)')(format=".") +:marked diff --git a/public/docs/ts/latest/quickstart.jade b/public/docs/ts/latest/quickstart.jade index eb3197a304..1df1ea4dbd 100644 --- a/public/docs/ts/latest/quickstart.jade +++ b/public/docs/ts/latest/quickstart.jade @@ -1,270 +1,431 @@ include ../../../_includes/_util-fns - + :marked - Let's start from zero and build a super simple Angular 2 application in TypeScript. + Our QuickStart goal is to build and run a super-simple Angular 2 application in TypeScript. -.callout.is-helpful - header Don't want TypeScript? - :marked - Although we're getting started in TypeScript, you can also write Angular 2 apps - in JavaScript and Dart by selecting either of those languages from the combo-box in the banner. - -.l-main-section -:marked ## See It Run! - Running the [live example](/resources/live-examples/quickstart/ts/plnkr.html) - is the quickest way to see an Angular 2 app come to life. - - Clicking that link fires up a browser, loads the sample in [plunker](http://plnkr.co/ "Plunker"), + Try this live example + which loads the sample app in plunker and displays a simple message: figure.image-display - img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app") + img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of QuickStart app") :marked - Here is the file structure: -.filetree - .file angular2-quickstart - .children - .file app - .children - .file app.component.ts - .file main.ts - .file index.html - .file license.md -:marked - Functionally, it's an `index.html` and two TypeScript files in an `app/` folder. - We can handle that! - - Of course we won't build many apps that only run in plunker. - Let's follow a process that's closer to what we'd do in real life. - - 1. Set up our development environment - 1. Write the Angular root component for our app - 1. Bootstrap it to take control of the main web page - 1. Write the main page (`index.html`) + Of course we don't build apps to run in plunker. + The following steps establish a development environment for the documentation samples + that also can be the foundation for our real world applications. At a high level, we will + - set up the [development environment](#devenv) + - write the app's Angular [root component](#component) + - write [main.ts](#main) which tells Angular to display the root component + - write the [host web page](#index) (`index.html`) + .l-sub-section :marked - We really can build the QuickStart from scratch in five minutes - if we follow the instructions and ignore the commentary. + We'll see many code blocks as we pursue this agenda. They're all easy to copy and paste: + code-example(format='.', language='html'). + Click the glyph on the right to copy code snippets to the clipboard ⇨⇨⇨⇨⇨⇨⇨⇨⇨⇨ - Most of us will be interested in the "why" as well as the "how" and that will take longer. -:marked +button(class="verbose off md-primary md-button md-ink-ripple", type="button", onclick="verbose(false)"). + Hide explanations +button(class="verbose on md-primary md-button md-ink-ripple", type="button", onclick="verbose(true)"). + View explanations +.l-verbose-section + :marked + *Explanations* describe the concepts and reasons behind the instructions. + Explanations have a thin border on the left like *this* block of text. + + Click *Hide Explanations* to show only the instructions. + Click it again to see everything again. +a(id="devenv") .l-main-section :marked ## Development Environment - We'll need a place to stand (the application project folder), - some TypeScript configuration, and some libraries for development and runtime. + We need to set up our development environment with + * an [application project folder](#app-folder) + * a [tsconfig.json](#tsconfig) to guide the TypeScript compiler + * a [typings.json](#typings) to install TypeScript definition files + * a [package.json](#package-json) to install *npm* packages with scripts and other assets our app will need. - ### Create a new project folder - +a(id="app-folder") +:marked + Create a **new project folder** code-example(format=""). mkdir angular2-quickstart cd angular2-quickstart -:marked - ### Configure TypeScript - - We must guide the TypeScript compiler with very specific settings. +a(id="tsconfig") +:marked Add a **tsconfig.json** file to the project folder and copy/paste the following: +makeJson('quickstart/ts/tsconfig.1.json', null, 'tsconfig.json')(format=".") -.l-sub-section - :marked - We explore the `tsconfig.json` in an [appendix below](#tsconfig) -:marked - ### TypeScript Typings - Many JavaScript libraries extend the JavaScript environment with features and syntax - that the TypeScript compiler doesn't recognize natively. We teach it about these capabilities with - [TypeScript type definition files](http://www.typescriptlang.org/Handbook#writing-dts-files) - — *d.ts files* — which we identify in a `typings.json` file. - +:marked + This `tsconfig.json` file guides the TypeScript compiler. + Learn more about it in the + TypeScript Configuration chapter. + +a(id="typings") +:marked Add a **typings.json** file to the project folder and copy/paste the following: +makeJson('quickstart/ts/typings.1.json', null, 'typings.json')(format=".") -.l-sub-section - :marked - We go a little deeper into *typings* in an [appendix below](#typings) -:marked - ### Add the libraries we need - - We recommend the **npm** package manager for acquiring and managing our development libraries. -.l-sub-section +.l-verbose-section :marked - Don't have npm? - [Get it now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm") - because we're going to use it now and repeatedly throughout this documentation. + Many JavaScript libraries extend the JavaScript environment with features and syntax + that the TypeScript compiler doesn't recognize natively. We teach it about these capabilities with + TypeScript type definition files + — *d.ts files* — which we identify in a `typings.json` file. + + We go a little deeper into *typings* in the + TypeScript Configuration chapter. + +a(id="package-json") :marked Add a **package.json** file to the project folder and copy/paste the following: -+makeJson('quickstart/ts/package.1.json', null, 'package.json')(format=".") - -.l-sub-section - :marked - Itching to know the details? We explain in the [appendix below](#package-json) ++makeJson('quickstart/ts/package.1.json', null, 'package.json')(format=".") + :marked - Install these packages. Open a terminal window (command window in Windows) and - run this npm command. + **Install these packages** by entering the following *npm* command in a terminal window (command window in Windows): code-example(format=""). npm install -:marked -.l-sub-section + +.alert.is-important :marked Scary error messages in red may appear **during** install. - Ignore them. The install will succeed. See the [appendix below](#npm-errors) for more information. + The install typically recovers from these errors and finishes successfully. + .l-verbose-section(class="l-verbose-inherit") + :marked + #### npm errors and warnings + + All is well if there are no console messages starting with `npm ERR!` *at the end* of **npm install**. + There might be a few `npm WARN` messages along the way — and that is perfectly fine. + + We often see an `npm WARN` message after a series of `gyp ERR!` messages. + Ignore them. A package may try to re-compile itself using `node-gyp`. + If the re-compile fails, the package recovers (typically with a pre-built version) + and everything works. + + Just make sure there are no `npm ERR!` messages at the end of `npm install`. +.l-verbose-section + :marked + ### Adding the libraries we need with *npm* + Angular application developers rely on the npm + package manager to acquire the libraries their apps require. + + Don't have npm? + Get it now + because we're going to use it now and repeatedly throughout this documentation. + + The Angular team recommends the starter-set of packages specified in the `dependencies` and `devDependencies` + sections of this QuickStart + package.json file. + + +makeJson('quickstart/ts/package.1.json',{ paths: 'dependencies, devDependencies'}, 'package.json (dependencies)')(format=".") + :marked + There are other possible package choices. + We're recommending this particular set that we know work well together. + Feel free to make substitutions later to suit your tastes and experience. + + A `package.json` has an optional **scripts** section where we can define helpful + commands for development and build tasks. + We've included a number of such scripts in our suggested `package.json`: + +makeJson('quickstart/ts/package.1.json',{ paths: 'scripts'}, 'package.json (scripts)')(format=".") + + :marked + We execute most npm scripts in the following way: `npm run` + *script-name*. + Some commands (such as `start` don't require the `run` keyword). + + Here's what these scripts do: + + * `npm start` - run the compiler and a server at the same time, both in "watch mode" + + * `npm run tsc` - run the TypeScript compiler once + + * `npm run tsc:w` - run the TypeScript compiler in watch mode; + the process keeps running, awaiting changes to TypeScript files and re-compiling when it sees them. + + * `npm run lite` - run the lite-server, + a light-weight, static file server, written and maintained by + John Papa + with excellent support for Angular apps that use routing. + + * `npm run typings` - runs the [*typings* tool](#typings) + + * `npm postinstall` - called by *npm* automatically *after* it successfully completes package installation. + This script installs the [TypeScript definition files](#typings) this app requires. + :marked **We're all set.** Let's write some code. + +a(id="component") .l-main-section :marked ## Our First Angular Component - - The *Component* is the most fundamental of Angular concepts. - A component manages a view - a piece of the web page where we display information - to the user and respond to user feedback. - - Technically, a component is a class that controls a view template. - We'll write a lot of them as we build Angular apps. This is our first attempt - so we'll keep it ridiculously simple. - - ### Create an application source sub-folder - - We like to keep our application code in a sub-folder off the root called `app/`. - Execute the following command in the console window. + Let's create a folder to hold our application and add a super-simple Angular component. + + **Create an *app* sub-folder** off the root directory and make it the current directory code-example(format=""). mkdir app cd app + +a(id="app-component") :marked - ### Add the component file - Now add a file named **app.component.ts** and paste the following lines: + **Add a component file** named *app.component.ts* and paste the following lines: +makeExample('quickstart/ts/app/app.component.ts', null, 'app/app.component.ts')(format=".") -:marked - Let's review this file in detail, starting at the bottom where we define a class. - - ### The Component class - At the bottom of the file is an empty, do-nothing class named `AppComponent`. - When we're ready to build a substantive application, - we can expand this class with properties and application logic. - Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart. - ### Modules - Angular apps are modular. They consist of many files each dedicated to a purpose. - - Most application files *export* one thing such as a component. - Our `app.component` file exports the `AppComponent`. -+makeExample('quickstart/ts/app/app.component.ts', 'export', 'app/app.component.ts (export)')(format=".") -:marked - The act of exporting turns the file into a module. - The name of the file (without extension) is usually the name of the module. - Accordingly, '*app.component*' is the name of our first module. - - A more sophisticated application would have child components that descended from - `AppComponent` in a visual tree. - A more sophisticated app would have more files and modules, at least as many as it had components. - - This Quickstart isn't sophisticated; one component is all we need. - Yet modules play a fundamental organizational role in even this small app. - - Modules rely on other modules. In TypeScript Angular apps, when we need something - provided by another module, we import it. - When another module needs to refer to `AppComponent`, it imports the `AppComponent` *symbol* like this: -+makeExample('quickstart/ts/app/main.ts', 'app-component','app/main.ts (import)')(format=".") -:marked - Angular is also modular. It is a collection of library modules. - Each library is itself a module made up of several, related feature modules. - - When we need something from Angular, we import it from an Angular library module. - We need something from Angular right now to help us define metadata about our component. - - ### Component Metadata - A class becomes an Angular component when we give it metadata. - Angular needs the metadata to understand how to construct the view - and how the component interacts with other parts of the application. - - We define a component's metadata with the Angular `Component` function. - We access that function by importing it from the primary Angular library,`angular2/core`. -+makeExample('quickstart/ts/app/app.component.ts', 'import', 'app/app.component.ts (import)')(format=".") -:marked - In TypeScript we apply that function to the class as a *decorator* - by prefixing it with the **@** symbol and invoking it - just above the component class: -+makeExample('quickstart/ts/app/app.component.ts', 'metadata', 'app/app.component.ts (metadata)') -:marked - `@Component` tells Angular that this class *is an Angular component*. - The configuration object passed to the `@Component` method has two - fields, a `selector` and a `template`. - - The `selector` specifies a simple CSS selector for a host HTML element named `my-app`. - Angular creates and displays an instance of our `AppComponent` - wherever it encounters a `my-app` element in the host HTML. - -.alert.is-helpful +.l-verbose-section :marked - Remember the `my-app` selector! We'll need that information when we write our `index.html` -:marked - The `template` property holds the component's companion template. - A template is a form of HTML that tells Angular how to render a view. - Our template is a single line of HTML announcing "My First Angular App". - - Now we need something to tell Angular to load this component. + ### AppComponent is the root of the application + + Every Angular app has at least one root component, conventionally named `AppComponent`, + that hosts the client user experience. + + Components are the basic building blocks of Angular applications. + A component controls a portion of the screen — a *view* — through its associated template. - ### Bootstrap it + This QuickStart has only one, extremely simple component. + But it has the essential structure of every component we'll ever write: + + * One or more import + statements to reference the things we need. + + * A @Component decorator + that tells Angular what template to use and how to create the component. + + * A component class + that controls the appearance and behavior of a view through its template. + + a(id="component-import") + :marked + ### Import + + Angular apps are modular. They consist of many files each dedicated to a purpose. + + Angular itself is modular. It is a collection of library modules + each made up of several, related features that we'll use to build our application. + + When we need something from a module, we import it. + Here we import the Angular `Component` decorator function from the + main Angular library module because we need it to define our component. + +makeExample('quickstart/ts/app/app.component.ts', 'import', 'app/app.component.ts (import)')(format=".") + + a(id="component-decorator") + :marked + ### @Component decorator + + `Component` is a **decorator** function that takes a *metadata* object. + The metadata tell Angular how to create and use this component. + + We apply this function to the component class + by prefixing the function with the **@** symbol and invoking it with the metadata object. + just above the class: + +makeExample('quickstart/ts/app/app.component.ts', 'metadata', 'app/app.component.ts (metadata)')(format=".") + :marked + This particular metadata object has two fields, a `selector` and a `template`. + + The **selector** specifies a simple CSS selector for an HTML element that represents the component. + + >The element for this component is named `my-app`. + Angular creates and displays an instance of our `AppComponent` + wherever it encounters a `my-app` element in the host HTML. + + The **template** specifies the component's companion template, + written in an enhanced form of HTML that tells Angular how to render this component's view. + + >Our template is a single line of HTML announcing "*My First Angular App*". + + >A more advanced template could contain data bindings to component properties + and might identify other application components which have their own templates. + These templates might identify yet other components. + In this way an Angular application becomes a tree of components. + + a(id="component-class") + :marked + ### Component class + At the bottom of the file is an empty, do-nothing class named `AppComponent`. + +makeExample('quickstart/ts/app/app.component.ts', 'export', 'app/app.component.ts (class)')(format=".") + :marked + When we're ready to build a substantive application, + we can expand this class with properties and application logic. + Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart. + + We **export** `AppComponent` so that we can **import** it elsewhere in our application, + as we'll see when we create `main.ts`. + +a(id="main") +.l-main-section +:marked + ## Show it with *main.ts* + Now we need something to tell Angular to load the root component Add a new file , `main.ts`, to the `app/` folder as follows: +makeExample('quickstart/ts/app/main.ts', null, 'app/main.ts')(format=".") -:marked - We need two things to launch the application: - 1. Angular's browser `bootstrap` function - 1. The application root component that we just wrote. - - We import both. Then we call `bootstrap`, passing in the **root component type**, - `AppComponent`. - -.l-sub-section +.l-verbose-section :marked - Learn why we import `bootstrap` from `angular2/platform/browser` - and why we create a separate *main.ts* file in the [appendix below](#main). -:marked - We've asked Angular to launch the app in a browser with our component at the root. - Where will Angular put it? + We import the two things we need to launch the application: + 1. Angular's browser `bootstrap` function + 1. The application root component, `AppComponent`. + + Then we call `bootstrap` with `AppComponent`. + + ### Bootstrapping is platform-specific + Notice that we import the `bootstrap` function from `angular2/platform/browser`, + not `angular2/core`. + + Bootstrapping isn't core because there isn't a single way to bootstrap the app. + True, most applications that run in a browser call the bootstrap function from + this library. + + But it is possible to load a component in a different environment. + We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/) or [NativeScript](https://www.nativescript.org/). + We might wish to render the first page of our application on the server + to improve launch performance or facilitate + [SEO](http://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf). + + These targets require a different kind of bootstrap function that we'd import from a different library. + + ### Why create a separate ***main.ts*** file? + + The *main.ts* file is tiny. This is just a QuickStart. + We could have folded its few lines into the `app.component` file + and spared ourselves some complexity. + + We'd rather demonstrate the proper way to structure an Angular application. + App bootstrapping is a separate concern from presenting a view. + Mixing concerns creates difficulties down the road. + We might launch the `AppComponent` in multiple environments with different bootstrappers. + Testing the component is much easier if it doesn't also try to run the entire application. + Let's make the small extra effort to do it *the right way*. + +a(id="index") .l-main-section :marked ## Add the `index.html` + The `index.html` is the web page that hosts the application - Angular displays our application in a specific location on our `index.html`. - It's time to create that file. - - We won't put our `index.html` in the `app/` folder. - We'll locate it **up one level, in the project root folder**. + Navigate to the **project root folder**. code-example(format=""). cd .. :marked - Now create the`index.html` file and paste the following lines: + Create an`index.html` file in this root folder and paste the following lines: +makeExample('quickstart/ts/index.html', null, 'index.html')(format=".") -:marked - There are three noteworthy sections of HTML: +.l-verbose-section + :marked + There are three noteworthy sections of HTML - 1. We load the JavaScript libraries we need; learn about them [below](#libraries). + 1. The JavaScript [libraries](#libraries) + + 2. Configuration of [SystemJS](#systemjs) where we also import and run the + `main` file that we just wrote. + + 3. The [<my-app>](#my-app) tag in the `` which is *where our app lives!* + + a(id="libraries") + :marked + ### Libraries + We loaded the following scripts + +makeExample('quickstart/ts/index.html', 'libraries', 'index.html')(format=".") + :marked + We began with Internet Explorer polyfills. + IE requires polyfills to run + an application that relies on ES2015 promises and dynamic module loading. + Most applications need those capabilities and most applications + should run in Internet Explorer. - 2. We configure something called `System` and ask it to import the - `main` file we just wrote. + Next are the polyfills for Angular2, `angular2-polyfills.js`. + + Then the [SystemJS](#systemjs) library for module loading, + followed by the Reactive Extensions RxJS library. + .l-sub-section + :marked + Our QuickStart doesn't use the Reactive Extensions + but any substantial application will want them + when working with observables. + We added the library here in QuickStart so we don't forget later. + :marked + Finally, we loaded the web development version of Angular 2 itself. - 3. We add the `` tag in the ``. **This is where our app lives!** + We'll make different choices as we gain experience and + become more concerned about production qualities such as + load times and memory footprint. + + a(id="systemjs") + :marked + ### SystemJS Configuration + + The QuickStart uses SystemJS + to load application and library modules. + There are alternatives that work just fine including the well-regarded + webpack. + SystemJS happens to be a good choice but we want to be clear that it was a choice and not a preference. + + All module loaders require configuration and all loader configuration + becomes complicated rather quickly as soon as the file structure diversifies and + we start thinking about building for production and performance. + + We suggest becoming well-versed in the loader of your choice. + Learn more about SystemJS configuration + here. + + With those cautions in mind, what are we doing in this QuickStart configuration? + +makeExample('quickstart/ts/index.html', 'systemjs', 'index.html (System configuration)')(format=".") + :marked + The `packages` node tells SystemJS what to do when it sees a request for a + module from the `app/` folder. + + Our QuickStart makes such requests when one of its + application TypeScript files has an import statement like this: + +makeExample('quickstart/ts/app/main.ts', 'app-component', 'main.ts (excerpt)')(format=".") + :marked + Notice that the module name (after `from`) does not mention a filename extension. + The `packages:` configuration tells SystemJS to default the extension to 'js', a JavaScript file. + + That makes sense because we transpile TypeScript to JavaScript + before running the application. - Something has to find and load our application modules. We're using **SystemJS** to do that. - There are other choices and we're not saying SystemJS is the best. We like it and it works. - - The specifics of SystemJS configuration are out of bounds. - We'll briefly describe this particular configuration in the [appendix below](#systemjs). - - When Angular calls the `bootstrap` function in `main.ts`, it reads the `AppComponent` - metadata, finds the `my-app` selector, locates an element tag named `my-app`, - and loads our application between those tags. + .l-sub-section + :marked + #### Transpiling in the browser + In the live example on plunker we transpile (AKA compile) to JavaScript in the browser + on the fly. That's fine for a demo. That's not our preference for development or production. + + We recommend transpiling (AKA compiling) to JavaScript during a build phase + before running the application for several reasons including: + + * We see compiler warnings and errors that are hidden from us in the browser. + + * Pre-compilation simpifies the module loading process and + it's much easier to diagnose problem when this is a separate, external step. + + * Pre-compilation means a faster user experience because the browser doesn't waste time compiling. + + * We iterate development faster because we only re-compile changed files. + We notice the difference as soon as the app grows beyond a handful of files. + + * Pre-compilation fits into a continuous integration process of build, test, deploy. + + :marked + The `System.import` call tells SystemJS to import the `main` file + (`main.js` ... after transpiling `main.ts`, remember?). + `main` is where we tell Angular to launch the application. + We also catch and log launch errors to the console. + + All other modules are loaded upon request + either by an import statement or by Angular itself. + + a(id="my-app") + :marked + ### *<my-app>* + When Angular calls the `bootstrap` function in `main.ts`, it reads the `AppComponent` + metadata, finds the `my-app` selector, locates an element tag named `my-app`, + and loads our application between those tags. .l-main-section :marked @@ -348,377 +509,3 @@ figure.image-display demonstrates the great things we can build with Angular 2. Join us on the [Tour of Heroes Tutorial](./tutorial)! - - -.l-main-section -:marked - ## Appendices - The balance of this chapter is a set of appendices that - elaborate on some of the points we covered quickly above. - - There is no essential material here. Continued reading is for the curious. - - - - -.l-main-section -:marked - ## Appendix: Libraries - We loaded the following scripts -+makeExample('quickstart/ts/index.html', 'libraries', 'index.html')(format=".") -:marked - We began with Internet Explorer polyfills. - IE requires polyfills to run - an application that relies on ES2015 promises and dynamic module loading. - Most applications need those capabilities and most applications - should run in Internet Explorer. -.l-sub-section - :marked - We can substitute the following libraries from a CDN: - +makeExample('router/ts/index.1.html','ie-cdn-polyfills')(format=".") -:marked - Next are the polyfills for Angular2, `angular2-polyfills.js`. - Then the [SystemJS library](#systemjs) for module loading, - followed by the Reactive Extensions RxJS library. -.l-sub-section - :marked - Our QuickStart doesn't use the Reactive Extensions - but any substantial application will want them - when working with observables. - We added the library here in QuickStart so we don't forget later. -:marked - Finally, we loaded the web development version of Angular 2 itself. - - We'll make different choices as we gain experience and - become more concerned about production qualities such as - load times and memory footprint. - -.l-main-section -:marked - - ## Appendix: package.json - - [npm](https://docs.npmjs.com/) is a popular package manager and Angular application developers rely on it - to acquire and manage the libraries their apps require. - - We specify the packages we need in an npm [package.json](https://docs.npmjs.com/files/package.json) file. - - The Angular team suggests the packages listed in the `dependencies` and `devDependencies` - sections listed in this file: - -+makeJson('quickstart/ts/package.1.json',{ paths: 'dependencies, devDependencies'}, 'package.json (dependencies)')(format=".") -:marked -.l-sub-section - :marked - There are other possible package choices. - We're recommending this particular set that we know work well together. - Play along with us for now. - Feel free to make substitutions later to suit your tastes and experience. -:marked - A `package.json` has an optional **scripts** section where we can define helpful - commands to perform development and build tasks. - We've included a number of such scripts in our suggested `package.json`: -+makeJson('quickstart/ts/package.1.json',{ paths: 'scripts'}, 'package.json (scripts)')(format=".") -:marked - We've seen how we can run the compiler and a server at the same time with this command: -code-example(format=""). - npm start -:marked - We execute npm scripts in that manner: `npm run` + *script-name*. Here's what these scripts do: - - * `npm run tsc` - run the TypeScript compiler once - - * `npm run tsc:w` - run the TypeScript compiler in watch mode; - the process keeps running, awaiting changes to TypeScript files and re-compiling when it sees them. - - * `npm run lite` - run the [lite-server](https://www.npmjs.com/package/lite-server), - a light-weight, static file server, written and maintained by [John Papa](http://johnpapa.net/) - with excellent support for Angular apps that use routing. - - -.l-main-section -:marked - - ## Appendix: Npm errors and warnings - - All is well if there are no console messages starting with `npm ERR!` *at the end* of **npm install**. - There might be a few `npm WARN` messages along the way — and that is perfectly fine. - - We often see an `npm WARN` message after a series of `gyp ERR!` messages. - Ignore them. A package may try to re-compile itself using `node-gyp`. - If the re-compile fails, the package recovers (typically with a pre-built version) - and everything works. - - Just make sure there are no `npm ERR!` messages at the very end of `npm install`. - - -.l-main-section -:marked - - ## Appendix: TypeScript configuration - We added a TypeScript configuration file (`tsconfig.json`) to our project to - guide the compiler as it generates JavaScript files. - Get details about `tsconfig.json` from the official - [TypeScript wiki](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json). - - The options and flags in the file we provided are essential. - - We'd like a moment to discuss the `noImplicitAny` flag. - TypeScript developers disagree about whether it should be `true` or `false`. - There is no correct answer and we can change the flag later. - But our choice now can make a difference in larger projects so it merits - discussion. - - When the `noImplicitAny` flag is `false`, - the compiler silently defaults the type of a variable to `any` if it cannot infer - the type based on how the variable is used. That's what we mean by "implicitly `any`". - - When the `noImplicitAny` flag is `true` and the TypeScript compiler cannot infer - the type, it still generates the JavaScript files but - it also reports an error. - - In this QuickStart and many of the other samples in this Developer Guide - we set the `noImplicitAny` flag to `false`. - - Developers who prefer stricter type checking should set the `noImplicitAny` flag to `true`. - We can still set a variable's type to `any` if - that seems like the best choice. We'd be doing so explicitly after - giving the matter some thought. - - If we set the `noImplicitAny` flag to `true`, we may get implicit index errors as well. - If we feel these are more annoying than helpful, - we can suppress them with the following additional flag. - ``` - "suppressImplicitAnyIndexErrors":true - ``` - - - -.l-main-section -:marked - ## Appendix: TypeScript Typings - Many libraries such as jQuery, the Jasmine testing library, and Angular itself, - add material to the JavaScript environment that the TypeScript compiler doesn't recognize. - When the compiler doesn't recognize something, it throws an error. - - We use [TypeScript type definition files](http://www.typescriptlang.org/Handbook#writing-dts-files) - — *d.ts files* — to tell the compiler about the libraries we load. - - TypeScript-aware editors leverage these same definition files to display type information about library features. - - Many libraries include their definition files in their npm packages where both the TypeScript compiler and editors - can find them. Angular is one such library. - Peek into the `node_modules/angular2/` folder to see several `...d.ts` files that describe parts of Angular. - - **We do nothing to get *typings* files for library packages with bundled *d.ts* files.** - - Sadly, many libraries — jQuery, Jasmine, and Lodash among them — do *not* include `d.ts` files in their npm packages. - Fortunately, either their authors or community contributors have created separate *d.ts* files for these libraries and - published them in well-known locations. - The *typings* tool can find and fetch these files for us. - - We installed the [typings](https://github.com/typings/typings/blob/master/README.md) tool - with npm (find it in the `package.json`) and added an npm script - to run that tool automatically after *npm* installation completes. -+makeJson('quickstart/ts/package.1.json', {paths: 'scripts.postinstall'}, 'package.json (postinstall)')(format=".") -:marked - This *typings* tool command installs the *d.ts* files that we identified in `typings.json`: -+makeJson('quickstart/ts/typings.1.json', null, 'typings.json')(format=".") -:marked - We identified only one *typings* file in this QuickStart, the *d.ts* file for - [es6-shim](https://github.com/paulmillr/es6-shim/blob/master/README.md) that brings ES2015/ES6 - capabilities to our ES5 browsers. - QuickStart itself doesn't need this shim but many of the documentation samples do - and most of us would be disappointed if typical ES2015 features didn't work out-of-the-box. - - We can also run the *typings* tool ourselves. The following command lists the locally installed typings files. -code-example(format=""). - npm run typings -- list -:marked - The following command installs the typings file for the Jasmine test library and updates the `typings.config` - so we that we get it automatically the next time. -code-example(format=""). - npm run typings -- install jasmine --ambient --save -.l-sub-section - :marked - The [–– option](https://docs.npmjs.com/cli/run-script) is important; - it tells npm to pass all arguments to the right of `--` to the *typings* command. - - Learn about the features of the *typings* tool at its [site on github](https://github.com/typings/typings/blob/master/README.md). -:marked - #### Typing file collisions - - The TypeScript compiler does not tolerate redefinition of a type. For example, it throws an error if it's given two definitions for - the `Promise` type. - - Double definitions are common. In fact, the `typings` tool deliberately creates - duplicate sets of typings (for reasons best explained elsewhere). - Look in the project structure for the *typings folder* where we should find something like: -.filetree - .file typings - .children - .file browser - .children - .file ambient - .children - .file es6-shim - .children - .file es6-shim.d.ts - .children - .file main - .children - .file ambient - .children - .file es6-shim - .children - .file es6-shim.d.ts - .children - .file browser.d.ts - .file main.d.ts -:marked - The `es6-shim` typings are duplicated and the `browser.d.ts` and `main.d.ts` have overlapping content. - - We must tell the compiler to ignore one or the other. - We removed the `main` set from consideration in the `exclude` section of our `tsconfig.json` file: -+makeJson('quickstart/ts/tsconfig.1.json', {paths: 'exclude'}, 'tsconfig.json (exclude)')(format=".") -:marked - - -.l-main-section -:marked - - ## Appendix: SystemJS Configuration - - The QuickStart uses [SystemJS](https://github.com/systemjs/systemjs) to load application - and library modules. - There are alternatives that work just fine including the well-regarded [webpack](https://webpack.github.io/). - SystemJS happens to be a good choice but we want to be clear that it was a choice and not a preference. - - All module loaders require configuration and all loader configuration - becomes complicated rather quickly as soon as the file structure diversifies and - we start thinking about building for production and performance. - - We suggest becoming well-versed in the loader of your choice. -.l-sub-section - :marked - Learn more about SystemJS configuration [here](https://github.com/systemjs/systemjs/blob/master/docs/config-api.md). -:marked - With those cautions in mind, what are we doing here? -+makeExample('quickstart/ts/index.html', 'systemjs', 'index.html (System configuration)')(format=".") -:marked - The `packages` node tells SystemJS what to do when it sees a request for a - module from the `app/` folder. - - Our QuickStart makes such requests when one of its - application TypeScript files has an import statement like this: -+makeExample('quickstart/ts/app/main.ts', 'app-component', 'main.ts (excerpt)')(format=".") -:marked - Notice that the module name (after `from`) does not mention a filename extension. - The `packages:` configuration tells SystemJS to default the extension to 'js', a JavaScript file. - - That makes sense because we transpile TypeScript to JavaScript - *before* running the application. - -.l-sub-section - :marked - In the live example on plunker we transpile (AKA compile) to JavaScript in the browser - on the fly. That's fine for a demo. That's not our preference for development or production. - - We recommend transpiling (AKA compiling) to JavaScript during a build phase - before running the application for several reasons including: - - * We see compiler warnings and errors that are hidden from us in the browser. - - * Pre-compilation simpifies the module loading process and - it's much easier to diagnose problem when this is a separate, external step. - - * Pre-compilation means a faster user experience because the browser doesn't waste time compiling. - - * We iterate development faster because we only re-compile changed files. - We notice the difference as soon as the app grows beyond a handful of files. - - * Pre-compilation fits into a continuous integration process of build, test, deploy. -:marked - The `System.import` call tells SystemJS to import the `main` file - (`main.js` ... after transpiling `main.ts`, remember?). - `main` is where we tell Angular to launch the application. - We also catch and log launch errors to the console. - - All other modules are loaded upon request - either by an import statement or by Angular itself. - -.l-main-section -:marked - - ## Appendix: **main.ts** - - ### Bootstrapping is platform-specific - We import the `bootstrap` function from `angular2/platform/browser`, - not `angular2/core`. There's a good reason. - - We only call "core" those capabilities that are the same across all platform targets. - True, most Angular applications run only in a browser and we'll call the bootstrap function from - this library most of the time. It's pretty "core" if we're always writing for a browser. - - But it is possible to load a component in a different enviroment. - - We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/) or [NativeScript](https://www.nativescript.org/). - - We might wish to render the first page of our application on the server - to improve launch performance or facilitate - [SEO](http://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf). - - These targets require a different kind of bootstrap function that we'd import from a different library. - - ### Why do we create a separate ***main.ts*** file? - - The *main.ts* file is tiny. This is just a QuickStart. - We could have folded its few lines into the `app.component` file - and spared ourselves some complexity. - - We didn't for what we believe to be good reasons: - 1. Doing it right is easy - 1. Testability - 1. Reusability - 1. Separation of concerns - 1. We learned about import and export - - ### It's easy - Sure it's an extra step and an extra file. How hard is that in the scheme of things? - - We'll see that a separate `main.ts` is beneficial for *most* apps - even if it isn't critical for the QuickStart. - Let's develop good habits now while the cost is low. - - ### Testability - We should be thinking about testability from the beginning - even if we know we'll never test the QuickStart. - - It is difficult to unit test a component when there is a call to `bootstrap` in the same file. - As soon as we load the component file to test the component, - the `bootstrap` function tries to load the application in the browser. - It throws an error because we're not expecting to run the entire application, - just test the component. - - Relocating the `bootstrap` function to `main.ts` eliminates this spurious error - and leaves us with a clean component module file. - - ### Reusability - We refactor, rename, and relocate files as our application evolves. - We can't do any of those things while the file calls `bootstrap`. - We can't move it. - We can't reuse the component in another application. - We can't pre-render the component on the server for better performance. - - ### Separation of concerns - A component's responsibility is to present and manage a view. - - Launching the application has nothing to do with view management. - That's a separate concern. The friction we're encountering in testing and reuse - stems from this unnecessary mix of responsibilities. - - ### Import/Export - - While writing a separate `main.ts` file we learned an essential Angular skill: - how to export from one module and import into another. - We'll do a lot of that as we learn more Angular. diff --git a/public/resources/css/layout/_layout.scss b/public/resources/css/layout/_layout.scss index 3f0babea9a..76bb04b0e8 100644 --- a/public/resources/css/layout/_layout.scss +++ b/public/resources/css/layout/_layout.scss @@ -139,7 +139,29 @@ } } +button.verbose { + font-size: ($unit * 3); + @media handheld and (max-width: $phone-breakpoint), + screen and (max-device-width: $phone-breakpoint), + screen and (max-width: $tablet-breakpoint) { + font-size: ($unit * 2); + } +} +button.verbose.on {display: none} +.l-verbose-section { + margin: 0px 0px ($unit * 4) 0px; + padding-left: ($unit * 2); + //background: lighten($light, 5%); + border-left: ($unit / 6) solid $grey; + border-radius: ($unit / 6); +} +.l-verbose-inherit { + margin: 0; + padding: 0; + border-left: 0; + border-radius: 0; +} /* * Margins & Padding