From dd38ce6585b0e7ffa755f4c65d78ed90204729d1 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 28 Feb 2012 12:14:47 -0800 Subject: docs(scope): rewrite --- CHANGELOG.md | 2 +- .../dev_guide.mvc.understanding_controller.ngdoc | 2 +- .../guide/dev_guide.mvc.understanding_model.ngdoc | 2 +- .../content/guide/dev_guide.scopes.internals.ngdoc | 230 -------------- docs/content/guide/dev_guide.scopes.ngdoc | 35 --- .../dev_guide.scopes.understanding_scopes.ngdoc | 66 ----- .../guide/dev_guide.templates.databinding.ngdoc | 2 +- docs/content/guide/index.ngdoc | 13 +- docs/content/guide/scope.ngdoc | 330 +++++++++++++++++++++ docs/content/misc/started.ngdoc | 2 +- src/ng/rootScope.js | 22 +- 11 files changed, 348 insertions(+), 358 deletions(-) delete mode 100644 docs/content/guide/dev_guide.scopes.internals.ngdoc delete mode 100644 docs/content/guide/dev_guide.scopes.ngdoc delete mode 100644 docs/content/guide/dev_guide.scopes.understanding_scopes.ngdoc create mode 100644 docs/content/guide/scope.ngdoc diff --git a/CHANGELOG.md b/CHANGELOG.md index f0f3decc..0f5626b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1007,7 +1007,7 @@ behavior and migrate your controllers one at a time: -it('should inherit properties', inject(function($rootScope)) { - var root = $rootScope; - var child = root.$new(); - - root.name = 'angular'; - expect(child.name).toEqual('angular'); - expect(root.name).toEqual('angular'); - - child.name = 'super-heroic framework'; - expect(child.name).toEqual('super-heroic framework'); - expect(root.name).toEqual('angular'); -}); - - - -### Scope life cycle -1. **Creation** - - * The root scope is created by the {@link api/angular.module.ng.$rootScope $rootScope} service. - * To create a child scopes, you should call {@link api/angular.module.ng.$rootScope.Scope#$new parentScope.$new()}. - -2. **Watcher registration** - - Watcher registration can happen at any time and on any scope (root or child) via {@link -api/angular.module.ng.$rootScope.Scope#$watch scope.$watch()} API. - -3. **Model mutation** - - For mutations to be properly observed, you should make them only within the execution of the -function passed into {@link api/angular.module.ng.$rootScope.Scope#$apply scope.$apply()} call. (Angular apis do this -implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers, or -asynchronous work with {@link api/angular.module.ng.$http $http} or {@link api/angular.module.ng.$defer -$defer} services. - -4. **Mutation observation** - - At the end of each `$apply` call {@link api/angular.module.ng.$rootScope.Scope#$digest $digest} cycle is started on -the root scope, which then propagates throughout all child scopes. - - During the `$digest` cycle, all `$watch-ers` expressions or functions are checked for model -mutation and if a mutation is detected, the `$watch-er` listener is called. - -5. **Scope destruction** - - When child scopes are no longer needed, it is the responsibility of the child scope creator to -destroy them via {@link api/angular.module.ng.$rootScope.Scope#$destroy scope.$destroy()} API. This will stop -propagation of `$digest` calls into the child scope and allow for memory used by the child scope -models to be reclaimed by the garbage collector. - - The root scope can't be destroyed via the `$destroy` API. Instead, it is enough to remove all -references from your application to the scope object and garbage collector will do its magic. -## Scopes in Angular applications -To understand how Angular applications work, you need to understand how scopes work within an -application. This section describes the typical life cycle of an application so you can see how -scopes come into play throughout and get a sense of their interactions. -### How scopes interact in applications - -1. At application compile time, a root scope is created and is attached to the root `` DOM -element. -2. During the compilation phase, the {@link dev_guide.compiler compiler} matches {@link -guide/directive directives} against the DOM template. The directives -usually fall into one of two categories: - - Observing {@link guide/directive directives}, such as double-curly - expressions `{{expression}}`, register listeners using the {@link - api/angular.module.ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs to - be notified whenever the expression changes so that it can update the view. - - Listener directives, such as {@link api/angular.module.ng.$compileProvider.directive.ngClick - ngClick}, register a listener with the DOM. When the DOM listener fires, the directive executes - the associated expression and updates the view using the {@link - api/angular.module.ng.$rootScope.Scope#$apply $apply()} method. -3. When an external event (such as a user action, timer or XHR) is received, the associated {@link -dev_guide.expressions expression} must be applied to the scope through the {@link -api/angular.module.ng.$rootScope.Scope#$apply $apply()} method so that all listeners are updated correctly. - - -### Directives that create scopes -In most cases, {@link guide/directive directives} and scopes interact but do not create new -instances of scope. However, some directives, such as {@link api/angular.module.ng.$compileProvider.directive.ngController -ngController} and {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat}, create new child scopes using -the {@link api/angular.module.ng.$rootScope.Scope#$new $new()} method and then attach the child scope to the -corresponding DOM element. You can retrieve a scope for any DOM element by using an -`angular.element(aDomElement).scope()` method call.) - - -### Controllers and scopes -Scopes and controllers interact with each other in the following situations: - - Controllers use scopes to expose controller methods to templates (see {@link -api/angular.module.ng.$compileProvider.directive.ngController ngController}). - - Controllers define methods (behavior) that can mutate the model (properties on the scope). - - Controllers may register {@link api/angular.module.ng.$rootScope.Scope#$watch watches} on the model. These watches -execute immediately after the controller behavior executes, but before the DOM gets updated. - -See the {@link dev_guide.mvc.understanding_controller controller docs} for more information. - -### Updating scope properties -You can update a scope by calling its {@link api/angular.module.ng.$rootScope.Scope#$apply $apply()} method with an -expression or a function as the function argument. However it is typically not necessary to do this -explicitly. In most cases, angular intercepts all external events (such as user interactions, XHRs, -and timers) and wraps their callbacks into the `$apply()` method call on the scope object for you -at the right time. The only time you might need to call `$apply()` explicitly is when you create -your own custom asynchronous widget or service. - -The reason it is unnecessary to call `$apply()` from within your controller functions when you use -built-in angular widgets and services is because your controllers are typically called from within -an `$apply()` call already. - -When a user inputs data, angularized widgets invoke `$apply()` on the current scope and evaluate an -angular expression or execute a function on this scope. Afterwards `$apply` will trigger `$digest` -call on the root scope, to propagate your changes through the entire system, which results in -$watch-ers firing and view getting updated. Similarly, when a request to fetch data from a server -is made and the response comes back, the data is written into the model (scope) within an $apply, -which then pushes updates through to the view and any other dependents. - -A widget that creates scopes (such as {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat}) via `$new`, -doesn't need to worry about propagating the `$digest` call from the parent scope to child scopes. -This happens automatically. - -## Scopes in unit-testing -You can create scopes, including the root scope, in tests by having the $rootScope injected into -your spec. This allows you to mimic the run-time environment and have full control over -the life cycle of the scope so that you can assert correct model transitions. Since these scopes -are created outside the normal compilation process, their life cycles must be managed by the test. - -### Using scopes in unit-testing -The following example demonstrates how the scope life cycle needs to be manually triggered from -within the unit-tests. - -
-  // example of a test
-  it('should trigger a watcher', inject(function($rootScope) {
-    var scope = $rootScope;
-    scope.$watch('name', function(name) {
-     scope.greeting = 'Hello ' + name + '!';
-    });
-
-    scope.name = 'angular';
-    // The watch does not fire yet since we have to manually trigger the digest phase.
-    expect(scope.greeting).toEqual(undefined);
-
-    // manually trigger digest phase from the test
-    scope.$digest();
-    expect(scope.greeting).toEqual('Hello Angular!');
-  }
-
- - -### Dependency injection in Tests - -When you find it necessary to inject your own mocks in your tests, use a scope to override the -service instances, as shown in the following example. - -
-it('should allow override of providers', inject(
-  function($provide) {
-    $provide.value('$location', {mode:'I am a mock'});
-  },
-  function($location){
-    expect($location.mode).toBe('I am a mock');
-  }
-)};
-
- -## Related Topics - -* {@link dev_guide.scopes Angular Scope Objects} -* {@link dev_guide.scopes.understanding_scopes Understanding Scopes} - -## Related API - -* {@link api/angular.module.ng.$rootScope.Scope Angular Scope API} - diff --git a/docs/content/guide/dev_guide.scopes.ngdoc b/docs/content/guide/dev_guide.scopes.ngdoc deleted file mode 100644 index 6ddbcae4..00000000 --- a/docs/content/guide/dev_guide.scopes.ngdoc +++ /dev/null @@ -1,35 +0,0 @@ -@ngdoc overview -@name Developer Guide: Scopes -@description - - -An Angular scope is a JavaScript object with additional APIs useful for watching property changes, -Angular scope is the model in Model-View-Controller paradigm. Instances of scope serve as the -context within which all {@link dev_guide.expressions expressions} get evaluated. - -You can think of Angular scope objects as the medium through which the model, view, and controller -communicate. Scopes are linked during the compilation process with the view. This linkage provides -the contexts in which Angular creates data-bindings between the model and the view. - -In addition to providing the context in which data is evaluated, Angular scope objects watch for -model changes. The scope objects also notify all components interested in any model changes (for -example, functions registered through {@link api/angular.module.ng.$rootScope.Scope#$watch $watch}, bindings created by -{@link api/angular.module.ng.$compileProvider.directive.ngBind ngBind}, or HTML input elements). - -Angular scope objects: - -* Link the model, controller and view template together. -* Provide the mechanism to watch for model changes ({@link api/angular.module.ng.$rootScope.Scope#$watch $watch}). -* Apply model changes to the system ({@link api/angular.module.ng.$rootScope.Scope#$apply $apply}). -* Provide the context in which expressions are evaluated ({@link api/angular.module.ng.$rootScope.Scope#$eval $eval}). - - -## Related Topics - -* {@link dev_guide.scopes.understanding_scopes Understanding Scopes} -* {@link dev_guide.scopes.internals Scopes Internals} - -## Related API - -* {@link api/angular.module.ng.$rootScope.Scope Angular Scope API} - diff --git a/docs/content/guide/dev_guide.scopes.understanding_scopes.ngdoc b/docs/content/guide/dev_guide.scopes.understanding_scopes.ngdoc deleted file mode 100644 index aeab3191..00000000 --- a/docs/content/guide/dev_guide.scopes.understanding_scopes.ngdoc +++ /dev/null @@ -1,66 +0,0 @@ -@ngdoc overview -@name Developer Guide: Scopes: Understanding Scopes -@description - -Angular automatically creates a root scope during initialization, and attaches it to the page's -root DOM element (usually ``). The root scope object, along with any of its child scope -objects, serves as the infrastructure on which your data model is built. The data model (JavaScript -objects, arrays, or primitives) is attached to angular scope properties. Angular binds the property -values to the DOM where bindings are specified in the template. Angular attaches any controller -functions you have created to their respective scope objects. - - - -Angular scopes can be nested, so a child scope has a parent scope upstream in the DOM. When you -display an angular expression in the view, angular walks the DOM tree looking in the closest -attached scope object for the specified data. If it doesn't find the data in the closest attached -scope, it looks further up the scope hierarchy until it finds the data. - -A child scope object inherits properties from its parents. For example, in the following snippet of -code, observe how the value of `name` changes, based on the HTML element it is displayed in: - - - -
    -
  • - Name = {{name}}! -
  • -
-
Name={{name}}
-
- - it('should override the name property', function() { - expect(using('.doc-example-live').repeater('li').row(0)). - toEqual(['Igor']); - expect(using('.doc-example-live').repeater('li').row(1)). - toEqual(['Misko']); - - expect(using('.doc-example-live').repeater('li').row(2)). - toEqual(['Gail']); - expect(using('.doc-example-live').repeater('li').row(3)). - toEqual(['Kai']); - expect(using('.doc-example-live').element('pre').text()). - toBe('Name=Hank'); - }); - -
- -The angular {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} directive creates a new scope for each -element that it repeats (in this example the elements are list items). In the `