Skip to content

Commit f7dfd23

Browse files
committed
chore(query): refactor QueryList and BaseQueryList.
Closes angular#3035, angular#3016
1 parent b03560b commit f7dfd23

6 files changed

Lines changed: 127 additions & 133 deletions

File tree

modules/angular2/core.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ export {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
1515
export {Compiler} from 'angular2/src/core/compiler/compiler';
1616

1717
export {AppViewManager} from 'angular2/src/core/compiler/view_manager';
18+
export {IQueryList} from 'angular2/src/core/compiler/interface_query';
1819
export {QueryList} from 'angular2/src/core/compiler/query_list';
19-
export {BaseQueryList} from 'angular2/src/core/compiler/base_query_list';
2020
export {ElementRef} from 'angular2/src/core/compiler/element_ref';
2121
export {RenderElementRef} from 'angular2/src/render/api';
2222
export {ViewRef, ProtoViewRef} from 'angular2/src/core/compiler/view_ref';

modules/angular2/src/core/annotations_impl/di.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ export class Query extends DependencyMetadata {
7272
* Specifies that a {@link QueryList} should be injected.
7373
*
7474
* See {@link QueryList} for usage and example.
75-
*
76-
* @exportedAs angular2/annotations
7775
*/
7876
@CONST()
7977
export class ViewQuery extends Query {

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

Lines changed: 0 additions & 43 deletions
This file was deleted.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* An iterable live list of components in the Light DOM.
3+
*
4+
* Injectable Objects that contains a live list of child directives in the light DOM of a directive.
5+
* The directives are kept in depth-first pre-order traversal of the DOM.
6+
*
7+
* The `QueryList` is iterable, therefore it can be used in both javascript code with `for..of` loop
8+
* as well as in
9+
* template with `*ng-for="of"` directive.
10+
*
11+
* NOTE: In the future this class will implement an `Observable` interface. For now it uses a plain
12+
* list of observable
13+
* callbacks.
14+
*
15+
* # Example:
16+
*
17+
* Assume that `<tabs>` component would like to get a list its children which are `<pane>`
18+
* components as shown in this
19+
* example:
20+
*
21+
* ```html
22+
* <tabs>
23+
* <pane title="Overview">...</pane>
24+
* <pane *ng-for="#o of objects" [title]="o.title">{{o.text}}</pane>
25+
* </tabs>
26+
* ```
27+
*
28+
* In the above example the list of `<tabs>` elements needs to get a list of `<pane>` elements so
29+
* that it could render
30+
* tabs with the correct titles and in the correct order.
31+
*
32+
* A possible solution would be for a `<pane>` to inject `<tabs>` component and then register itself
33+
* with `<tabs>`
34+
* component's on `hydrate` and deregister on `dehydrate` event. While a reasonable approach, this
35+
* would only work
36+
* partialy since `*ng-for` could rearrange the list of `<pane>` components which would not be
37+
* reported to `<tabs>`
38+
* component and thus the list of `<pane>` components would be out of sync with respect to the list
39+
* of `<pane>` elements.
40+
*
41+
* A preferred solution is to inject a `QueryList` which is a live list of directives in the
42+
* component`s light DOM.
43+
*
44+
* ```javascript
45+
* @Component({
46+
* selector: 'tabs'
47+
* })
48+
* @View({
49+
* template: `
50+
* <ul>
51+
* <li *ng-for="#pane of panes">{{pane.title}}</li>
52+
* </ul>
53+
* <content></content>
54+
* `
55+
* })
56+
* class Tabs {
57+
* panes: QueryList<Pane>
58+
*
59+
* constructor(@Query(Pane) panes:QueryList<Pane>) {
60+
* this.panes = panes;
61+
* }
62+
* }
63+
*
64+
* @Component({
65+
* selector: 'pane',
66+
* properties: ['title']
67+
* })
68+
* @View(...)
69+
* class Pane {
70+
* title:string;
71+
* }
72+
* ```
73+
*/
74+
// So far this interface is only used for purposes of having unified documentation.
75+
// There are limitations for exposing the interface as the main entry point.
76+
// - Typescript does not support getters/setters in interfaces
77+
// - Dart does not support generic methods (needed for map).
78+
export interface IQueryList<T> {}

modules/angular2/src/core/compiler/base_query_list.dart renamed to modules/angular2/src/core/compiler/query_list.dart

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
library angular2.src.core.compiler.base_query_list;
1+
library angular2.src.core.compiler.query_list;
22

33
import 'dart:collection';
4+
import './interface_query.dart';
45

56
/**
67
* Injectable Objects that contains a live list of child directives in the light Dom of a directive.
@@ -9,42 +10,42 @@ import 'dart:collection';
910
* In the future this class will implement an Observable interface.
1011
* For now it uses a plain list of observable callbacks.
1112
*/
12-
class BaseQueryList<T> extends Object with IterableMixin<T> {
13+
class QueryList<T> extends Object with IterableMixin<T> implements IQueryList<T> {
1314
List<T> _results = [];
1415
List _callbacks = [];
1516
bool _dirty = false;
1617

1718
Iterator<T> get iterator => _results.iterator;
1819

19-
reset(newList) {
20+
void reset(List<T> newList) {
2021
_results = newList;
2122
_dirty = true;
2223
}
2324

24-
add(obj) {
25+
void add(T obj) {
2526
_results.add(obj);
2627
_dirty = true;
2728
}
2829

2930
// TODO(rado): hook up with change detection after #995.
30-
fireCallbacks() {
31+
void fireCallbacks() {
3132
if (_dirty) {
3233
_callbacks.forEach((c) => c());
3334
_dirty = false;
3435
}
3536
}
3637

37-
onChange(callback) {
38+
void onChange(callback) {
3839
_callbacks.add(callback);
3940
}
4041

41-
removeCallback(callback) {
42+
void removeCallback(callback) {
4243
_callbacks.remove(callback);
4344
}
4445

45-
get length => _results.length;
46-
get first => _results.first;
47-
get last => _results.last;
46+
int get length => _results.length;
47+
T get first => _results.first;
48+
T get last => _results.last;
4849

4950
List map(fn(T)) {
5051
// Note: we need to return a list instead of iterable to match JS.
Lines changed: 37 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,44 @@
1-
import {BaseQueryList} from './base_query_list';
1+
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
2+
import {IQueryList} from './interface_query';
23

34
/**
4-
* An iterable live list of components in the Light DOM.
5-
*
6-
* Injectable Objects that contains a live list of child directives in the light DOM of a directive.
5+
* Injectable Objects that contains a live list of child directives in the light Dom of a directive.
76
* The directives are kept in depth-first pre-order traversal of the DOM.
87
*
9-
* The `QueryList` is iterable, therefore it can be used in both javascript code with `for..of` loop
10-
* as well as in
11-
* template with `*ng-for="of"` directive.
12-
*
13-
* NOTE: In the future this class will implement an `Observable` interface. For now it uses a plain
14-
* list of observable
15-
* callbacks.
16-
*
17-
* # Example:
18-
*
19-
* Assume that `<tabs>` component would like to get a list its children which are `<pane>`
20-
* components as shown in this
21-
* example:
22-
*
23-
* ```html
24-
* <tabs>
25-
* <pane title="Overview">...</pane>
26-
* <pane *ng-for="#o of objects" [title]="o.title">{{o.text}}</pane>
27-
* </tabs>
28-
* ```
29-
*
30-
* In the above example the list of `<tabs>` elements needs to get a list of `<pane>` elements so
31-
* that it could render
32-
* tabs with the correct titles and in the correct order.
33-
*
34-
* A possible solution would be for a `<pane>` to inject `<tabs>` component and then register itself
35-
* with `<tabs>`
36-
* component's on `hydrate` and deregister on `dehydrate` event. While a reasonable approach, this
37-
* would only work
38-
* partialy since `*ng-for` could rearrange the list of `<pane>` components which would not be
39-
* reported to `<tabs>`
40-
* component and thus the list of `<pane>` components would be out of sync with respect to the list
41-
* of `<pane>` elements.
42-
*
43-
* A preferred solution is to inject a `QueryList` which is a live list of directives in the
44-
* component`s light DOM.
45-
*
46-
* ```javascript
47-
* @Component({
48-
* selector: 'tabs'
49-
* })
50-
* @View({
51-
* template: `
52-
* <ul>
53-
* <li *ng-for="#pane of panes">{{pane.title}}</li>
54-
* </ul>
55-
* <content></content>
56-
* `
57-
* })
58-
* class Tabs {
59-
* panes: QueryList<Pane>
60-
*
61-
* constructor(@Query(Pane) panes:QueryList<Pane>) {
62-
* this.panes = panes;
63-
* }
64-
* }
65-
*
66-
* @Component({
67-
* selector: 'pane',
68-
* properties: ['title']
69-
* })
70-
* @View(...)
71-
* class Pane {
72-
* title:string;
73-
* }
74-
* ```
8+
* In the future this class will implement an Observable interface.
9+
* For now it uses a plain list of observable callbacks.
7510
*/
76-
export class QueryList<T> extends BaseQueryList<T> {
77-
/**
78-
*/
79-
onChange(callback) { super.onChange(callback); }
11+
export class QueryList<T> implements IQueryList<T> {
12+
protected _results: List < T >= [];
13+
protected _callbacks: List < () => void >= [];
14+
protected _dirty: boolean = false;
15+
16+
reset(newList: List<T>): void {
17+
this._results = newList;
18+
this._dirty = true;
19+
}
20+
21+
add(obj: T): void {
22+
this._results.push(obj);
23+
this._dirty = true;
24+
}
25+
26+
fireCallbacks(): void {
27+
if (this._dirty) {
28+
ListWrapper.forEach(this._callbacks, (c) => c());
29+
this._dirty = false;
30+
}
31+
}
32+
33+
onChange(callback: () => void): void { this._callbacks.push(callback); }
34+
35+
removeCallback(callback: () => void): void { ListWrapper.remove(this._callbacks, callback); }
36+
37+
get length(): number { return this._results.length; }
38+
get first(): T { return ListWrapper.first(this._results); }
39+
get last(): T { return ListWrapper.last(this._results); }
40+
41+
map<U>(fn: (T) => U): U[] { return this._results.map(fn); }
8042

81-
/**
82-
*/
83-
removeCallback(callback) { super.removeCallback(callback); }
43+
[Symbol.iterator](): any { return this._results[Symbol.iterator](); }
8444
}

0 commit comments

Comments
 (0)