parent
a1c5d44468
commit
40312da5b0
|
@ -0,0 +1,25 @@
|
|||
// #docregion
|
||||
library developer_guide_intro.backend_service;
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:developer_guide_intro/logger_service.dart';
|
||||
import 'package:developer_guide_intro/hero.dart';
|
||||
|
||||
@Injectable()
|
||||
class BackendService {
|
||||
final Logger _logger;
|
||||
List getAll(type) {
|
||||
// TODO get from the database and return as a promise
|
||||
if (type == Hero) {
|
||||
return [
|
||||
new Hero('Windstorm', power: 'Weather mastery'),
|
||||
new Hero('Mr. Nice', power: 'Killing them with kindness'),
|
||||
new Hero('Magneta', power: 'Manipulates metalic objects')
|
||||
];
|
||||
}
|
||||
_logger.error('Cannot get object of this type');
|
||||
throw new ArgumentError("TODO: put log content here");
|
||||
}
|
||||
|
||||
BackendService(Logger this._logger);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// #docregion
|
||||
library developer_guide_intro.hero;
|
||||
|
||||
class Hero {
|
||||
static int _nextId = 1;
|
||||
int id;
|
||||
String name;
|
||||
String power;
|
||||
|
||||
Hero(this.name, {this.power}) {
|
||||
id = _nextId++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// #docregion
|
||||
library developer_guide_intro.hero_detail_component;
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:developer_guide_intro/hero.dart';
|
||||
|
||||
@Component(selector: 'hero-detail', templateUrl: 'hero_detail_component.html')
|
||||
class HeroDetailComponent {
|
||||
@Input()
|
||||
Type hero = Hero;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<hr>
|
||||
<h4>{{hero.name}} Detail</h4>
|
||||
<div>Id: {{hero.id}}</div>
|
||||
<div>Name:
|
||||
<!-- #docregion ng-model -->
|
||||
<input [(ngModel)]="hero.name"></div>
|
||||
<!-- #enddocregion ng-model -->
|
||||
<div>Power:<input [(ngModel)]="hero.power">
|
||||
</div>
|
|
@ -0,0 +1,38 @@
|
|||
// #docplaster
|
||||
library developer_guide_intro.hero_list_component;
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:developer_guide_intro/hero.dart';
|
||||
import 'package:developer_guide_intro/hero_detail_component.dart';
|
||||
import 'package:developer_guide_intro/hero_service.dart';
|
||||
|
||||
// #docregion metadata
|
||||
// #docregion providers
|
||||
@Component(
|
||||
// #enddocregion providers
|
||||
selector: 'hero-list',
|
||||
templateUrl: 'hero_list_component.html',
|
||||
directives: const [HeroDetailComponent],
|
||||
// #docregion providers
|
||||
providers: const [HeroService])
|
||||
// #enddocregion providers
|
||||
// #enddocregion metadata
|
||||
/*
|
||||
// #docregion metadata, providers
|
||||
class HeroListComponent { ... }
|
||||
// #enddocregion metadata, providers
|
||||
*/
|
||||
// #docregion class
|
||||
class HeroListComponent {
|
||||
List<Hero> heroes;
|
||||
Hero selectedHero;
|
||||
// #docregion ctor
|
||||
HeroListComponent(HeroService heroService) {
|
||||
heroes = heroService.getHeroes();
|
||||
}
|
||||
// #enddocregion ctor
|
||||
selectHero(Hero hero) {
|
||||
selectedHero = hero;
|
||||
}
|
||||
}
|
||||
// #enddocregion class
|
|
@ -0,0 +1,8 @@
|
|||
<!-- #docregion -->
|
||||
<h2>Hero List</h2>
|
||||
|
||||
<div *ngFor="#hero of heroes" (click)="selectHero(hero)">
|
||||
{{hero.name}}
|
||||
</div>
|
||||
|
||||
<hero-detail *ngIf="selectedHero != null" [hero]="selectedHero"></hero-detail>
|
|
@ -0,0 +1,10 @@
|
|||
<!--#docregion binding -->
|
||||
<div ... >{{hero.name}}</div>
|
||||
<hero-detail ... [hero]="selectedHero"></hero-detail>
|
||||
<div ... (click)="selectHero(hero)">...</div>
|
||||
<!--#enddocregion binding -->
|
||||
|
||||
<!--#docregion structural -->
|
||||
<div *ngFor="#hero of heroes" ...>...</div>
|
||||
<hero-detail *ngIf="selectedHero != null" ...></hero-detail>
|
||||
<!--#enddocregion structural -->
|
|
@ -0,0 +1,20 @@
|
|||
library developer_guide_intro.hero_service;
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:developer_guide_intro/hero.dart';
|
||||
import 'package:developer_guide_intro/backend_service.dart';
|
||||
import 'package:developer_guide_intro/logger_service.dart';
|
||||
|
||||
// #docregion class
|
||||
@Injectable()
|
||||
class HeroService {
|
||||
final BackendService _backendService;
|
||||
final Logger _logger;
|
||||
HeroService(Logger this._logger, BackendService this._backendService);
|
||||
List<Hero> getHeroes() {
|
||||
List<Hero> heroes = _backendService.getAll(Hero);
|
||||
_logger.log('Got ${heroes.length} heroes from the server.');
|
||||
return heroes;
|
||||
}
|
||||
}
|
||||
// #enddocregion class
|
|
@ -0,0 +1,18 @@
|
|||
// #docregion
|
||||
library developer_guide_intro.logger_service;
|
||||
|
||||
import 'dart:html';
|
||||
|
||||
import 'package:angular2/angular2.dart';
|
||||
|
||||
/// A service for logging messages of various types.
|
||||
///
|
||||
/// We could switch this implementation to use package:logging.
|
||||
@Injectable()
|
||||
class Logger {
|
||||
void log(Object msg) => window.console.log(msg);
|
||||
|
||||
void error(Object msg) => window.console.error(msg);
|
||||
|
||||
void warn(Object msg) => window.console.warn(msg);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
name: developer_guide_intro
|
||||
description: Developer Guide Intro
|
||||
version: 0.0.1
|
||||
dependencies:
|
||||
angular2: 2.0.0-beta.0
|
||||
browser: ^0.10.0
|
||||
transformers:
|
||||
- angular2:
|
||||
platform_directives: 'package:angular2/src/common/directives.dart#CORE_DIRECTIVES'
|
||||
entry_points: web/main.dart
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Intro to Angular 2</title>
|
||||
<script defer src="main.dart" type="application/dart"></script>
|
||||
<script defer src="packages/browser/dart.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<hero-list>Loading...</hero-list>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
// #docregion
|
||||
import 'package:angular2/bootstrap.dart';
|
||||
import 'package:developer_guide_intro/backend_service.dart';
|
||||
import 'package:developer_guide_intro/hero_service.dart';
|
||||
import 'package:developer_guide_intro/logger_service.dart';
|
||||
import 'package:developer_guide_intro/hero_list_component.dart';
|
||||
|
||||
main() {
|
||||
// #docregion bootstrap
|
||||
bootstrap(HeroListComponent, [BackendService, HeroService, Logger]);
|
||||
// #enddocregion bootstrap
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
"guide": {
|
||||
"icon": "list",
|
||||
"title": "Step By Step Guide",
|
||||
"title": "Developers Guide",
|
||||
"banner": "Angular 2 is currently in Beta."
|
||||
},
|
||||
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
"_listtype": "ordered",
|
||||
|
||||
"index": {
|
||||
"title": "Step By Step Guide"
|
||||
"title": "Developers Guide"
|
||||
},
|
||||
|
||||
"cheatsheet": {
|
||||
"title": "Angular Cheat Sheet"
|
||||
},
|
||||
|
||||
"setup": {
|
||||
"title": "Getting Started"
|
||||
"architecture": {
|
||||
"title": "Architecture Overview"
|
||||
},
|
||||
|
||||
"displaying-data": {
|
||||
|
|
|
@ -0,0 +1,452 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:marked
|
||||
Angular 2 is a framework to help us build client applications in HTML and
|
||||
either JavaScript or a language (like Dart or TypeScript) that compiles to JavaScript.
|
||||
Angular 2 for Dart is published as the `angular2` package, which
|
||||
(like many other Dart packages) is available via the Pub tool.
|
||||
|
||||
With Angular, we write applications by composing HTML *templates* with Angularized markup,
|
||||
writing *component* classes to manage those templates, adding application logic in *services*,
|
||||
and handing the top root component to Angular's *bootstrapper*.
|
||||
|
||||
Angular takes over, presenting our application content in a browser and responding to user interactions
|
||||
according to the instructions we provided.
|
||||
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/airplane.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
Of course there is more to it than this.
|
||||
We're cruising at high altitude in this overview.
|
||||
We're looking for landmarks. We should expect the object below to be fuzzy and obscured by occasional clouds.
|
||||
Details become more clear and precise when we land in the chapters themselves.
|
||||
<br clear="all">
|
||||
|
||||
:marked
|
||||
An Angular 2 for Dart application rests on seven main building blocks:
|
||||
1. [Components](#component)
|
||||
1. [Templates](#template)
|
||||
1. [Metadata](#metadata)
|
||||
1. [Data binding](#data-binding)
|
||||
1. [Directives](#directive)
|
||||
1. [Services](#service)
|
||||
1. [Dependency injection](#dependency-injection)
|
||||
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/overview.png" alt="overview" style="margin-left:-40px;" width="700")
|
||||
:marked
|
||||
Learn these seven and we're on our way.
|
||||
|
||||
.l-main-section
|
||||
<a id="component"></a>
|
||||
:marked
|
||||
## Components
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
A **component** controls a patch of screen real estate that we could call a *view*.
|
||||
A set of navigation links, a list of heroes, a hero editor ...
|
||||
they're all views controlled by components.
|
||||
|
||||
We define a component's application logic — what it does to support the view — inside a class.
|
||||
The class interacts with the view through an API of properties and methods.
|
||||
|
||||
<a id="component-code"></a>
|
||||
A `HeroListComponent`, for example, might have a `heroes` property that returns an array of heroes
|
||||
that it acquired from a service.
|
||||
It might have a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||
The component might be a class like this:
|
||||
|
||||
+makeExample('architecture/dart/lib/hero_list_component.dart', 'class', 'lib/hero_list_component.dart')
|
||||
:marked
|
||||
Angular creates, updates, and destroys components as the user moves through the application.
|
||||
The developer can take action at each moment in this lifecycle through optional lifecycle hooks.
|
||||
<!-- PENDING: What was that supposed to link to? -->
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
We may wonder who is calling the component's constructor? Who provides the service parameter?
|
||||
For the moment, have faith that Angular will call the constructor and deliver an
|
||||
appropriate `HeroService` when we need it.
|
||||
|
||||
.l-main-section
|
||||
<a id="template"></a>
|
||||
:marked
|
||||
## Templates
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
We define a component's view with its companion **template**. A template is a form of HTML
|
||||
that tells Angular how to render the component.
|
||||
|
||||
A template looks like regular HTML much of the time ... and then it gets a bit strange. Here is a
|
||||
template for our `HeroListComponent`:
|
||||
+makeExample('architecture/dart/lib/hero_list_component.html', null, 'lib/hero_list_component.html')
|
||||
:marked
|
||||
This template features typical HTML elements like `<h2>` and `<div>`.
|
||||
But what are `*ngFor`, <code>{‌{hero.name}}</code>, `(click)`, `[hero]`, and `<hero-detail>`?
|
||||
They're examples of Angular's template syntax. <!-- TODO: link to template-syntax.html -->
|
||||
We'll grow accustomed to that syntax and may even learn to love it.
|
||||
|
||||
Take a look at the last line,
|
||||
which has the `<hero-detail>` tag.
|
||||
That tag adds a custom element representing a component we haven't seen yet,
|
||||
a `HeroDetailComponent`.
|
||||
|
||||
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` we've seen.
|
||||
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
|
||||
hero that the user selects from the list presented by the the `HeroListComponent`.
|
||||
The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
|
||||
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
Notice how `<hero-detail>` rests comfortably among native HTML elements.
|
||||
We can and _will_ mix our custom components with native HTML in the same layouts.
|
||||
|
||||
In this manner we'll compose complex component trees to build out our richly featured application.
|
||||
<br clear="all">
|
||||
|
||||
.l-main-section
|
||||
<a id="metadata"></a>
|
||||
:marked
|
||||
## Metadata
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
<p style="padding-top:10px">Metadata tells Angular how to process a class.</p>
|
||||
<br clear="all">
|
||||
:marked
|
||||
[Looking back at the code](#component-code) for `HeroListComponent`, we see that it's just a class.
|
||||
There is no evidence of a framework, no "Angular" in it at all.
|
||||
|
||||
In fact, it really is *just a class*. It's not a component until we *tell Angular about it*.
|
||||
|
||||
We tell Angular that `HeroListComponent` is a component by attaching **metadata** to the class.
|
||||
|
||||
In Dart, we attach metadata by using an **annotation**.
|
||||
Here's some metadata for `HeroListComponent`:
|
||||
|
||||
+makeExample('architecture/dart/lib/hero_list_component.dart', 'metadata', 'lib/hero_list_component.dart')
|
||||
:marked
|
||||
Here we see the `@Component` annotation, which (no surprise) identifies the class
|
||||
immediately below it as a component class.
|
||||
|
||||
Annotations often have configuration parameters.
|
||||
The `@Component` annotation takes parameters to provide the
|
||||
information Angular needs to create and present the component and its view.
|
||||
|
||||
Here we see a few of the possible `@Component` parameters:
|
||||
|
||||
* `selector`: A CSS selector that tells Angular to create and insert an instance of this component
|
||||
where it finds a `<hero-list>` tag in *parent* HTML.
|
||||
For example, if an app's HTML contains `<hero-list></hero-list>`, then
|
||||
Angular inserts an instance of the `HeroListComponent` view between those tags.
|
||||
|
||||
* `templateUrl`: The address of this component's template, which we showed [above](#the-template).
|
||||
|
||||
* `directives`: An array of the components or directives that *this* template requires.
|
||||
We saw in the last line of our template that we expect Angular to insert a `HeroDetailComponent`
|
||||
in the space indicated by `<hero-detail>` tags.
|
||||
Angular will do so only if we mention the `HeroDetailComponent` in this `directives` array.
|
||||
|
||||
* `providers`: An array of **dependency injection providers** for services that the component requires.
|
||||
This is one way to tell Angular that our component's constructor requires a `HeroService`
|
||||
so it can get the list of heroes to display. We'll get to dependency injection later.
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px" )
|
||||
|
||||
:marked
|
||||
At runtime, Angular discovers the metadata specified by the `@Component`
|
||||
annotation. That's how Angular learns how to do "the right thing".
|
||||
|
||||
The template, metadata, and component together describe the view.
|
||||
|
||||
We apply other metadata annotations in a similar fashion to guide Angular behavior.
|
||||
`@Injectable`, `@Input`, `@Output`, and `@RouterConfig` are a few of the more popular annotations
|
||||
we'll master as our Angular knowledge grows.
|
||||
<br clear="all">
|
||||
:marked
|
||||
The architectural takeaway is that we must add metadata to our code
|
||||
so that Angular knows what to do.
|
||||
|
||||
.l-main-section
|
||||
<a id="data-binding"></a>
|
||||
:marked
|
||||
## Data binding
|
||||
Without a framework, we would be responsible for pushing data values into the HTML controls and turning user responses
|
||||
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to
|
||||
read as any experienced jQuery programmer can attest.
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px" )
|
||||
:marked
|
||||
Angular supports **data binding**,
|
||||
a mechanism for coordinating parts of a template with parts of a component.
|
||||
We add binding markup to the template HTML to tell Angular how to connect both sides.
|
||||
|
||||
There are four forms of data binding syntax. Each form has a direction — to the DOM, from the DOM, or in both directions —
|
||||
as indicated by the arrows in the diagram.
|
||||
<br clear="all">
|
||||
:marked
|
||||
We saw three forms of data binding in our [example](#template) template:
|
||||
+makeExample('architecture/dart/lib/hero_list_component_1.html', 'binding')(format=".")
|
||||
:marked
|
||||
* The <code>{‌{hero.name}}</code> [interpolation](displaying-data.html#interpolation)
|
||||
displays the component's `hero.name` property value within the `<div>` tags.
|
||||
|
||||
* The `[hero]` property binding <!-- TODO: link to template-syntax.html#property-binding-->
|
||||
passes the value of `selectedHero` from
|
||||
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
|
||||
|
||||
* The `(click)` [event binding](user-input.html#click) calls the component's `selectHero` method when the user clicks a hero's name.
|
||||
|
||||
**Two-way data binding** is an important fourth form
|
||||
that combines property and event binding in a single notation, using the `ngModel` directive.
|
||||
We didn't have a two-way binding in the `HeroListComponent` template;
|
||||
here's an example from the `HeroDetailComponent` template:
|
||||
|
||||
+makeExample('architecture/dart/lib/hero_detail_component.html', 'ng-model', 'lib/hero_detail_component.html (excerpt)')(format=".")
|
||||
:marked
|
||||
In two-way binding, a data property value flows to the input box from the component as with property binding.
|
||||
The user's changes also flow back to the component, resetting the property to the latest value,
|
||||
as with event binding.
|
||||
|
||||
Angular processes *all* data bindings once per JavaScript event cycle,
|
||||
depth-first from the root of the application component tree.
|
||||
<!-- PENDING: clarify what "depth-first from the root" really means,
|
||||
or reassure that they'll learn it soon. -->
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
We don't know all the details yet,
|
||||
but it's clear from these examples that data binding plays an important role in communication
|
||||
between a template and its component.
|
||||
<br clear="all">
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
Data binding is also important for communication between parent and child components.
|
||||
<br clear="all">
|
||||
|
||||
.l-main-section
|
||||
<a id="directive"></a>
|
||||
:marked
|
||||
## Directives
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
|
||||
according to the instructions given by **directives**.
|
||||
|
||||
A directive is a class with directive metadata. In Dart we apply the `@Directive` annotation
|
||||
to attach metadata to the class.
|
||||
<br clear="all">
|
||||
:marked
|
||||
We already met one form of directive: the component. A component is a *directive-with-a-template*;
|
||||
a `@Component` annotation is actually a `@Directive` annotation extended with template-oriented features.
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
While **a component is technically a directive**,
|
||||
components are so distinctive and central to Angular applications that we chose
|
||||
to separate components from directives in this architectural overview.
|
||||
:marked
|
||||
Two *other* kinds of directives exist: _structural_ and _attribute_ directives.
|
||||
|
||||
They tend to appear within an element tag like attributes,
|
||||
sometimes by name but more often as the target of an assignment or a binding.
|
||||
|
||||
**Structural** directives alter layout by adding, removing, and replacing elements in DOM.
|
||||
|
||||
Our [example](#template) template uses two built-in structural directives:
|
||||
+makeExample('architecture/dart/lib/hero_list_component_1.html', 'structural')(format=".")
|
||||
:marked
|
||||
* [`*ngFor`](displaying-data.html#ng-for) tells Angular to stamp out one `<div>` per hero in the `heroes` list.
|
||||
* [`*ngIf`](displaying-data.html#ng-if) includes the `HeroDetail` component only if a selected hero exists.
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
In Dart, **the only value that is true is the boolean value `true`**; all
|
||||
other values are false. JavaScript and TypeScript, in contrast, treat values
|
||||
such as 1 and most non-null objects as true. For this reason, the JavaScript
|
||||
and TypeScript versions of this app can use just `selectedHero` as the value
|
||||
of the `*ngIf` expression. The Dart version must use a boolean operator such
|
||||
as `!=` instead.
|
||||
|
||||
:marked
|
||||
**Attribute** directives alter the appearance or behavior of an existing element.
|
||||
In templates they look like regular HTML attributes, hence the name.
|
||||
|
||||
The `ngModel` directive, which implements two-way data binding, is
|
||||
an example of an attribute directive. `ngModel` modifies the behavior of
|
||||
an existing element (typically an `<input>`)
|
||||
by setting its display value property and responding to change events.
|
||||
|
||||
+makeExample('architecture/dart/lib/hero_detail_component.html', 'ng-model')(format=".")
|
||||
:marked
|
||||
Angular ships with a small number of other directives that either alter the layout structure
|
||||
(for example, `ngSwitch`) <!-- TODO: link to template-syntax.html#ng-switch -->
|
||||
or modify aspects of DOM elements and components
|
||||
(for example, `ngStyle` and `ngClass`).
|
||||
<!-- PENDING: link to template-syntax.html#ng-style template-syntax.html#ng-class-->
|
||||
|
||||
Of course, we can also write our own directives. Components such as
|
||||
`HeroListComponent` are one kind of custom directive.
|
||||
<!-- PENDING: link to where to learn more about other kinds! -->
|
||||
|
||||
.l-main-section
|
||||
<a id="service"></a>
|
||||
:marked
|
||||
## Services
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
_Services_ is a broad category encompassing any value, function, or feature that our application needs.
|
||||
|
||||
Almost anything can be a service.
|
||||
A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.
|
||||
<br clear="all">
|
||||
:marked
|
||||
Examples include:
|
||||
* logging service
|
||||
* data service
|
||||
* message bus
|
||||
* tax calculator
|
||||
* application configuration
|
||||
|
||||
There is nothing specifically _Angular_ about services. Angular itself has no definition of a service.
|
||||
There is no service base class, and no place to register a service.
|
||||
|
||||
Yet services are fundamental to any Angular application. Our components are big consumers of services.
|
||||
|
||||
We prefer our component classes lean. Our components don't fetch data from the server,
|
||||
they don't validate user input, and they don't log directly to console. They delegate such tasks to services.
|
||||
|
||||
A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template)
|
||||
and the application logic (which often includes some notion of a _model_).
|
||||
A good component presents properties and methods for data binding.
|
||||
It delegates everything nontrivial to services.
|
||||
|
||||
Angular doesn't *enforce* these principles.
|
||||
It won't complain if we write a "kitchen sink" component with 3000 lines.
|
||||
|
||||
Angular does help us *follow* these principles by making it easy to factor our
|
||||
application logic into services and make those services available to components through *dependency injection*.
|
||||
|
||||
.l-main-section
|
||||
<a id="dependency-injection"></a>
|
||||
:marked
|
||||
## Dependency injection
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
Dependency injection is a way to supply a new instance of a class
|
||||
with the fully-formed dependencies it requires. Most dependencies are services.
|
||||
Angular uses dependency injection to provide new components with the services they need.
|
||||
<br clear="all">
|
||||
:marked
|
||||
Angular can tell which services a component needs by looking at the types of its constructor parameters.
|
||||
For example, the constructor of our `HeroListComponent` needs a `HeroService`:
|
||||
+makeExample('architecture/dart/lib/hero_list_component.dart', 'ctor', 'lib/hero_list_component.dart (excerpt)')(format='.')
|
||||
:marked
|
||||
When Angular creates a component, it first asks an **injector** for
|
||||
the services that the component requires.
|
||||
|
||||
An injector maintains a container of service instances that it has previously created.
|
||||
If a requested service instance is not in the container, the injector makes one and adds it to the container
|
||||
before returning the service to Angular.
|
||||
When all requested services have been resolved and returned,
|
||||
Angular can call the component's constructor with those services as arguments.
|
||||
This is what we mean by *dependency injection*.
|
||||
|
||||
The process of `HeroService` injection looks a bit like this:
|
||||
figure
|
||||
img(src="/resources/images/devguide/architecture/injector-injects.png" alt="Service" )
|
||||
:marked
|
||||
If the injector doesn't have a `HeroService`, how does it know how to make one?
|
||||
|
||||
In brief, we must have previously registered a **provider** of the `HeroService` with the injector.
|
||||
A provider is something that can create or return a service, typically the service class itself.
|
||||
|
||||
We can register providers at any level of the application component tree.
|
||||
We often do so at the root when we bootstrap the application so that
|
||||
the same instance of a service is available everywhere.
|
||||
+makeExample('architecture/dart/web/main.dart', 'bootstrap', 'web/main.dart (excerpt)')(format='.')
|
||||
:marked
|
||||
Alternatively, we might register at a component level:
|
||||
+makeExample('architecture/dart/lib/hero_list_component.dart', 'providers', 'lib/hero_list_component.dart (excerpt)')(format='.')
|
||||
:marked
|
||||
Registering at a component level means we get a new instance of the
|
||||
service with each new instance of that component.
|
||||
|
||||
<!-- We've vastly oversimplified dependency injection for this overview.
|
||||
The full story is in the [Dependency Injection](dependency-injection.html) chapter. -->
|
||||
|
||||
Points to remember about dependency injection:
|
||||
|
||||
* Dependency injection is wired into the Angular framework and used everywhere.
|
||||
|
||||
* The *injector* is the main mechanism.
|
||||
* An injector maintains a *container* of service instances that it created.
|
||||
* An injector can create a new service instance from a *provider*.
|
||||
|
||||
* A *provider* is a recipe for creating a service.
|
||||
|
||||
* We register *providers* with injectors.
|
||||
|
||||
<a id="other-stuff"></a>
|
||||
.l-main-section
|
||||
:marked
|
||||
## Other stuff
|
||||
|
||||
We've learned just a bit about the seven main building blocks of an Angular application:
|
||||
1. [Components](#component)
|
||||
1. [Templates](#template)
|
||||
1. [Metadata](#metadata)
|
||||
1. [Data binding](#data-binding)
|
||||
1. [Directives](#directive)
|
||||
1. [Services](#service)
|
||||
1. [Dependency injection](#dependency-injection)
|
||||
|
||||
That's a foundation for everything else in an Angular application,
|
||||
and it's more than enough to get going.
|
||||
But it doesn't include everything we'll need or want to know.
|
||||
|
||||
Here is a brief, alphabetical list of other important Angular features and services.
|
||||
Most of them are covered in this Developers Guide (or soon will be).
|
||||
|
||||
>**Animations:** A forthcoming animation library makes it easy for developers to animate component behavior
|
||||
without deep knowledge of animation techniques or CSS.
|
||||
|
||||
>**Bootstrap:** A method to configure and launch the root application component.
|
||||
|
||||
>**Change detection:** Learn how Angular decides that a component property value has changed and
|
||||
when to update the screen.
|
||||
Learn how it uses **zones** to intercept asynchronous activity and run its change detection strategies.
|
||||
|
||||
>**Component router:** With the component Router service, users can navigate a multi-screen application
|
||||
in a familiar web browsing style using URLs.
|
||||
|
||||
>**Events:** The DOM raises events. So can components and services. Angular offers mechanisms for
|
||||
publishing and subscribing to events including an implementation of the [RxJS Observable](https://github.com/zenparsing/es-observable) proposal.
|
||||
|
||||
>**[Forms](forms.html):** Support complex data entry scenarios with HTML-based validation and dirty checking.
|
||||
|
||||
>**HTTP:** Communicate with a server to get data, save data, and invoke server-side actions with this Angular HTTP client.
|
||||
|
||||
>**Lifecycle hooks:** We can tap into key moments in the lifetime of a component, from its creation to its destruction,
|
||||
by implementing the lifecycle hook interfaces.
|
||||
|
||||
>**Pipes:** Services that transform values for display.
|
||||
We can put pipes in our templates to improve the user experience. Consider
|
||||
this `currency` pipe expression:
|
||||
<div style="margin-left:40px">
|
||||
code-example(language="javascript" linenumbers=".").
|
||||
price | currency:'USD':true'
|
||||
</div>
|
||||
:marked
|
||||
>It displays a price of "42.33" as `$42.33`.
|
||||
|
||||
>**Testing:** Angular provides a
|
||||
[testing library](https://pub.dartlang.org/packages/angular2_testing)
|
||||
to run unit tests on our application parts as they interact with the Angular framework.
|
|
@ -60,6 +60,7 @@
|
|||
All three of these files remain similar in the rest of the examples,
|
||||
so we'll focus on what changes.
|
||||
|
||||
<a id="interpolation"></a>
|
||||
.l-main-section
|
||||
h2#section-showing-properties-with-interpolation Showing properties with interpolation
|
||||
p.
|
||||
|
@ -152,6 +153,7 @@
|
|||
|
||||
p Reload the app, and you'll now see the seconds updating automatically.
|
||||
|
||||
<a id="ng-for"></a>
|
||||
.l-main-section
|
||||
h2#Create-an-array Display an iterable using *ng-for
|
||||
p Moving up from a single value, create a property that's a list of values.
|
||||
|
@ -268,6 +270,7 @@
|
|||
code-example(language="dart").
|
||||
@Component(selector: 'display', <span class="pnk">viewProviders: const [FriendsService]</span>)
|
||||
|
||||
<a id="ng-if"></a>
|
||||
.l-main-section
|
||||
h2#Conditionally-displaying-data-with-NgIf Conditionally display data using *ng-if
|
||||
p.
|
||||
|
|
|
@ -1,10 +1,93 @@
|
|||
- var number = 1;
|
||||
ul.is-plain
|
||||
for page, slug in public.docs[current.path[1]][current.path[2]].guide._data
|
||||
include ../../../../_includes/_util-fns
|
||||
|
||||
if slug != '_listtype' && slug != 'index'
|
||||
- var url = "/docs/" + current.path[1] + "/" + current.path[2] + "/" + current.path[3] + "/" + slug + ".html"
|
||||
- var num = number++
|
||||
:marked
|
||||
This Developers Guide is a practical guide to Angular for experienced programmers who
|
||||
are building client applications in HTML and Dart.
|
||||
figure
|
||||
img(src="/resources/images/devguide/intro/people.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||
:marked
|
||||
We are on a journey together to understand how Angular works and, more importantly,
|
||||
how to make it work for us. We look at our application requirements and we see problems to solve.
|
||||
<br clear="all">
|
||||
|
||||
li
|
||||
!= partial("../../../../_includes/_hover-card", { icon: "icon-number", number: num, name: page.title, url: url })
|
||||
* How do we get data onto the screen and handle user interactions?
|
||||
* How do we organize our code into manageable, cohesive chunks of functionality that work together?
|
||||
* What are the essential Angular building blocks and how do they help?
|
||||
* How do we minimize routine, mechanical coding in favor of declarative, higher level constructs without losing control?
|
||||
|
||||
This chapter begins the journey.
|
||||
|
||||
<a id="how-to-read"></a>
|
||||
:marked
|
||||
# How to read this guide
|
||||
Each chapter of this guide targets an Angular feature,
|
||||
showing how to use it to solve a programming problem.
|
||||
|
||||
All the chapters include code snippets ... snippets we can reuse in our own applications.
|
||||
Typically, these snippets are excerpts from a sample application that accompanies the chapter.
|
||||
|
||||
**All the source files** for each sample app are displayed together at the **end of each chapter.**
|
||||
|
||||
<!-- Although a few early chapters are written as tutorials, most later chapters
|
||||
don't explain how to build the accompanying sample.
|
||||
These non-tutorial chapters highlight key points in code but generally don't include the entire source. -->
|
||||
|
||||
<!-- We don't have to read this guide straight through. -->
|
||||
<!-- The "[Cheat Sheet](cheatsheet.html)" is a handy map to Angular overall. -->
|
||||
<!-- A few early chapters are arranged sequentially and best read together to establish a foundation in Angular.
|
||||
But most chapters stand on their own. We can browse to any of them as our interest or some necessity moves us. -->
|
||||
|
||||
Here is a learning path we might follow:
|
||||
|
||||
1. First, be familiar with Dart programming and with web concepts such as
|
||||
the DOM, HTML, and CSS. Dart tutorials such as
|
||||
[Get Started](https://www.dartlang.org/docs/tutorials/get-started/) and
|
||||
[Connect Dart & HTML](https://www.dartlang.org/docs/tutorials/connect-dart-html/)
|
||||
are a great way to start.
|
||||
|
||||
1. Follow the [QuickStart](../quickstart), which is the "Hello, World" of Angular 2.
|
||||
It shows how to set up the libraries and tools needed to write *any* Angular app.
|
||||
It ends with a "proof of life", a running Angular app.
|
||||
|
||||
1. Next, read the Developers Guide chapters in order:
|
||||
<!-- TODO: adjust this text once we have non-introductory/tutorial chapters -->
|
||||
1. The rest of this chapter, especially the Architecture overview
|
||||
1. [Displaying Data](displaying-data.html)
|
||||
1. [User Input](user-input.html)
|
||||
1. [Forms](forms.html)
|
||||
<!-- add dependency injection when it exists -->
|
||||
<!-- add text about template syntax, once that exists -->
|
||||
|
||||
1. Consider hopping over to the [TypeScript docs](/docs/ts/latest/)
|
||||
since they're currently ahead of the Dart docs. (We're working on that!)
|
||||
Especially check out the [Tutorial](/docs/ts/latest/tutorial/) and
|
||||
[Cheat Sheet](/docs/ts/latest/guide/cheatsheet.html), and the guide chapters
|
||||
[Dependency Injection](/docs/ts/latest/guide/dependency-injection.html)
|
||||
and [Template Syntax](/docs/ts/latest/guide/template-syntax.html).
|
||||
|
||||
<!-- Follow your own star from there, wherever it leads. -->
|
||||
|
||||
Don't miss the [Cheat Sheet](cheatsheet.html), a handy map to Angular.
|
||||
|
||||
<a id="toh"></a>
|
||||
.l-main-section
|
||||
:marked
|
||||
# Appendix: The Hero Staffing Agency
|
||||
|
||||
There's a backstory to the <!-- the "Tour of Heroes" and --> samples in this guide.
|
||||
|
||||
The world is full of crises large and small.
|
||||
Fortunately, courageous heroes are prepared to take on every challenge.
|
||||
The shadowy Hero Staffing Agency matches crises to heroes.
|
||||
|
||||
We are contract developers, hired by the Agency to build an application to manage their operations.
|
||||
The Agency maintains a stable of heroes with special powers.
|
||||
Ordinary humans submit crises as job requests. The heroes bid to take the job, and the Agency
|
||||
assigns each job accordingly.
|
||||
|
||||
Our application handles every detail of recruiting, tracking, and job assignment.
|
||||
For example, the [Forms](forms.html) chapter features a screen for
|
||||
entering personal information about heroes:
|
||||
|
||||
figure.image-display
|
||||
img(src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form")
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
.l-main-section
|
||||
|
||||
p.
|
||||
As long as you already
|
||||
<a href="https://www.dartlang.org/downloads/">have the Dart SDK</a>,
|
||||
getting started with Angular 2 is simple:
|
||||
|
||||
ol
|
||||
li Depend on the <b>angular2</b> pub package.
|
||||
li Create a Dart file that defines (directly or indirectly) a
|
||||
<b>root component</b> and <b>bootstraps</b> Angular.
|
||||
li Create an HTML file that uses the root component and points to the Dart file
|
||||
|
||||
p.
|
||||
You can use whichever editor or IDE you like,
|
||||
or just use the command-line tools that the Dart SDK provides.
|
||||
See <a href="http://www.dartlang.org/tools/">Dart Tools</a>
|
||||
for more information.
|
||||
|
||||
|
||||
h2#section-install Depend on angular2
|
||||
|
||||
p.
|
||||
To use Angular2 in your app, include angular2 as a dependency in
|
||||
your app's <b>pubspec.yaml</b> file. For example:
|
||||
|
||||
code-example(language="yaml").
|
||||
# pubspec.yaml
|
||||
name: getting_started
|
||||
description: Getting Started example
|
||||
version: 0.0.1
|
||||
dependencies:
|
||||
angular2: 2.0.0-alpha.45
|
||||
browser: ^0.10.0
|
||||
transformers:
|
||||
- angular2:
|
||||
entry_points: web/main.dart
|
||||
p.
|
||||
Run <b>pub get</b> to download the packages your app depends on.
|
||||
(<a href="https://www.dartlang.org/tools/">Dart-savvy editors and IDEs</a>
|
||||
typically run <code>pub get</code> for you.)
|
||||
|
||||
|
||||
.l-main-section
|
||||
h2#section-set-up-the-starting-component Write the Dart code
|
||||
|
||||
p.
|
||||
Next to your <code>pubspec.yaml</code> file,
|
||||
create a <code>web</code> subdirectory containing a Dart file
|
||||
(<code>main.dart</code>).
|
||||
Edit <code>main.dart</code>, adding a component class (<b>AppComponent</b>),
|
||||
configuring it to bind to the <code><my-app></code> element,
|
||||
and creating a top-level <code>main()</code> function that calls
|
||||
Angular's <code>bootstrap()</code> function.
|
||||
|
||||
code-example(language="dart" escape="html").
|
||||
// web/main.dart
|
||||
import 'package:angular2/angular2.dart';
|
||||
import 'package:angular2/bootstrap.dart';
|
||||
|
||||
@Component(selector: 'my-app')
|
||||
@View(template: '<h1>My first Angular 2 App</h1>')
|
||||
class AppComponent {}
|
||||
|
||||
main() {
|
||||
bootstrap(AppComponent);
|
||||
}
|
||||
|
||||
.l-main-section
|
||||
h2#section-create-an-entry-point Create an HTML file
|
||||
p.
|
||||
In the <code>web/</code> directory of your app,
|
||||
create an HTML file (<code>index.html</code>).
|
||||
Edit <code>index.html</code> to add a <code><my-app></code> element
|
||||
and call <code>main.dart</code>.
|
||||
|
||||
code-example(language="html").
|
||||
<!-- web/index.html -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Getting Started</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script async src="main.dart" type="application/dart"></script>
|
||||
<script async src="packages/browser/dart.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<my-app></my-app>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
.l-main-section
|
||||
h2#section-run-it Run the app!
|
||||
|
||||
p.
|
||||
Now run the app. How you do this depends on your tools.
|
||||
|
||||
ul
|
||||
li.
|
||||
If you're using <b>WebStorm</b> or <b>IntelliJ IDEA</b>,
|
||||
right-click <b>web/index.html</b>,
|
||||
and choose <b>Run 'index.html'</b>.
|
||||
|
||||
li.
|
||||
If you're using the command line and don't have Dartium,
|
||||
serve the app using <code>pub serve</code>,
|
||||
and then run it by visiting <b>http://localhost:8080</b> in a browser.
|
||||
Generating the JavaScript takes a few seconds when you first visit the page,
|
||||
and the generated JavaScript is currently large.
|
||||
The generated JavaScript will be smaller once
|
||||
Angular's transformer becomes available.
|
||||
|
||||
p.
|
||||
You should see something like this:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App")
|
||||
|
||||
.l-main-section
|
||||
h2#section-explanations Explanations
|
||||
|
||||
p This basic Angular app contains the structure for any app you'll build.
|
||||
|
||||
.l-sub-section
|
||||
h3 It's all a tree
|
||||
|
||||
p.
|
||||
You can think of an Angular app as a tree of components.
|
||||
The root component acts as the top-level container for the rest of your application.
|
||||
You've named this one <code>AppComponent</code>, but there's
|
||||
nothing special about the name; you can use whatever makes sense to you.
|
||||
|
||||
p.
|
||||
The root component's job is to give a location in the HTML file where
|
||||
your application can
|
||||
render through its element—in this case, <code><my-app></code>.
|
||||
There's nothing special about the HTML filename or the element name;
|
||||
you can pick whatever you like.
|
||||
|
||||
p.
|
||||
The root component loads the initial template for the application,
|
||||
which loads other components to perform
|
||||
whatever functions your application needs—menu bars, views, forms, and so on.
|
||||
We'll walk through examples of all of
|
||||
these in the following pages.
|
||||
|
||||
.l-sub-section
|
||||
h3 @Component and @View annotations
|
||||
|
||||
p.
|
||||
A component annotation describes details about the component.
|
||||
An annotation can be identified by its at-sign (<code>@</code>).
|
||||
p.
|
||||
The <code>@Component</code> annotation defines the HTML tag for
|
||||
the component by specifying the component's CSS selector.
|
||||
p.
|
||||
The <code>@View</code> annotation defines the HTML that
|
||||
represents the component.
|
||||
The component you wrote uses an inline template,
|
||||
but you can also have an external template.
|
||||
To use an external template,
|
||||
specify a <code>templateUrl</code> property and
|
||||
give it the path to the HTML file.
|
||||
|
||||
|
||||
p.
|
||||
Exciting! Not excited yet?
|
||||
Let's move on to <a href="displaying-data.html">Displaying Data</a>.
|
|
@ -81,6 +81,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<a id="click"></a>
|
||||
.l-main-section
|
||||
h2#section-add-todos-to-the-list Add todos to the list via button click
|
||||
p.
|
||||
|
|
Loading…
Reference in New Issue