Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

docs(guide): add dart version of structural directives #696

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions harp.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,15 @@
"bio": "Scott works for Google on the Material Design team, where he brings designers' dreams to life on the web.",
"type": "Google"
},

"kara": {
"name": "Kara Erickson",
"picture": "/resources/images/bios/kara-erickson.jpg",
"twitter": "karaforthewin",
"bio": "Kara is a software engineer on the Angular team at Google and a co-organizer of the Angular-SF Meetup. Prior to Google, she helped build UI components in Angular for guest management systems at OpenTable. She enjoys snacking indiscriminately and probably other things too.",
"type": "Google"
},

"pawel": {
"name": "Pawel Kozlowski",
"picture": "/resources/images/bios/pawel.jpg",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// #docregion
import 'package:angular2/angular2.dart';
import 'dart:async';

int nextId = 1;

@Component(
selector: 'heavy-loader',
template: '<span>heavy loader #{{id}} on duty!</span>')
class HeavyLoaderComponent implements OnInit, OnDestroy {
int id = nextId++;
@Input() List<String> logs;

ngOnInit() {
// Mock todo: get 10,000 rows of data from the server
_log(
"heavy-loader ${id} initialized, loading 10,000 rows of data from the server");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally like it this way but the style guide says to omit {} when they are not required

}

ngOnDestroy() {
// Mock todo: clean-up
_log("heavy-loader ${id} destroyed, cleaning up");
}

_log(String msg) {
logs.add(msg);
_tick();
}

/// Triggers the next round of Angular change detection
/// after one turn of the JavaScript cycle
/// ensuring display of msg added in onDestroy
_tick() {
new Future(() {});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really have an effect, a no-op callback in a Future that's not returned? Is this just for the side effect of zone intercepting this for change detection.
Is this telated to

You can. Call markForCheck on a change detector ref, and then call LifeCycle.tick.

(a comment in http://victorsavkin.com/post/110170125256/change-detection-in-angular-2)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kwalrath could give you a better feedback on this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just the Dart equivalent of the TS code, which I assume is just to kick the event loop. I have no real knowledge of how it works, and it's possible that without a return value it might be optimized away.

@adaojunior: Does the app behave differently when you comment out this line?

}
}
// #enddocregion
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// #docplaster
// #docregion
import 'package:angular2/angular2.dart';
import 'package:structural_directives/unless_directive.dart';
import 'package:structural_directives/heavy_loader_component.dart';

@Component(
selector: 'structural-directives',
templateUrl: 'structural_directives_component.html',
styles: const ['button { min-width: 100px; }'],
directives: const [UnlessDirective, HeavyLoaderComponent])
class StructuralDirectivesComponent {
List<String> heroes = ['Mr. Nice', 'Narco', 'Bombasto'];
bool condition = true;
bool isVisible = true;
List<String> logs = [];
String status = 'ready';

get hero => heroes[0];
}
//#enddocregion
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!-- #docplaster -->
<!-- #docregion -->
<h1>Structural Directives</h1>

<!-- #docregion structural-directives -->
<!-- #docregion asterisk -->
<div *ngIf="hero != null">{{hero}}</div>
<div *ngFor="#hero of heroes">{{hero}}</div>
<!-- #enddocregion asterisk -->
<!-- #docregion ngSwitch -->
<div [ngSwitch]="status">
<template [ngSwitchWhen]="'in-mission'">In Mission</template>
<template [ngSwitchWhen]="'ready'">Ready</template>
<template ngSwitchDefault>Unknown</template>
</div>
<!-- #enddocregion ngSwitch -->
<!-- #enddocregion structural-directives -->

<hr>

<button
(click)="condition = !condition"
[style.background] = "condition ? 'orangered': 'lightgreen'"
>
Set 'condition' to {{condition ? 'False': 'True'}}
</button>

<!-- #docregion ngIf -->
<p *ngIf="condition">
condition is true and ngIf is true.
</p>
<p *ngIf="!condition">
condition is false and ngIf is false.
</p>
<!-- #enddocregion ngIf -->
<!-- #docregion myUnless-->
<p *myUnless="condition">
condition is false and myUnless is true.
</p>

<p *myUnless="!condition">
condition is true and myUnless is false.
</p>
<!-- #enddocregion myUnless-->

<hr>

<!-- #docregion message-log -->
<div><!-- Visibility -->
<button (click)="isVisible = !isVisible">show | hide</button>
<heavy-loader [style.display]="isVisible ? 'inline' : 'none'" [logs]="logs"></heavy-loader>
</div>

<div><!-- NgIf -->
<button (click)="condition = !condition">if | !if</button>
<heavy-loader *ngIf="condition" [logs]="logs"></heavy-loader>
</div>

<h4>heavy-loader log:</h4>
<div *ngFor="#message of logs">{{message}}</div>
<!-- #enddocregion message-log -->

<hr>

<!-- #docregion template-tag -->
<p>
Hip!
</p>
<template>
<p>
Hip!
</p>
</template>
<p>
Hooray!
</p>
<!-- #enddocregion template-tag -->

<hr>

<!-- #docregion ngIf-template -->
<!-- Examples (A) and (B) are the same -->
<!-- (A) *ngIf paragraph -->
<p *ngIf="condition">
Our heroes are true!
</p>

<!-- (B) [ngIf] with template -->
<template [ngIf]="condition">
<p>
Our heroes are true!
</p>
</template>
<!-- #enddocregion ngIf-template -->

<hr>

<!-- #docregion ngFor-template -->
<!-- Examples (A) and (B) are the same -->

<!-- (A) *ngFor div -->
<div *ngFor="#hero of heroes">{{ hero }}</div>

<!-- (B) ngFor with template -->
<template ngFor #hero [ngForOf]="heroes">
<div>{{ hero }}</div>
</template>
<!-- #enddocregion ngFor-template -->
<!-- #enddocregion -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// #docplaster
// #docregion
// #docregion unless-declaration
import 'package:angular2/angular2.dart';
// #enddocregion unless-declaration

// #docregion unless-declaration
@Directive(selector: '[myUnless]')
class UnlessDirective {
// #enddocregion unless-declaration

// #docregion unless-constructor
TemplateRef _templateRef;
ViewContainerRef _viewContainer;

UnlessDirective(this._templateRef, this._viewContainer);
// #enddocregion unless-constructor

// #docregion unless-set
@Input()
set myUnless(bool condition) {
if (!condition) {
_viewContainer.createEmbeddedView(_templateRef);
} else {
_viewContainer.clear();
}
}
// #enddocregion unless-set
// #docregion unless-declaration
}
// #enddocregion unless-declaration
// #enddocregion
14 changes: 14 additions & 0 deletions public/docs/_examples/structural-directives/dart/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: structural_directives
description: Structural directives example
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a mention on another PR and the comments sounded that SDK constraint >=1.13.0<2.0.0 makes sense to ensure ^1.2.3 version constraints in pubspec.yaml are supported as well as async / await.
See #693 (comment) and follow-ups.
No definitive yes/or no though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, we decided to add sdk and dart_to_js_script_rewriter to all pubspecs.

version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
dependencies:
angular2: 2.0.0-beta.1
browser: ^0.10.0
dart_to_js_script_rewriter: ^0.1.0
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#COMMON_DIRECTIVES'
entry_points: web/main.dart
- dart_to_js_script_rewriter
15 changes: 15 additions & 0 deletions public/docs/_examples/structural-directives/dart/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<!-- #docregion -->
<html>

<head>
<title>Angular 2 Structural Directives</title>
<script defer src="main.dart" type="application/dart"></script>
<script defer src="packages/browser/dart.js"></script>
</head>

<body>
<structural-directives>Loading...</structural-directives>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// #docregion
import 'package:angular2/bootstrap.dart';
import 'package:structural_directives/structural_directives_component.dart';

main() {
bootstrap(StructuralDirectivesComponent);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {HeavyLoaderComponent} from './heavy-loader.component';

@Component({
selector: 'structural-directives',
templateUrl: 'app/structural-directives.component.html',
templateUrl: 'app/structural_directives_component.html',
styles: ['button { min-width: 100px; }'],
directives: [UnlessDirective, HeavyLoaderComponent]
})
Expand Down
26 changes: 13 additions & 13 deletions public/docs/ts/latest/guide/hierarchical-dependency-injection.jade
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ include ../../../../_includes/_util-fns
that parallel an application's component tree.
We can re-configure the injectors at any level of that component tree with
interesting and useful results.

In this chapter we explore these points and write some code.

[Live Example](/resources/live-examples/hierarchical-dependency-injection/ts/plnkr.html).

.l-main-section
Expand All @@ -21,19 +21,19 @@ include ../../../../_includes/_util-fns
In the [Dependency Injection](./dependency-injection.html) chapter
we learned how to configure a dependency injector and how to retrieve dependencies where we need them.

We oversimplified. In fact, there is no such thing as ***the*** injector!
We oversimplified. In fact, there is no such thing as ***the*** injector!
An application may have multiple injectors!

An Angular application is a tree of components. Each component instance has its own injector!
The tree of components parallels the tree of injectors.


.l-sub-section
:marked
Angular doesn't *literally* create a separate injector for each component.
Every component doesn't need its own injector and it would be horribly inefficient to create
Angular doesn't *literally* create a separate injector for each component.
Every component doesn't need its own injector and it would be horribly inefficient to create
masses of injectors for no good purpose.

But it is true that every component ***has an injector*** (even if it shares that injector with another component)
and there may be many different injector instances operating at different levels of the component tree.

Expand Down Expand Up @@ -135,12 +135,12 @@ figure.image-display

Our `HeroEditComponent` uses this services under the hood for it’s `hero` property. It intercepts the `get` and `set` method to delegate the actual work to our `RestoreService` which in turn makes sure that we won’t work on the original item but on a copy instead.

At this point we may be scratching our heads asking what this has to do with component injectors?
If closely at the metadata for our `HeroEditComponent`. Notice the `providers` property.
At this point we may be scratching our heads asking what this has to do with component injectors?
Look closely at the metadata for our `HeroEditComponent`. Notice the `providers` property.

+makeExample('hierarchical-dependency-injection/ts/app/hero-editor.component.ts', 'providers')
:marked
This adds a `RestoreService` provider to the injector of the `HeroEditComponent`.
This adds a `RestoreService` provider to the injector of the `HeroEditComponent`.
Couldn’t we simply alter our bootstrap call to this?

+makeExample('hierarchical-dependency-injection/ts/app/boot.ts', 'bad-alternative')
Expand All @@ -155,11 +155,11 @@ figure.image-display
Any of those injectors could have its own instance of the service.

If we defined a `RestoreService` provider only on the root component,
we would have exactly one instance of that service and it would be shared across the entire application.
we would have exactly one instance of that service and it would be shared across the entire application.

That’s clearly not what we want in this scenario. We want each component to have its own instance of the `RestoreService`.
Defining (or re-defining) a provider at the component level creates a new instance of the service for each new instance
of that component. We've made the `RestoreService` a kind of "private" singleton for each `HeroEditComponent`,
of that component. We've made the `RestoreService` a kind of "private" singleton for each `HeroEditComponent`,
scoped to that component instance and its child components.

<!--
Expand Down
Binary file added public/resources/images/bios/kara-erickson.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.