X Tutup
Skip to content

Commit 5948aba

Browse files
committed
feat(core): add support for ambient directives
Ambient directives can be configured when bootstraping an application. Ambient directives can be used in every component of the application without needing to explicitly list them.
1 parent 0931195 commit 5948aba

File tree

16 files changed

+199
-66
lines changed

16 files changed

+199
-66
lines changed

modules/angular2/angular2.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ library angular2;
77
*/
88
export 'package:angular2/core.dart'
99
hide forwardRef, resolveForwardRef, ForwardRefFn;
10+
export 'package:angular2/common.dart';
1011
export 'package:angular2/profile.dart';
1112
export 'package:angular2/lifecycle_hooks.dart';
1213
export 'package:angular2/src/core/application_tokens.dart'

modules/angular2/angular2.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './common';
12
export * from './core';
23
export * from './profile';
34
export * from './lifecycle_hooks';

modules/angular2/common.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {CONST_EXPR, Type} from './src/core/facade/lang';
2+
3+
import {FORM_DIRECTIVES} from './src/core/forms';
4+
import {CORE_DIRECTIVES} from './src/core/directives';
5+
export * from './src/core/pipes';
6+
export * from './src/core/directives';
7+
8+
/**
9+
* A collection of Angular core directives that are likely to be used in each and every Angular
10+
* application. This includes core directives (e.g., NgIf and NgFor), and forms directives (e.g.,
11+
* NgModel).
12+
*
13+
* This collection can be used to quickly enumerate all the built-in directives in the `directives`
14+
* property of the `@Component` or `@View` decorators.
15+
*
16+
* ### Example
17+
*
18+
* Instead of writing:
19+
*
20+
* ```typescript
21+
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm} from
22+
* 'angular2/angular2';
23+
* import {OtherDirective} from './myDirectives';
24+
*
25+
* @Component({
26+
* selector: 'my-component',
27+
* templateUrl: 'myComponent.html',
28+
* directives: [NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm,
29+
* OtherDirective]
30+
* })
31+
* export class MyComponent {
32+
* ...
33+
* }
34+
* ```
35+
* one could import all the common directives at once:
36+
*
37+
* ```typescript
38+
* import {COMMON_DIRECTIVES} from 'angular2/angular2';
39+
* import {OtherDirective} from './myDirectives';
40+
*
41+
* @Component({
42+
* selector: 'my-component',
43+
* templateUrl: 'myComponent.html',
44+
* directives: [COMMON_DIRECTIVES, OtherDirective]
45+
* })
46+
* export class MyComponent {
47+
* ...
48+
* }
49+
* ```
50+
*/
51+
export const COMMON_DIRECTIVES: Type[][] = CONST_EXPR([CORE_DIRECTIVES, FORM_DIRECTIVES]);

modules/angular2/core.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ export * from './src/core/directives';
1919
export * from './src/core/forms';
2020
export * from './src/core/debug';
2121
export * from './src/core/change_detection';
22+
export * from './src/core/compiler/ambient';

modules/angular2/src/core/application_ref.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import {AppViewManager} from 'angular2/src/core/linker/view_manager';
3838
import {AppViewManagerUtils} from 'angular2/src/core/linker/view_manager_utils';
3939
import {AppViewListener} from 'angular2/src/core/linker/view_listener';
4040
import {ProtoViewFactory} from './linker/proto_view_factory';
41-
import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
4241
import {ViewResolver} from './linker/view_resolver';
4342
import {DirectiveResolver} from './linker/directive_resolver';
4443
import {PipeResolver} from './linker/pipe_resolver';
@@ -48,6 +47,8 @@ import {AppViewManager_} from "./linker/view_manager";
4847
import {Compiler_} from "./linker/compiler";
4948
import {wtfLeave, wtfCreateScope, WtfScopeFn} from './profile/profile';
5049
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detector_ref';
50+
import {AMBIENT_DIRECTIVES, AMBIENT_PIPES} from "angular2/src/core/compiler/ambient";
51+
import {COMMON_DIRECTIVES, COMMON_PIPES} from "angular2/common";
5152

5253
/**
5354
* Constructs the set of providers meant for use at the platform level.
@@ -104,11 +105,12 @@ export function applicationCommonProviders(): Array<Type | Provider | any[]> {
104105
AppViewListener,
105106
ProtoViewFactory,
106107
ViewResolver,
107-
DEFAULT_PIPES,
108108
provide(IterableDiffers, {useValue: defaultIterableDiffers}),
109109
provide(KeyValueDiffers, {useValue: defaultKeyValueDiffers}),
110110
DirectiveResolver,
111111
PipeResolver,
112+
provide(AMBIENT_PIPES, {useValue: COMMON_PIPES, multi: true}),
113+
provide(AMBIENT_DIRECTIVES, {useValue: COMMON_DIRECTIVES, multi: true}),
112114
provide(DynamicComponentLoader, {useClass: DynamicComponentLoader_})
113115
];
114116
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import {OpaqueToken} from "angular2/src/core/di";
2+
import {CONST_EXPR} from "angular2/src/core/facade/lang";
3+
4+
/**
5+
* A token that can be provided when bootstraping an application to make an array of directives
6+
* available in every component of the application.
7+
*
8+
* ### Example
9+
*
10+
* ```typescript
11+
* import {AMBIENT_DIRECTIVES} from 'angular2/angular2';
12+
* import {OtherDirective} from './myDirectives';
13+
*
14+
* @Component({
15+
* selector: 'my-component',
16+
* template: `
17+
* <!-- can use other directive even though the component does not list it in `directives` -->
18+
* <other-directive></other-directive>
19+
* `
20+
* })
21+
* export class MyComponent {
22+
* ...
23+
* }
24+
*
25+
* bootstrap(MyComponent, [provide(AMBIENT_DIRECTIVES, {useValue: [OtherDirective], multi:true})]);
26+
* ```
27+
*/
28+
export const AMBIENT_DIRECTIVES: OpaqueToken = CONST_EXPR(new OpaqueToken("Ambient Directives"));
29+
30+
/**
31+
* A token that can be provided when bootstraping an application to make an array of pipes
32+
* available in every component of the application.
33+
*
34+
* ### Example
35+
*
36+
* ```typescript
37+
* import {AMBIENT_PIPES} from 'angular2/angular2';
38+
* import {OtherPipe} from './myPipe';
39+
*
40+
* @Component({
41+
* selector: 'my-component',
42+
* template: `
43+
* {{123 | other-pipe}}
44+
* `
45+
* })
46+
* export class MyComponent {
47+
* ...
48+
* }
49+
*
50+
* bootstrap(MyComponent, [provide(AMBIENT_PIPES, {useValue: [OtherPipe], multi:true})]);
51+
* ```
52+
*/
53+
export const AMBIENT_PIPES: OpaqueToken = CONST_EXPR(new OpaqueToken("Ambient Pipes"));

modules/angular2/src/core/compiler/compiler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export {
66
CompileTemplateMetadata
77
} from './directive_metadata';
88
export {SourceModule, SourceWithImports} from './source_module';
9+
export {AMBIENT_DIRECTIVES, AMBIENT_PIPES} from './ambient';
910

1011
import {assertionsEnabled, Type} from 'angular2/src/core/facade/lang';
1112
import {provide, Provider} from 'angular2/src/core/di';

modules/angular2/src/core/compiler/runtime_metadata.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ import {ViewMetadata} from 'angular2/src/core/metadata/view';
1717
import {hasLifecycleHook} from 'angular2/src/core/linker/directive_lifecycle_reflector';
1818
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/interfaces';
1919
import {reflector} from 'angular2/src/core/reflection/reflection';
20-
import {Injectable} from 'angular2/src/core/di';
20+
import {Injectable, Inject, Optional} from 'angular2/src/core/di';
21+
import {AMBIENT_DIRECTIVES} from 'angular2/src/core/compiler/ambient';
2122
import {MODULE_SUFFIX} from './util';
2223

2324
@Injectable()
2425
export class RuntimeMetadataResolver {
2526
private _cache = new Map<Type, cpl.CompileDirectiveMetadata>();
2627

27-
constructor(private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver) {}
28+
constructor(private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
29+
@Optional() @Inject(AMBIENT_DIRECTIVES) private _ambientDirectives: Type[]) {}
2830

2931
getMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
3032
var meta = this._cache.get(directiveType);
@@ -68,7 +70,7 @@ export class RuntimeMetadataResolver {
6870

6971
getViewDirectivesMetadata(component: Type): cpl.CompileDirectiveMetadata[] {
7072
var view = this._viewResolver.resolve(component);
71-
var directives = flattenDirectives(view);
73+
var directives = flattenDirectives(view, this._ambientDirectives);
7274
for (var i = 0; i < directives.length; i++) {
7375
if (!isValidDirective(directives[i])) {
7476
throw new BaseException(
@@ -86,18 +88,22 @@ function removeDuplicates(items: any[]): any[] {
8688
return MapWrapper.keys(m);
8789
}
8890

89-
function flattenDirectives(view: ViewMetadata): Type[] {
90-
if (isBlank(view.directives)) return [];
91-
var directives = [];
92-
flattenList(view.directives, directives);
91+
function flattenDirectives(view: ViewMetadata, ambientDirectives: any[]): Type[] {
92+
let directives = [];
93+
if (isPresent(ambientDirectives)) {
94+
flattenArray(ambientDirectives, directives);
95+
}
96+
if (isPresent(view.directives)) {
97+
flattenArray(view.directives, directives);
98+
}
9399
return directives;
94100
}
95101

96-
function flattenList(tree: any[], out: Array<Type | any[]>): void {
102+
function flattenArray(tree: any[], out: Array<Type | any[]>): void {
97103
for (var i = 0; i < tree.length; i++) {
98104
var item = resolveForwardRef(tree[i]);
99105
if (isArray(item)) {
100-
flattenList(item, out);
106+
flattenArray(item, out);
101107
} else {
102108
out.push(item);
103109
}

modules/angular2/src/core/linker/proto_view_factory.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import {ListWrapper} from 'angular2/src/core/facade/collection';
21
import {isPresent, isBlank, Type, isArray, isNumber} from 'angular2/src/core/facade/lang';
32

43
import {RenderProtoViewRef} from 'angular2/src/core/render/api';
54

6-
import {Injectable, Provider, resolveForwardRef, Inject} from 'angular2/src/core/di';
5+
import {Optional, Injectable, Provider, resolveForwardRef, Inject} from 'angular2/src/core/di';
76

87
import {PipeProvider} from '../pipes/pipe_provider';
98
import {ProtoPipes} from '../pipes/pipes';
@@ -15,7 +14,7 @@ import {DirectiveResolver} from './directive_resolver';
1514
import {ViewResolver} from './view_resolver';
1615
import {PipeResolver} from './pipe_resolver';
1716
import {ViewMetadata} from '../metadata/view';
18-
import {DEFAULT_PIPES_TOKEN} from 'angular2/src/core/pipes';
17+
import {AMBIENT_PIPES} from 'angular2/src/core/compiler/ambient';
1918

2019
import {
2120
visitAllCommands,
@@ -38,15 +37,10 @@ import {APP_ID} from 'angular2/src/core/application_tokens';
3837
@Injectable()
3938
export class ProtoViewFactory {
4039
private _cache: Map<number, AppProtoView> = new Map<number, AppProtoView>();
41-
private _defaultPipes: Type[];
42-
private _appId: string;
43-
44-
constructor(private _renderer: Renderer, @Inject(DEFAULT_PIPES_TOKEN) defaultPipes: Type[],
40+
constructor(private _renderer: Renderer,
41+
@Optional() @Inject(AMBIENT_PIPES) private _ambientPipes: Array<Type | any[]>,
4542
private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
46-
private _pipeResolver: PipeResolver, @Inject(APP_ID) appId: string) {
47-
this._defaultPipes = defaultPipes;
48-
this._appId = appId;
49-
}
43+
private _pipeResolver: PipeResolver, @Inject(APP_ID) private _appId: string) {}
5044

5145
clearCache() { this._cache.clear(); }
5246

@@ -118,9 +112,13 @@ export class ProtoViewFactory {
118112
}
119113

120114
private _flattenPipes(view: ViewMetadata): any[] {
121-
if (isBlank(view.pipes)) return this._defaultPipes;
122-
var pipes = ListWrapper.clone(this._defaultPipes);
123-
_flattenList(view.pipes, pipes);
115+
let pipes = [];
116+
if (isPresent(this._ambientPipes)) {
117+
_flattenArray(this._ambientPipes, pipes);
118+
}
119+
if (isPresent(view.pipes)) {
120+
_flattenArray(view.pipes, pipes);
121+
}
124122
return pipes;
125123
}
126124
}
@@ -313,11 +311,11 @@ function arrayToMap(arr: string[], inverse: boolean): Map<string, string> {
313311
return result;
314312
}
315313

316-
function _flattenList(tree: any[], out: Array<Type | Provider | any[]>): void {
314+
function _flattenArray(tree: any[], out: Array<Type | Provider | any[]>): void {
317315
for (var i = 0; i < tree.length; i++) {
318316
var item = resolveForwardRef(tree[i]);
319317
if (isArray(item)) {
320-
_flattenList(item, out);
318+
_flattenArray(item, out);
321319
} else {
322320
out.push(item);
323321
}

modules/angular2/src/core/pipes.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,31 @@
33
* @description
44
* This module provides a set of common Pipes.
55
*/
6+
import {AsyncPipe} from './pipes/async_pipe';
7+
import {UpperCasePipe} from './pipes/uppercase_pipe';
8+
import {LowerCasePipe} from './pipes/lowercase_pipe';
9+
import {JsonPipe} from './pipes/json_pipe';
10+
import {SlicePipe} from './pipes/slice_pipe';
11+
import {DatePipe} from './pipes/date_pipe';
12+
import {DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
13+
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
614

715
export {AsyncPipe} from './pipes/async_pipe';
816
export {DatePipe} from './pipes/date_pipe';
9-
export {DEFAULT_PIPES, DEFAULT_PIPES_TOKEN} from './pipes/default_pipes';
1017
export {JsonPipe} from './pipes/json_pipe';
1118
export {SlicePipe} from './pipes/slice_pipe';
1219
export {LowerCasePipe} from './pipes/lowercase_pipe';
1320
export {NumberPipe, DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
1421
export {UpperCasePipe} from './pipes/uppercase_pipe';
22+
23+
export const COMMON_PIPES = CONST_EXPR([
24+
AsyncPipe,
25+
UpperCasePipe,
26+
LowerCasePipe,
27+
JsonPipe,
28+
SlicePipe,
29+
DecimalPipe,
30+
PercentPipe,
31+
CurrencyPipe,
32+
DatePipe
33+
]);

0 commit comments

Comments
 (0)
X Tutup