docs(query): edit and extend query and view query docs.

This commit is contained in:
Rado Kirov
2015-09-17 22:33:51 -07:00
parent 3525d8a394
commit 5809a02624
4 changed files with 200 additions and 140 deletions

View File

@ -3,73 +3,7 @@ library angular2.src.core.compiler.query_list;
import 'dart:collection';
/**
* An iterable and observable live list of components in the DOM.
*
* A QueryList contains a live list of child directives in the DOM of a directive.
* The directives are kept in depth-first pre-order traversal of the DOM.
*
* The `QueryList` is iterable, therefore it can be used in both javascript code with `for..of` loop
* as well as in template with `*ng-for="of"` directive.
*
* QueryList is updated as part of the change-detection cycle of a directive. Since change detection
* happens after construction of a directive, QueryList will always be empty when observed in the
* constructor.
*
*
* NOTE: In the future this class will implement an `Observable` interface. For now it uses a plain
* list of observable callbacks.
*
* # Example:
*
* Assume that `<tabs>` component would like to get a list its children which are `<pane>`
* components as shown in this example:
*
* ```html
* <tabs>
* <pane title="Overview">...</pane>
* <pane *ng-for="#o of objects" [title]="o.title">{{o.text}}</pane>
* </tabs>
* ```
*
* In the above example the list of `<tabs>` elements needs to get a list of `<pane>` elements so
* that it could render tabs with the correct titles and in the correct order.
*
* A possible solution would be for a `<pane>` to inject `<tabs>` component and then register itself
* with `<tabs>` component's on `hydrate` and deregister on `dehydrate` event. While a reasonable
* approach, this would only work partialy since `*ng-for` could rearrange the list of `<pane>`
* components which would not be reported to `<tabs>` component and thus the list of `<pane>`
* components would be out of sync with respect to the list of `<pane>` elements.
*
* A preferred solution is to inject a `QueryList` which is a live list of directives in the
* component`s light DOM.
*
* ```javascript
* @Component(
* selector: 'tabs'
* )
* @View(
* template: `
* <ul>
* <li *ng-for="#pane of panes">{{pane.title}}</li>
* </ul>
* <content></content>
* `
* )
* class Tabs {
* QueryList<Pane> panes;
*
* constructor(@Query(Pane) QueryList<Pane> this.panes) { }
* }
*
* @Component(
* selector: 'pane',
* properties: ['title']
* )
* @View(...)
* class Pane {
* String title;
* }
* ```
* See query_list.ts
*/
class QueryList<T> extends Object
with IterableMixin<T> {
@ -79,6 +13,7 @@ class QueryList<T> extends Object
Iterator<T> get iterator => _results.iterator;
/** @private */
void reset(List<T> newList) {
_results = newList;
_dirty = true;
@ -89,7 +24,6 @@ class QueryList<T> extends Object
_dirty = true;
}
void onChange(callback) {
_callbacks.add(callback);
}
@ -114,7 +48,7 @@ class QueryList<T> extends Object
return this._results.map(fn).toList();
}
// Internal to the framework.
/** @private */
void fireCallbacks() {
if (_dirty) {
_callbacks.forEach((c) => c());

View File

@ -3,74 +3,27 @@ import {getSymbolIterator} from 'angular2/src/core/facade/lang';
/**
* An iterable and observable live list of components in the DOM.
* An unmodifiable list of items that Angular keeps up to date when the state
* of the application changes.
*
* A QueryList contains a live list of child directives in the DOM of a directive.
* The directives are kept in depth-first pre-order traversal of the DOM.
* The type of object that {@link QueryMetadata} and {@link ViewQueryMetadata} provide.
*
* The `QueryList` is iterable, therefore it can be used in both javascript code with `for..of` loop
* as well as in template with `*ng-for="of"` directive.
* Implements an iterable interface, therefore it can be used in both ES6
* javascript `for (var i of items)` loops as well as in Angular templates with
* `*ng-for="#i of myList"`.
*
* QueryList is updated as part of the change-detection cycle of a directive. Since change detection
* happens after construction of a directive, QueryList will always be empty when observed in the
* constructor.
* Changes can be observed by attaching callbacks.
*
* NOTE: In the future this class will implement an `Observable` interface.
*
* NOTE: In the future this class will implement an `Observable` interface. For now it uses a plain
* list of observable callbacks.
*
* # Example:
*
* Assume that `<tabs>` component would like to get a list its children which are `<pane>`
* components as shown in this example:
*
* ```html
* <tabs>
* <pane title="Overview">...</pane>
* <pane *ng-for="#o of objects" [title]="o.title">{{o.text}}</pane>
* </tabs>
* ```
*
* In the above example the list of `<tabs>` elements needs to get a list of `<pane>` elements so
* that it could render tabs with the correct titles and in the correct order.
*
* A possible solution would be for a `<pane>` to inject `<tabs>` component and then register itself
* with `<tabs>` component's on `hydrate` and deregister on `dehydrate` event. While a reasonable
* approach, this would only work partially since `*ng-for` could rearrange the list of `<pane>`
* components which would not be reported to `<tabs>` component and thus the list of `<pane>`
* components would be out of sync with respect to the list of `<pane>` elements.
*
* A preferred solution is to inject a `QueryList` which is a live list of directives in the
* component`s light DOM.
*
* ### Example ([live demo](http://plnkr.co/edit/RX8sJnQYl9FWuSCWme5z?p=preview))
* ```javascript
* @Component({
* selector: 'tabs'
* })
* @View({
* template: `
* <ul>
* <li *ng-for="#pane of panes">{{pane.title}}</li>
* </ul>
* <content></content>
* `
* })
* class Tabs {
* panes: QueryList<Pane>
*
* constructor(@Query(Pane) panes:QueryList<Pane>) {
* this.panes = panes;
* @Component({...})
* class Container {
* constructor(@Query(Item) items: QueryList<Item>) {
* items.onChange(() => console.log(items.length));
* }
* }
*
* @Component({
* selector: 'pane',
* properties: ['title']
* })
* @View(...)
* class Pane {
* title:string;
* }
* ```
*/
export class QueryList<T> {
@ -78,21 +31,31 @@ export class QueryList<T> {
protected _callbacks: Array < () => void >= [];
protected _dirty: boolean = false;
/** @private */
reset(newList: T[]): void {
this._results = newList;
this._dirty = true;
}
/** @private */
add(obj: T): void {
this._results.push(obj);
this._dirty = true;
}
/**
* registers a callback that is called upon each change.
*/
onChange(callback: () => void): void { this._callbacks.push(callback); }
/**
* removes a given callback.
*/
removeCallback(callback: () => void): void { ListWrapper.remove(this._callbacks, callback); }
/**
* removes all callback that have been attached.
*/
removeAllCallbacks(): void { this._callbacks = []; }
toString(): string { return this._results.toString(); }
@ -101,11 +64,14 @@ export class QueryList<T> {
get first(): T { return ListWrapper.first(this._results); }
get last(): T { return ListWrapper.last(this._results); }
/**
* returns a new list with the passsed in function applied to each element.
*/
map<U>(fn: (item: T) => U): U[] { return this._results.map(fn); }
[getSymbolIterator()](): any { return this._results[getSymbolIterator()](); }
// Internal to the framework.
/** @private */
fireCallbacks(): void {
if (this._dirty) {
ListWrapper.forEach(this._callbacks, (c) => c());