From 8c05db665e8ffb7f26118f06861d950dfaf1ac6b Mon Sep 17 00:00:00 2001 From: naomi black Date: Tue, 15 Apr 2014 11:05:33 -0700 Subject: [PATCH] docs: add more scope and change detection docs for 0.9.11 --- lib/application.dart | 10 ++++ lib/application_factory.dart | 14 ++++- lib/application_factory_static.dart | 29 ++++++++++- lib/change_detection/watch_group.dart | 12 +++++ lib/core/module.dart | 2 + lib/core/scope.dart | 73 +++++++++++++++++++-------- 6 files changed, 117 insertions(+), 23 deletions(-) diff --git a/lib/application.dart b/lib/application.dart index 05cacd62c..8cdf7a2ea 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -139,6 +139,9 @@ abstract class Application { final List modules = []; dom.Element element; +/** +* Creates a selector for a DOM element. +*/ dom.Element selector(String selector) => element = _find(selector); Application(): element = _find('[ng-app]', dom.window.document.documentElement) { @@ -148,6 +151,9 @@ abstract class Application { ..factory(dom.Node, (i) => i.get(Application).element); } +/** +* Returns the injector for this module. +*/ Injector injector; Application addModule(Module module) { @@ -174,5 +180,9 @@ abstract class Application { }); } +/** +* Creates an injector function that can be used for retrieving services as well as for +* dependency injection. +*/ Injector createInjector(); } diff --git a/lib/application_factory.dart b/lib/application_factory.dart index 9ba122d80..342e39dfa 100644 --- a/lib/application_factory.dart +++ b/lib/application_factory.dart @@ -67,5 +67,17 @@ class _DynamicApplication extends Application { Injector createInjector() => new DynamicInjector(modules: modules); } - +/** +* Creates an `applicationFactory` that bootstraps Angular as part of the `main()` function. +* +* main() { +* applicationFactory() +* .addModule(new MyModule()) +* .run(); +* } +* +* During `pub build`, `applicationFactory()` is replaced by `staticApplication()` and +* populated with the getters, setters, annotations, and factories generated by +* Angular's transformers for dart2js compilation. +*/ Application applicationFactory() => new _DynamicApplication(); diff --git a/lib/application_factory_static.dart b/lib/application_factory_static.dart index a5ab70bb7..4b80da876 100644 --- a/lib/application_factory_static.dart +++ b/lib/application_factory_static.dart @@ -64,7 +64,34 @@ class _StaticApplication extends Application { Injector createInjector() => new StaticInjector(modules: modules, typeFactories: typeFactories); } - +/** +* +* Bootstraps Angular as part of the `main()` function. +* +* `staticApplication()` replaces `dynamicApplication()` in the main function during pub build, +* and is populated with the getters, setters, annotations, and factories generated by +* Angular's transformers for dart2js compilation. It is not typically called directly. +* +* For example, +* +* main() { +* applicationFactory() +* .addModule(new Module()..type(HelloWorld)) +* .run(); +* } +* +* becomes: +* +* main() { +* staticApplication(generated_static_injector.factories, +* generated_static_metadata.typeAnnotations, +* generated_static_expressions.getters, +* generated_static_expressions.setters, +* generated_static_expressions.symbols) +* .addModule(new Module()..type(HelloWorldController)) +* .run(); +* +*/ Application staticApplicationFactory( Map typeFactories, Map metadata, diff --git a/lib/change_detection/watch_group.dart b/lib/change_detection/watch_group.dart index 452183d0b..764ff6349 100644 --- a/lib/change_detection/watch_group.dart +++ b/lib/change_detection/watch_group.dart @@ -6,6 +6,18 @@ part 'linked_list.dart'; part 'ast.dart'; part 'prototype_map.dart'; +/** + * A function that is notified of changes to the model. + * + * ReactionFn is a function implemented by the developer that executes when a change is detected + * in a watched expression. + * + * * [value]: The current value of the watched expression. + * * [previousValue]: The previous value of the watched expression. + * + * If the expression is watching a collection (a list or a map), then [value] is wrapped in + * a [CollectionChangeItem] that lists all the changes. + */ typedef void ReactionFn(value, previousValue); typedef void ChangeLog(String expression, current, previous); diff --git a/lib/core/module.dart b/lib/core/module.dart index afa5760bb..c4326f22b 100644 --- a/lib/core/module.dart +++ b/lib/core/module.dart @@ -9,6 +9,8 @@ */ library angular.core; +export "package:angular/change_detection/watch_group.dart" show + ReactionFn; export "package:angular/core/parser/parser.dart" show Parser; diff --git a/lib/core/scope.dart b/lib/core/scope.dart index fd7b38fe5..7554907c3 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -187,15 +187,22 @@ class Scope { this._stats); /** - * Use [watch] to set up a watch in the [apply] cycle. + * Use [watch] to set up change detection on an expression. * - * When [canChangeModel] is [:false:], the watch will be executed in the - * [flush] cycle. It should be used when the [reactionFn] does not change the - * model and allows speeding up the [digest] phase. - * - * On the opposite, [canChangeModel] should be set to [:true:] if the - * [reactionFn] could change the model so that the watch is evaluated in the - * [digest] cycle. + * * [expression]: The expression to watch for changes. + * * [reactionFn]: The reaction function to execute when a change is detected in the watched + * expression. + * * [context]: The object against which the expression is evaluated. This defaults to the + * [Scope.context] if no context is specified. + * * [formatters]: If the watched expression contains formatters, + * this map specifies the set of formatters that are used by the expression. + * * [canChangeModel]: Specifies whether the [reactionFn] changes the model. Reaction + * functions that change the model are processed as part of the [digest] cycle. Otherwise, + * they are processed as part of the [flush] cycle. + * * [collection]: If [:true:], then the expression points to a collection (a list or a map), + * and the collection should be shallow watched. If [:false:] then the expression is watched + * by reference. When watching a collection, the reaction function receives a + * [CollectionChangeItem] that lists all the changes. */ Watch watch(String expression, ReactionFn reactionFn, {context, FormatterMap formatters, bool canChangeModel: true, bool collection: false}) { @@ -538,18 +545,24 @@ class RootScope extends Scope { * While processing data bindings, Angular passes through multiple states. When testing or * debugging, it can be useful to access the current `state`, which is one of the following: * - * ## `null` + * * null + * * apply + * * digest + * * flush + * * assert + * + * ##null * * Angular is not currently processing changes * - * ## `apply` + * ##apply * - * The apply state begins by executing the optional expression within the context of + * The apply state begins by executing the optional expression within the context of * angular change detection mechanism. Any exceptions are delegated to [ExceptionHandler]. At the * end of apply state RootScope enters the digest followed by flush phase (optionally if asserts - * enabled run assert phase.). + * enabled run assert phase.) * - * ## `digest` + * ##digest * * The apply state begins by processing the async queue, * followed by change detection @@ -558,18 +571,19 @@ class RootScope extends Scope { * iterations the model is considered unstable and angular exists with an exception. (See * ScopeDigestTTL) * - * ## `flush` + * ##flush * - * Flush phase consist of these steps. - * 1) processing the DOM write queue, - * 2) followed by change detection on DOM only updates (these are reaction functions which must + * The flush phase consists of these steps: + * + * 1. processing the DOM write queue + * 2. change detection on DOM only updates (these are reaction functions which must * not change the model state and hence don't need stabilization as in digest phase). - * 3) processing the DOM read queue - * 4) repeat step 1/3 (not 2) until queues are empty + * 3. processing the DOM read queue + * 4. repeat steps 1 and 3 (not 2) until queues are empty * - * ## `assert` + * ##assert * - * Optionally if dart assert is on, verify that flush reaction functions did not make any changes + * Optionally if Dart assert is on, verify that flush reaction functions did not make any changes * to model and throw error if changes detected. * */ @@ -596,6 +610,23 @@ class RootScope extends Scope { RootScope get rootScope => this; bool get isAttached => true; +/** + * Propagates changes between different parts of the application model. Normally called by + * [VMTurnZone] right before DOM rendering to initiate data binding. May also be called directly + * for unit testing. + * + * Before each iteration of change detection, [digest] first processes the async queue. Any + * work scheduled on the queue is executed before change detection. Since work scheduled on + * the queue may generate more async calls, [digest] must process the queue multiple times before + * it completes. The async queue must be empty before the model is considered stable. + * + * Next, [digest] collects the changes that have occurred in the model. For each change, + * [digest] calls the associated [ReactionFn]. Since a [ReactionFn] may further change the model, + * [digest] processes changes multiple times until no more changes are detected. + * + * If the model does not stabilize within 5 iterations, an exception is thrown. See + * [ScopeDigestTTL]. + */ void digest() { _transitionState(null, STATE_DIGEST); try {