From 8e2675029f5ca404a7c649cc161df3ea642d941f Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sat, 28 Apr 2012 22:45:28 -0700 Subject: chore(docs): re-skin main documentation --- ...ular.module.ng.$compileProvider.directive.ngdoc | 719 --------------------- docs/content/api/index.ngdoc | 62 +- docs/content/cookbook/deeplinking.ngdoc | 151 +++-- docs/content/guide/dev_guide.bootstrap.ngdoc | 2 +- docs/content/guide/dev_guide.compiler.ngdoc | 4 +- ...dev_guide.compiler.understanding_compiler.ngdoc | 4 +- docs/content/guide/dev_guide.forms.ngdoc | 12 +- .../dev_guide.mvc.understanding_controller.ngdoc | 2 +- .../content/guide/dev_guide.scopes.internals.ngdoc | 8 +- .../guide/dev_guide.services.$location.ngdoc | 2 +- .../dev_guide.services.injecting_controllers.ngdoc | 4 +- ..._guide.templates.filters.creating_filters.ngdoc | 2 +- docs/content/guide/dev_guide.templates.ngdoc | 4 +- docs/content/guide/directive.ngdoc | 719 +++++++++++++++++++++ docs/content/guide/index.ngdoc | 2 +- docs/content/guide/type.ngdoc | 3 + docs/content/misc/started.ngdoc | 2 +- docs/content/tutorial/index.ngdoc | 44 +- docs/content/tutorial/step_00.ngdoc | 34 +- docs/content/tutorial/step_01.ngdoc | 8 +- docs/content/tutorial/step_02.ngdoc | 8 +- docs/content/tutorial/step_03.ngdoc | 10 +- docs/content/tutorial/step_04.ngdoc | 39 +- docs/content/tutorial/step_05.ngdoc | 8 +- docs/content/tutorial/step_06.ngdoc | 8 +- docs/content/tutorial/step_07.ngdoc | 8 +- docs/content/tutorial/step_08.ngdoc | 8 +- docs/content/tutorial/step_09.ngdoc | 6 +- docs/content/tutorial/step_10.ngdoc | 8 +- docs/content/tutorial/step_11.ngdoc | 6 +- 30 files changed, 938 insertions(+), 959 deletions(-) delete mode 100644 docs/content/api/angular.module.ng.$compileProvider.directive.ngdoc create mode 100644 docs/content/guide/directive.ngdoc create mode 100644 docs/content/guide/type.ngdoc (limited to 'docs/content') diff --git a/docs/content/api/angular.module.ng.$compileProvider.directive.ngdoc b/docs/content/api/angular.module.ng.$compileProvider.directive.ngdoc deleted file mode 100644 index a79bd9ba..00000000 --- a/docs/content/api/angular.module.ng.$compileProvider.directive.ngdoc +++ /dev/null @@ -1,719 +0,0 @@ -@ngdoc overview -@name angular.module.ng.$compileProvider.directive -@description - -Directives are a way to teach HTML new tricks. During DOM compilation directives are matched -against the HTML and executed. This allows directives to register behavior, or transform the DOM. - -Angular comes with a built in set of directives which are useful for building web applications but -can be extended such that HTML can be turned into a declarative domain specific language (DSL). - -# Invoking directives from HTML - -Directives have camel cased names such as 'ngBind'. The directive can be invoked by translating -the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the -directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a -list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and -`data-ng-bind`. - -The directives can be placed in element names, attributes, class names, as well as comments. Here -are some equivalent examples of invoking `myDir`. (However, most directives are restricted to -attribute only.) - -
-  
-  
-  
-  
-
- -Directives can be invoked in many different ways, but are equivalent in the end result as shown in -the following example. - - - - -
- Hello
- <span ng:bind="name">
- <span ng_bind="name">
- <span ng-bind="name">
- <span data-ng-bind="name">
- <span x-ng-bind="name">
-
-
- - it('should load template1.html', function() { - expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular'); - }); - -
- -# String interpolation - -During the compilation process the {@link angular.module.ng.$compile compiler} matches text and -attributes using the {@link angular.module.ng.$interpolate $interpolate} service to see if they -contain embedded expressions. These expressions are registered as {@link -angular.module.ng.$rootScope.Scope#$watch watches} and will update as part of normal {@link -angular.module.ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is shown -here: - -
-Hello {{username}}!
-
- -# Compilation process, and directive matching - -Compilation of HTML happens in three phases: - - 1. First the HTML is parsed into DOM using the standard browser API. This is important to - realize because the templates must be parsable HTML. This is in contrast to most templating - systems that operate on strings, rather then on DOM elements. - - 2. The compilation of the DOM is performed by the call to {@link angular.module.ng.$compile - $compile()} method. The method traverses the DOM and matches the directives. If a match is found - it is added to the list of directives associated with the given DOM element. Once all directives - for a given DOM element have been identified they are sorted by priority and their `compile()` - functions are executed. The directive compile function has a chance to modify the DOM structure - and is responsible for producing a `link()` function explained next. The {@link - angular.module.ng.$compile $compile()} method returns a combined linking function, which is a - collection of all of the linking functions returned from the individual directive compile - functions. - - 3. Link the template with scope by calling the linking function returned from the previous step. - This in turn will call the linking function of the individual directives allowing them to - register any listeners on the elements and set up any {@link - angular.module.ng.$rootScope.Scope#$watch watches} with the {@link - angular.module.ng.$rootScope.Scope scope}. The result of this is a live binding between the - scope and the DOM. A change in the scope is reflected in the DOM. - -
-  var $compile = ...; // injected into your code
-  var scope = ...;
-
-  var html = '
'; - - // Step 1: parse HTML into DOM element - var template = angular.element(html); - - // Step 2: compile the template - var linkFn = $compile(template); - - // Step 3: link the compiled template with the scope. - linkFn(scope); -
- -## Reasons behind the compile/link separation - -At this point you may wonder why is the compile process broken down to a compile and link phase. -To understand this, lets look at a real world example with repeater: - -
-  Hello {{user}}, you have these actions:
-  
-
- -The short answer is that compile and link separation is needed any time a change in model causes -a change in DOM structure such as in repeaters. - -When the above example is compiled, the compiler visits every node and looks for directives. The -`{{user}}` is an example of {@link angular.module.ng.$interpolate interpolation} directive. {@link -angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} is another directive. But {@link -angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} has a dilemma. It needs to be -able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs -to save a clean copy of the `li` element for cloning purposes and as new `action`s are inserted, -the template `li` element needs to be cloned and inserted into `ul`. But cloning the `li` element -is not enough. It also needs to compile the `li` so that its directives such as -`{{action.descriptions}}` evaluate against the right {@link angular.module.ng.$rootScope.Scope -scope}. A naive method would be to simply insert a copy of the `li` elemnt and then compile it. -But compiling on every `li` element clone would be slow, since the compilation requires that we -traverse the DOM tree and look for directives and execute them. If we put the compilation inside a -repeater which needs to unroll 100 items we would quickly run into performance problem. - -The solution is to break the compilation process into two phases the compile phase where all of -the directives are identified and sorted by priority, and a linking phase where any work which -links a specific instance of the {@link angular.module.ng.$rootScope.Scope scope} and the specific -instance of an `li` is performed. - -{@link angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} works by preventing the -compilation process form descending into `li` element. Instead the {@link -angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} directive compiles `li` -seperatly. The result of of the `li` element compilation is a linking function which contains all -of the directives contained in the `li` element ready to be attached to a specific clone of `li` -element. At runtime the {@link angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} -watches the expression and as items are added to the array it clones the `li` element, creates a -new {@link angular.module.ng.$rootScope.Scope scope} for the cloned `li` element and calls the -link function on the cloned `li`. - -Summary: - - * *compile function* - The compile function is relatively rare in directives, since most - directives are concerned with working with a specific DOM element instance rather then - transforming the template DOM element. Any operation which can be shared among the instance of - directives should be moved to the compile function for performance reasons. - - * *link function* - It is rare for the directive not to have a link function. Link function - allows the directive to register listeners to the specific cloned DOM element instance as well - as to copy content into the DOM from the scope. - - -# Writing directives (short version) - -In this example we will build a directive which displays the current time. - - - - -
- Date format:
- Current time is: - - - - - - -# Writing directives (long version) - -The full skeleton of the directive is shown here: - -
-  var myModule = angular.module(...);
-
-  myModule.directive('directiveName', function factory(injectables) {
-    var directiveDefinitionObject = {
-      priority: 0,
-      template: '
', - templateUrl: 'directive.html', - replace: false, - transclude: false, - restrict: 'A', - scope: false, - compile: function compile(tElement, tAttrs, transclude) { - return { - pre: function preLink(scope, iElement, iAttrs, controller) { ... }, - post: function postLink(scope, iElement, iAttrs, controller) { ... } - } - }, - link: function postLink(scope, iElement, iAttrs) { ... } - }; - return directiveDefinitionObject; - }); -
- -In most cases you will not need such fine control and so the above can be simplified. All of the -different parts of this skeleton are explained in following sections. In this section we are -interested only isomers of this skeleton. - -The first step in simplyfing the code is to rely on the deafult values. Therefore the above can be -simplified as: - -
-  var myModule = angular.module(...);
-
-  myModule.directive('directiveName', function factory(injectables) {
-    var directiveDefinitionObject = {
-      compile: function compile(tElement, tAttrs) {
-        return function postLink(scope, iElement, iAttrs) { ... }
-      }
-    };
-    return directiveDefinitionObject;
-  });
-
- -Most directives concern themselves only with instances not with template transformations allowing -further simplification: - -
-  var myModule = angular.module(...);
-
-  myModule.directive('directiveName', function factory(injectables) {
-    return function postLink(scope, iElement, iAttrs) { ... }
-  });
-
- - -## Factory method - -The factory method is responsible for creating the directive. It is invoked only once, when the -{@link angular.module.ng.$compile compiler} matches the directive for the first time. You can -perform any initialization work here. The method is invoked using the {@link -http://localhost:8000/build/docs/api/angular.module.AUTO.$injector#invoke $injector.invoke} which -makes it injectable following all of the rules of injection annotation. - -## Directive Definition Object - -The directive definition object provides instructions to the {@link angular.module.ng.$compile -compiler}. The attributes are: - - * `name` - Name of the current scope. Optional defaults to the name at registration. - - * `priority` - When there are multiple directives defined on a single DOM element, sometimes it - is necessary to specify the order in which the directives are applied. The `priority` is used - to sort the directives before their `compile` functions get called. Higher `priority` goes - first. The order of directives within the same priority is undefined. - - * `terminal` - If set to true then the current `priority` will be the last set of directives - which will execute (any directives at the current priority will still execute - as the order of execution on same `priority` is undefined). - - * `scope` - If set to: - - * `true` - then a new scope will be created for this directive. If multiple directives on the - same element request new scope, only one new scope is created. The new scope rule does not - apply for the root of the template since the root of the template always gets a new scope. - - * `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from - normal scope that it does not prototypically inherit from the parent scope. This is useful - when creating reusable components, which should not accidentally read or modify data in - parent scope.
- The 'isolate' scope takes an object hash which defines a set of local scope properties - derived from the parent scope. These local properties are useful for aliasing values for - templates. Locals definition is a hash of normalized element attribute name to their - corresponding binding strategy. Valid binding strategies are: - - * `attribute` - one time read of element attribute value and save it to widget scope.
- Given `` and widget definition of `scope: {myAttr:'attribute'}`, - then widget scope property `myAttr` will be `"abc"`. - - * `evaluate` - one time evaluation of expression stored in the attribute.
Given - `` and widget definition of `scope: {myAttr:'evaluate'}`, and - parent scope `{name:'angular'}` then widget scope property `myAttr` will be `"angular"`. - - * `bind` - Set up one way binding from the element attribute to the widget scope.
- Given `` and widget definition of `scope: {myAttr:'bind'}`, - and parent scope `{name:'angular'}` then widget scope property `myAttr` will be - `"angular"`, but any changes in the parent scope will be reflected in the widget scope. - - * `accessor` - Set up getter/setter function for the expression in the widget element - attribute to the widget scope.
Given `` and widget definition - of `scope: {myAttr:'prop'}`, and parent scope `{name:'angular'}` then widget scope - property `myAttr` will be a function such that `myAttr()` will return `"angular"` and - `myAttr('new value')` will update the parent scope `name` property. This is useful for - treating the element as a data-model for reading/writing. - - * `expression` - Treat element attribute as an expression to be executed on the parent scope. -
- Given `` and widget definition of `scope: - {myAttr:'expression'}`, and parent scope `{doSomething:function() {}}` then calling the - widget scope function `myAttr` will execute the expression against the parent scope. - - * `controller` - Controller constructor function. The controller is instantiated before the - pre-linking phase and it is shared with other directives if they request it by name (see - `require` attribute). This allows the directives to communicate with each other and augment - each other behavior. The controller is injectable with the following locals: - - * `$scope` - Current scope associated with the element - * `$element` - Current element - * `$attrs` - Current attributes obeject for the element - * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope: - `function(cloneLinkingFn)`. - - * `require` - Require another controller be passed into current directive linking function. The - `require` takes a name of the directive controller to pass in. If no such controller can be - found an error is raised. The name can be prefixed with: - - * `?` - Don't raise an error. This makes the require dependency optional. - * `^` - Look for the controller on parent elements as well. - - - * `inject` (object hash) - Specifies a way to inject bindings into a controller. Injection - definition is a hash of normalized element attribute names to their corresponding binding - strategy. Valid binding strategies are: - - * `attribute` - inject attribute value.
- Given `` and widget definition of `inject: {myAttr:'attribute'}`, then - `myAttr` will inject `"abc"`. - - * `evaluate` - inject one time evaluation of expression stored in the attribute.
- Given `` and widget definition of `inject: {myAttr:'evaluate'}`, and - parent scope `{name:'angular'}` then `myAttr` will inject `"angular"`. - - * `accessor` - inject a getter/setter function for the expression in the widget element - attribute to the widget scope.
- Given `` and widget definition of `inject: {myAttr:'prop'}`, and - parent scope `{name:'angular'}` then injecting `myAttr` will inject a function such - that `myAttr()` will return `"angular"` and `myAttr('new value')` will update the parent - scope `name` property. This is usefull for treating the element as a data-model for - reading/writing. - - * `expression` - Inject expression function.
- Given `` and widget definition of - `inject: {myAttr:'expression'}`, and parent scope `{doSomething:function() {}}` then - injecting `myAttr` will inject a function which when called will execute the expression - against the parent scope. - - * `restrict` - String of subset of `EACM` which restricts the directive to a specific directive - declaration style. If omitted directives are allowed on attributes only. - - * `E` - Element name: `` - * `A` - Attribute: `
` - * `C` - Class: `
` - * `M` - Comment: `` - - * `template` - replace the current element with the contents of the HTML. The replacement process - migrates all of the attributes / classes from the old element to the new one. See Creating - Widgets section below for more information. - - * `templateUrl` - Same as `template` but the template is loaded from the specified URL. Because - the template loading is asynchronous the compilation/linking is suspended until the template - is loaded. - - * `replace` - if set to `true` then the template will replace the current element, rather then - append the template to the element. - - * `transclude` - compile the content of the element and make it available to the directive. - Typically used with {@link api/angular.module.ng.$compileProvider.directive.ngTransclude - ngTransclude}. The advantage of transclusion is that the linking function receives a - transclusion function which is pre-bound to the correct scope. In a typical setup the widget - creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate` - scope. This makes it possible for the widget to have private state, and the transclusion to - be bound to the parent (pre-`isolate`) scope. - - * `true` - transclude the content of the directive. - * `'element'` - transclude the whole element including any directives defined at lower priority. - - - * `compile`: This is the compile function described in the section below. - - * `link`: This is the link function described in the section below. This property is used only - if the `compile` property is not defined. - -## Compile function - -
-  function compile(tElement, tAttrs, transclude) { ... }
-
- -Compile function deals with transforming the template DOM. Since most directives do not do -template transformation, it is not used often. Examples which require compile functions are -directives which transform template DOM such as {@link -angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} or load the contents -asynchronously such as {@link angular.module.ng.$compileProvider.directive.ngView ngView}. The -compile functions takes the following arguments. - - * `tElement` - template element - The element where the directive has been declared. It is - safe to do template transformation on the element and child elements only. - - * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared - between all directive compile functions. See {@link - #Attributes Attributes} - - * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`. - -NOTE: The template instance and the link instance may not be the same objects if the template has -been cloned. For this reason it is not safe in the compile function to do anything other the DOM -transformation that applies to all DOM clones. Specifically, DOM listener registration should be -done in a linking function rather than in a compile function. - -A compile function can have a return value which can be either a function or an object. - -* returning a function - is equivalent to registering the linking function via the `link` property - of the config object when the compile function is empty. - -* returning an object with function(s) registered via `pre` and `post` properties - allows you to - control when a linking function should be called during the linking phase. See info about - pre-linking and post-linking functions below. - - -## Linking function - -
-  function link(scope, iElement, iAttrs, controller) { ... }
-
- -Link function is responsible for registering DOM listeners as well as updating the DOM. It is -executed after the template has been cloned. This is where most of the directive logic will be -put. - - * `scope` - {@link angular.module.ng.$rootScope.Scope Scope} - The scope to be used by the - directive for registering {@link angular.module.ng.$rootScope.Scope#$watch watches}. - - * `iElement` - instance element - The element where the directive is to be used. It is safe to - manipulate the children of the element only in `postLink` function since the children have - already been linked. - - * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared - between all directive linking functions. See {@link #Attributes Attributes} - - * `controller` - a controller instance - A controller instance if at least one directive on the - element defines a controller. The controller is shared among all the directives, which allows - the directives to use the controllers as a communication channel. - - - -### Pre-linking function - -Executed before the child elements are linked. Not safe to do DOM transformation since the -compiler linking function will fail to locate the correct elements for linking. - -### Post-linking function - -Executed after the child elements are linked. Safe to do DOM transformation in here. - - -## Attributes - -The attributes object - passed as a parameter in the link() or compile() functions - is a way of -accessing: - - * *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways - sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed to - the attributes. - - * *directive inter-communication:* All directives share the same instance of the attributes - object which allows the directives to use the attributes object as inter directive - communication. - - * *supports interpolation:* Interpolation attributes are assigned to the attribute object - allowing other directives to read the interpolated value. - - * *observing interpolated attributes:* Use `$observe` to observe the value changes of attributes - that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also - the only way to easily get the actual value because during the linking phase the interpolation - hasn't been evaluated yet and so the value is at this time set to `undefined`. - -
-function linkingFn(scope, elm, attrs, ctrl) {
-  // get the attribute value
-  console.log(attrs.ngModel);
-
-  // change the attribute
-  attrs.$set('ngModel', 'new value');
-
-  // observe changes to interpolated attribute
-  attrs.$observe('ngModel', function(value) {
-    console.log('ngModel has changed value to ' + value);
-  });
-}
-
- - -# Understanding Transclusion and Scopes - -It is often desirable to have reusable components. Below is a pseudo code showing how a simplified -dialog component may work. - -
-  
- - - Body goes here: {{username}} is {{title}}. - -
- -Clicking on the "show" button will open the dialog. The dialog will have a title, which is -data bound to `username`, and it will also have a body which we would like to transclude -into the dialog. - -Here is an example of what the template definition for the `dialog` widget may look like. - -
-  
-

{{title}}

-
- -
-
- -This will not render properly, unless we do some scope magic. - -The first issue we have to solve is that the dialog box template expect `title` to be defined, but -the place of instantiation would like to bind to `username`. Furthermore the buttons expect `onOk` -as well as `onCancel` functions to be present in the scope. This limits the usefulness of the -widget. To solve the mapping issue we use the `locals` to create local variables which the template -expects as follows: - -
-  scope: {
-    title: 'bind',          // set up title to accept data-binding
-    onOk: 'expression',     // create a delegate onOk function
-    onCancel: 'expression', // create a delegate onCancel function
-    show: 'accessor'        // create a getter/setter function for visibility.
-  }
-
- -Creating local properties on widget scope creates two problems: - - 1. isolation - if the user forgets to set `title` attribute of the dialog widget the dialog - template will bind to parent scope property. This is unpredictable and undesirable. - - 2. transclusion - the transcluded DOM can see the widget locals, which may overwrite the - properties which the transclusion needs for data-binding. In our example the `title` - property of the widget clobbers the `title` property of the transclusion. - - -To solve the issue of lack of isolation, the directive declares a new `isolated` scope. An -isolated scope does not prototypically inherit from the child scope, and therefore we don't have -to worry about accidentally clobbering any properties. - -However 'isolated' scope creates a new problem: if a transcluded DOM is a child of the widget -isolated scope then it will not be able to bind to anything. For this reason the transcluded scope -is a child of the original scope, before the widget created an isolated scope for its local -variables. This makes the transcluded and widget isolated scope siblings. - -This may seem as unexpected complexity, but it gives the widget user and developer the least -surprise. - -Therefore the final directive definition looks something like this: - -
-transclude: true,
-scope: {
-  title: 'bind',          // set up title to accept data-binding
-  onOk: 'expression',     // create a delegate onOk function
-  onCancel: 'expression', // create a delegate onCancel function
-  show: 'accessor'        // create a getter/setter function for visibility.
-}
-
- -# Creating Components - -It is often desirable to replace a single directive with a more complex DOM structure. This -allows the directives to become a short hand for reusable components from which applications -can be built. - -Following is an example of building a reusable widget. - - - - - - -
- Title:
- Text: -
-
{{text}}
-
-
- - it('should bind and open / close', function() { - input('title').enter('TITLE'); - input('text').enter('TEXT'); - expect(element('.title').text()).toEqual('Details: TITLE...'); - expect(binding('text')).toEqual('TEXT'); - - expect(element('.zippy').prop('className')).toMatch(/closed/); - element('.zippy > .title').click(); - expect(element('.zippy').prop('className')).toMatch(/opened/); - }); - -
diff --git a/docs/content/api/index.ngdoc b/docs/content/api/index.ngdoc index 9f1bb398..88e354f5 100644 --- a/docs/content/api/index.ngdoc +++ b/docs/content/api/index.ngdoc @@ -2,62 +2,6 @@ @name API Reference @description -## Angular Compiler API - -* {@link angular.module.ng.$compileProvider.directive Directives} - Angular DOM element attributes -* {@link angular.module.ng.$filter Filters} - Angular output filters -* {@link angular.module.ng.$compile $compile} - Template compiler - -## Angular Scope API - -* {@link angular.module.ng.$rootScope.Scope Scope Object} - Angular scope object - - -## Angular Services & Dependency Injection API - -* {@link angular.module.ng Angular Services} -* {@link angular.injector angular.injector() } - - -## Angular Testing API - -* {@link angular.module.ngMock Testing Mocks API} - Mock objects for testing -* {@link guide/dev_guide.e2e-testing Angular Scenario Runner} - Automated scenario testing -documentation - - -## Angular Utility Functions - -### HTML & DOM Manipulation - -* {@link angular.element angular.element()} - -### Misc - -* {@link angular.bind angular.bind() } -* {@link angular.extend angular.extend() } -* {@link angular.forEach angular.forEach() } -* {@link angular.identity angular.identity() } -* {@link angular.noop angular.noop() } - - -## Type Identification - -* {@link angular.isArray angular.isArray() } -* {@link angular.isDate angular.isDate() } -* {@link angular.isDefined angular.isDefined() } -* {@link angular.isFunction angular.isFunction() } -* {@link angular.isNumber angular.isNumber() } -* {@link angular.isObject angular.isObject() } -* {@link angular.isString angular.isString() } -* {@link angular.isUndefined angular.isUndefined() } - -## Strings - -* {@link angular.lowercase angular.lowercase() } -* {@link angular.uppercase angular.uppercase() } - -### JSON - -* {@link angular.fromJson angular.fromJson() } -* {@link angular.toJson angular.toJson() } +Use the API Refference documentation when you need more information about a specific feature. Check out +{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recomend the +{@link tutorial/ Tutorial}. diff --git a/docs/content/cookbook/deeplinking.ngdoc b/docs/content/cookbook/deeplinking.ngdoc index f242f82e..491e3b79 100644 --- a/docs/content/cookbook/deeplinking.ngdoc +++ b/docs/content/cookbook/deeplinking.ngdoc @@ -30,72 +30,111 @@ In this example we have a simple app which consist of two screens: * Welcome: url `welcome` Show the user contact information. * Settings: url `settings` Show an edit screen for user contact information. - -The two partials are defined in the following URLs: - -* ./examples/settings.html -* ./examples/welcome.html - - - - + + + angular.module('deepLinking', ['ngSanitize']) + .config(function($routeProvider) { + $routeProvider. + when("/welcome", {template:'welcome.html', controller:WelcomeCntl}). + when("/settings", {template:'settings.html', controller:SettingsCntl}); + }); + + AppCntl.$inject = ['$scope', '$route'] + function AppCntl($scope, $route) { + $scope.$route = $route; + + // initialize the model to something useful + $scope.person = { + name:'anonymous', + contacts:[{type:'email', url:'anonymous@example.com'}] + }; + } + + function WelcomeCntl($scope) { + $scope.greet = function() { + alert("Hello " + $scope.person.name); + }; + } + + function SettingsCntl($scope, $location) { + $scope.cancel = function() { + $scope.form = angular.copy($scope.person); + }; + + $scope.save = function() { + angular.copy($scope.form, $scope.person); + $location.path('/welcome'); + }; + + $scope.cancel(); + } + + + [ng-view] { + border: 1px solid blue; + margin: 0; + padding:1em; + } + + .partial-info { + background-color: blue; + color: white; + padding: 3px; + } + +

Your App Chrome

[ Welcome | Settings ]
- + Partial: {{$route.current.template}} - +
Your app footer
-
- + + + + + +
+ + + [ X ] +
+
+ [ add ] +
+ + + +
+ + Hello {{person.name}}, +
+ Your contact information: +
{{contact.type}}: + +
+
+
+ it('should navigate to URL', function() { - element('a:contains(Welcome)').click(); - expect(element('ng\\:view').text()).toMatch(/Hello anonymous/); - element('a:contains(Settings)').click(); - input('form.name').enter('yourname'); - element(':button:contains(Save)').click(); - element('a:contains(Welcome)').click(); - expect(element('ng\\:view').text()).toMatch(/Hello yourname/); + element('a:contains(Welcome)').click(); + expect(element('[ng-view]').text()).toMatch(/Hello anonymous/); + element('a:contains(Settings)').click(); + input('form.name').enter('yourname'); + element(':button:contains(Save)').click(); + element('a:contains(Welcome)').click(); + expect(element('[ng-view]').text()).toMatch(/Hello yourname/); }); -
-
+ + diff --git a/docs/content/guide/dev_guide.bootstrap.ngdoc b/docs/content/guide/dev_guide.bootstrap.ngdoc index 02351ede..391475ca 100644 --- a/docs/content/guide/dev_guide.bootstrap.ngdoc +++ b/docs/content/guide/dev_guide.bootstrap.ngdoc @@ -38,7 +38,7 @@ Compatibility} doc. ## Creating Your Own Namespaces -When you are ready to define your own {@link api/angular.module.ng.$compileProvider.directive +When you are ready to define your own {@link guide/directive directive}, you may chose to create your own namespace in addition to specifying the Angular namespace. You use your own namespace to form the fully qualified name for directives that you create. diff --git a/docs/content/guide/dev_guide.compiler.ngdoc b/docs/content/guide/dev_guide.compiler.ngdoc index d979f309..f52928a6 100644 --- a/docs/content/guide/dev_guide.compiler.ngdoc +++ b/docs/content/guide/dev_guide.compiler.ngdoc @@ -3,7 +3,7 @@ @description The core of Angular is its HTML compiler. The compiler processes Angular -{@link api/angular.module.ng.$compileProvider.directive directives} allowing them to transform a +{@link guide/directive directives} allowing them to transform a static HTML page into a dynamic web application. The default HTML transformations that the Angular compiler provides are useful for building generic @@ -21,4 +21,4 @@ All compilation takes place in the web browser; no server is involved. ## Related API * {@link api/angular.module.ng.$compile Angular Compiler API} -* {@link api/angular.module.ng.$compileProvider.directive Directives API} +* {@link guide/directive Directives API} diff --git a/docs/content/guide/dev_guide.compiler.understanding_compiler.ngdoc b/docs/content/guide/dev_guide.compiler.understanding_compiler.ngdoc index 96c89d32..ea433cc5 100644 --- a/docs/content/guide/dev_guide.compiler.understanding_compiler.ngdoc +++ b/docs/content/guide/dev_guide.compiler.understanding_compiler.ngdoc @@ -3,7 +3,7 @@ @description The {@link api/angular.module.ng.$compile compiler} is responsible for applying -{@link api/angular.module.ng.$compileProvider.directive directives} to the HTML. The directives +{@link guide/directive directives} to the HTML. The directives extend the behavior of HTML elements and can effect the DOM structure, presentation, and behavior. This allows Angular to teach the browser new tricks. @@ -21,7 +21,7 @@ Since directives allow attachment of behavior to the HTML, the angular philosoph HTML as Domain Specific Language (DSL) when building an application. For example it may be useful to declare `TabPanel` directive, or `KeyboardShortcut` directive when for an application. -For details on how directives are created see {@link api/angular.module.ng.$compileProvider.directive +For details on how directives are created see {@link guide/directive directives} ## Related Topics diff --git a/docs/content/guide/dev_guide.forms.ngdoc b/docs/content/guide/dev_guide.forms.ngdoc index fe668ddf..6621e231 100644 --- a/docs/content/guide/dev_guide.forms.ngdoc +++ b/docs/content/guide/dev_guide.forms.ngdoc @@ -31,7 +31,7 @@ In addition it provides {@link api/angular.module.ng.$compileProvider.directive.
master = {{master | json}}
- +
+ Hello
+ <span ng:bind="name">
+ <span ng_bind="name">
+ <span ng-bind="name">
+ <span data-ng-bind="name">
+ <span x-ng-bind="name">
+
+
+ + it('should show off bindings', function() { + expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular'); + }); + +
+ +# String interpolation + +During the compilation process the {@link api/angular.module.ng.$compile compiler} matches text and +attributes using the {@link api/angular.module.ng.$interpolate $interpolate} service to see if they +contain embedded expressions. These expressions are registered as {@link +api/angular.module.ng.$rootScope.Scope#$watch watches} and will update as part of normal {@link +api/angular.module.ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is shown +here: + +
+Hello {{username}}!
+
+ +# Compilation process, and directive matching + +Compilation of HTML happens in three phases: + + 1. First the HTML is parsed into DOM using the standard browser API. This is important to + realize because the templates must be parsable HTML. This is in contrast to most templating + systems that operate on strings, rather then on DOM elements. + + 2. The compilation of the DOM is performed by the call to {@link api/angular.module.ng.$compile + $compile()} method. The method traverses the DOM and matches the directives. If a match is found + it is added to the list of directives associated with the given DOM element. Once all directives + for a given DOM element have been identified they are sorted by priority and their `compile()` + functions are executed. The directive compile function has a chance to modify the DOM structure + and is responsible for producing a `link()` function explained next. The {@link + api/angular.module.ng.$compile $compile()} method returns a combined linking function, which is a + collection of all of the linking functions returned from the individual directive compile + functions. + + 3. Link the template with scope by calling the linking function returned from the previous step. + This in turn will call the linking function of the individual directives allowing them to + register any listeners on the elements and set up any {@link + api/angular.module.ng.$rootScope.Scope#$watch watches} with the {@link + api/angular.module.ng.$rootScope.Scope scope}. The result of this is a live binding between the + scope and the DOM. A change in the scope is reflected in the DOM. + +
+  var $compile = ...; // injected into your code
+  var scope = ...;
+
+  var html = '
'; + + // Step 1: parse HTML into DOM element + var template = angular.element(html); + + // Step 2: compile the template + var linkFn = $compile(template); + + // Step 3: link the compiled template with the scope. + linkFn(scope); +
+ +## Reasons behind the compile/link separation + +At this point you may wonder why is the compile process broken down to a compile and link phase. +To understand this, lets look at a real world example with repeater: + +
+  Hello {{user}}, you have these actions:
+  
+
+ +The short answer is that compile and link separation is needed any time a change in model causes +a change in DOM structure such as in repeaters. + +When the above example is compiled, the compiler visits every node and looks for directives. The +`{{user}}` is an example of {@link api/angular.module.ng.$interpolate interpolation} directive. {@link +api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} is another directive. But {@link +api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} has a dilemma. It needs to be +able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs +to save a clean copy of the `li` element for cloning purposes and as new `action`s are inserted, +the template `li` element needs to be cloned and inserted into `ul`. But cloning the `li` element +is not enough. It also needs to compile the `li` so that its directives such as +`{{action.descriptions}}` evaluate against the right {@link api/angular.module.ng.$rootScope.Scope +scope}. A naive method would be to simply insert a copy of the `li` elemnt and then compile it. +But compiling on every `li` element clone would be slow, since the compilation requires that we +traverse the DOM tree and look for directives and execute them. If we put the compilation inside a +repeater which needs to unroll 100 items we would quickly run into performance problem. + +The solution is to break the compilation process into two phases the compile phase where all of +the directives are identified and sorted by priority, and a linking phase where any work which +links a specific instance of the {@link api/angular.module.ng.$rootScope.Scope scope} and the specific +instance of an `li` is performed. + +{@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} works by preventing the +compilation process form descending into `li` element. Instead the {@link +api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} directive compiles `li` +seperatly. The result of of the `li` element compilation is a linking function which contains all +of the directives contained in the `li` element ready to be attached to a specific clone of `li` +element. At runtime the {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} +watches the expression and as items are added to the array it clones the `li` element, creates a +new {@link api/angular.module.ng.$rootScope.Scope scope} for the cloned `li` element and calls the +link function on the cloned `li`. + +Summary: + + * *compile function* - The compile function is relatively rare in directives, since most + directives are concerned with working with a specific DOM element instance rather then + transforming the template DOM element. Any operation which can be shared among the instance of + directives should be moved to the compile function for performance reasons. + + * *link function* - It is rare for the directive not to have a link function. Link function + allows the directive to register listeners to the specific cloned DOM element instance as well + as to copy content into the DOM from the scope. + + +# Writing directives (short version) + +In this example we will build a directive which displays the current time. + + + + +
+ Date format:
+ Current time is: + + + + + + +# Writing directives (long version) + +The full skeleton of the directive is shown here: + +
+  var myModule = angular.module(...);
+
+  myModule.directive('directiveName', function factory(injectables) {
+    var directiveDefinitionObject = {
+      priority: 0,
+      template: '
', + templateUrl: 'directive.html', + replace: false, + transclude: false, + restrict: 'A', + scope: false, + compile: function compile(tElement, tAttrs, transclude) { + return { + pre: function preLink(scope, iElement, iAttrs, controller) { ... }, + post: function postLink(scope, iElement, iAttrs, controller) { ... } + } + }, + link: function postLink(scope, iElement, iAttrs) { ... } + }; + return directiveDefinitionObject; + }); +
+ +In most cases you will not need such fine control and so the above can be simplified. All of the +different parts of this skeleton are explained in following sections. In this section we are +interested only isomers of this skeleton. + +The first step in simplyfing the code is to rely on the deafult values. Therefore the above can be +simplified as: + +
+  var myModule = angular.module(...);
+
+  myModule.directive('directiveName', function factory(injectables) {
+    var directiveDefinitionObject = {
+      compile: function compile(tElement, tAttrs) {
+        return function postLink(scope, iElement, iAttrs) { ... }
+      }
+    };
+    return directiveDefinitionObject;
+  });
+
+ +Most directives concern themselves only with instances not with template transformations allowing +further simplification: + +
+  var myModule = angular.module(...);
+
+  myModule.directive('directiveName', function factory(injectables) {
+    return function postLink(scope, iElement, iAttrs) { ... }
+  });
+
+ + +## Factory method + +The factory method is responsible for creating the directive. It is invoked only once, when the +{@link api/angular.module.ng.$compile compiler} matches the directive for the first time. You can +perform any initialization work here. The method is invoked using the {@link +http://localhost:8000/build/docs/api/angular.module.AUTO.$injector#invoke $injector.invoke} which +makes it injectable following all of the rules of injection annotation. + +## Directive Definition Object + +The directive definition object provides instructions to the {@link api/angular.module.ng.$compile +compiler}. The attributes are: + + * `name` - Name of the current scope. Optional defaults to the name at registration. + + * `priority` - When there are multiple directives defined on a single DOM element, sometimes it + is necessary to specify the order in which the directives are applied. The `priority` is used + to sort the directives before their `compile` functions get called. Higher `priority` goes + first. The order of directives within the same priority is undefined. + + * `terminal` - If set to true then the current `priority` will be the last set of directives + which will execute (any directives at the current priority will still execute + as the order of execution on same `priority` is undefined). + + * `scope` - If set to: + + * `true` - then a new scope will be created for this directive. If multiple directives on the + same element request new scope, only one new scope is created. The new scope rule does not + apply for the root of the template since the root of the template always gets a new scope. + + * `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from + normal scope that it does not prototypically inherit from the parent scope. This is useful + when creating reusable components, which should not accidentally read or modify data in + parent scope.
+ The 'isolate' scope takes an object hash which defines a set of local scope properties + derived from the parent scope. These local properties are useful for aliasing values for + templates. Locals definition is a hash of normalized element attribute name to their + corresponding binding strategy. Valid binding strategies are: + + * `attribute` - one time read of element attribute value and save it to widget scope.
+ Given `` and widget definition of `scope: {myAttr:'attribute'}`, + then widget scope property `myAttr` will be `"abc"`. + + * `evaluate` - one time evaluation of expression stored in the attribute.
Given + `` and widget definition of `scope: {myAttr:'evaluate'}`, and + parent scope `{name:'angular'}` then widget scope property `myAttr` will be `"angular"`. + + * `bind` - Set up one way binding from the element attribute to the widget scope.
+ Given `` and widget definition of `scope: {myAttr:'bind'}`, + and parent scope `{name:'angular'}` then widget scope property `myAttr` will be + `"angular"`, but any changes in the parent scope will be reflected in the widget scope. + + * `accessor` - Set up getter/setter function for the expression in the widget element + attribute to the widget scope.
Given `` and widget definition + of `scope: {myAttr:'prop'}`, and parent scope `{name:'angular'}` then widget scope + property `myAttr` will be a function such that `myAttr()` will return `"angular"` and + `myAttr('new value')` will update the parent scope `name` property. This is useful for + treating the element as a data-model for reading/writing. + + * `expression` - Treat element attribute as an expression to be executed on the parent scope. +
+ Given `` and widget definition of `scope: + {myAttr:'expression'}`, and parent scope `{doSomething:function() {}}` then calling the + widget scope function `myAttr` will execute the expression against the parent scope. + + * `controller` - Controller constructor function. The controller is instantiated before the + pre-linking phase and it is shared with other directives if they request it by name (see + `require` attribute). This allows the directives to communicate with each other and augment + each other behavior. The controller is injectable with the following locals: + + * `$scope` - Current scope associated with the element + * `$element` - Current element + * `$attrs` - Current attributes obeject for the element + * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope: + `function(cloneLinkingFn)`. + + * `require` - Require another controller be passed into current directive linking function. The + `require` takes a name of the directive controller to pass in. If no such controller can be + found an error is raised. The name can be prefixed with: + + * `?` - Don't raise an error. This makes the require dependency optional. + * `^` - Look for the controller on parent elements as well. + + + * `inject` (object hash) - Specifies a way to inject bindings into a controller. Injection + definition is a hash of normalized element attribute names to their corresponding binding + strategy. Valid binding strategies are: + + * `attribute` - inject attribute value.
+ Given `` and widget definition of `inject: {myAttr:'attribute'}`, then + `myAttr` will inject `"abc"`. + + * `evaluate` - inject one time evaluation of expression stored in the attribute.
+ Given `` and widget definition of `inject: {myAttr:'evaluate'}`, and + parent scope `{name:'angular'}` then `myAttr` will inject `"angular"`. + + * `accessor` - inject a getter/setter function for the expression in the widget element + attribute to the widget scope.
+ Given `` and widget definition of `inject: {myAttr:'prop'}`, and + parent scope `{name:'angular'}` then injecting `myAttr` will inject a function such + that `myAttr()` will return `"angular"` and `myAttr('new value')` will update the parent + scope `name` property. This is usefull for treating the element as a data-model for + reading/writing. + + * `expression` - Inject expression function.
+ Given `` and widget definition of + `inject: {myAttr:'expression'}`, and parent scope `{doSomething:function() {}}` then + injecting `myAttr` will inject a function which when called will execute the expression + against the parent scope. + + * `restrict` - String of subset of `EACM` which restricts the directive to a specific directive + declaration style. If omitted directives are allowed on attributes only. + + * `E` - Element name: `` + * `A` - Attribute: `
` + * `C` - Class: `
` + * `M` - Comment: `` + + * `template` - replace the current element with the contents of the HTML. The replacement process + migrates all of the attributes / classes from the old element to the new one. See Creating + Widgets section below for more information. + + * `templateUrl` - Same as `template` but the template is loaded from the specified URL. Because + the template loading is asynchronous the compilation/linking is suspended until the template + is loaded. + + * `replace` - if set to `true` then the template will replace the current element, rather then + append the template to the element. + + * `transclude` - compile the content of the element and make it available to the directive. + Typically used with {@link api/angular.module.ng.$compileProvider.directive.ngTransclude + ngTransclude}. The advantage of transclusion is that the linking function receives a + transclusion function which is pre-bound to the correct scope. In a typical setup the widget + creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate` + scope. This makes it possible for the widget to have private state, and the transclusion to + be bound to the parent (pre-`isolate`) scope. + + * `true` - transclude the content of the directive. + * `'element'` - transclude the whole element including any directives defined at lower priority. + + + * `compile`: This is the compile function described in the section below. + + * `link`: This is the link function described in the section below. This property is used only + if the `compile` property is not defined. + +## Compile function + +
+  function compile(tElement, tAttrs, transclude) { ... }
+
+ +Compile function deals with transforming the template DOM. Since most directives do not do +template transformation, it is not used often. Examples which require compile functions are +directives which transform template DOM such as {@link +api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} or load the contents +asynchronously such as {@link api/angular.module.ng.$compileProvider.directive.ngView ngView}. The +compile functions takes the following arguments. + + * `tElement` - template element - The element where the directive has been declared. It is + safe to do template transformation on the element and child elements only. + + * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared + between all directive compile functions. See {@link + #Attributes Attributes} + + * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`. + +NOTE: The template instance and the link instance may not be the same objects if the template has +been cloned. For this reason it is not safe in the compile function to do anything other the DOM +transformation that applies to all DOM clones. Specifically, DOM listener registration should be +done in a linking function rather than in a compile function. + +A compile function can have a return value which can be either a function or an object. + +* returning a function - is equivalent to registering the linking function via the `link` property + of the config object when the compile function is empty. + +* returning an object with function(s) registered via `pre` and `post` properties - allows you to + control when a linking function should be called during the linking phase. See info about + pre-linking and post-linking functions below. + + +## Linking function + +
+  function link(scope, iElement, iAttrs, controller) { ... }
+
+ +Link function is responsible for registering DOM listeners as well as updating the DOM. It is +executed after the template has been cloned. This is where most of the directive logic will be +put. + + * `scope` - {@link api/angular.module.ng.$rootScope.Scope Scope} - The scope to be used by the + directive for registering {@link api/angular.module.ng.$rootScope.Scope#$watch watches}. + + * `iElement` - instance element - The element where the directive is to be used. It is safe to + manipulate the children of the element only in `postLink` function since the children have + already been linked. + + * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared + between all directive linking functions. See {@link #Attributes Attributes} + + * `controller` - a controller instance - A controller instance if at least one directive on the + element defines a controller. The controller is shared among all the directives, which allows + the directives to use the controllers as a communication channel. + + + +### Pre-linking function + +Executed before the child elements are linked. Not safe to do DOM transformation since the +compiler linking function will fail to locate the correct elements for linking. + +### Post-linking function + +Executed after the child elements are linked. Safe to do DOM transformation in here. + + +## Attributes + +The attributes object - passed as a parameter in the link() or compile() functions - is a way of +accessing: + + * *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways + sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed to + the attributes. + + * *directive inter-communication:* All directives share the same instance of the attributes + object which allows the directives to use the attributes object as inter directive + communication. + + * *supports interpolation:* Interpolation attributes are assigned to the attribute object + allowing other directives to read the interpolated value. + + * *observing interpolated attributes:* Use `$observe` to observe the value changes of attributes + that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also + the only way to easily get the actual value because during the linking phase the interpolation + hasn't been evaluated yet and so the value is at this time set to `undefined`. + +
+function linkingFn(scope, elm, attrs, ctrl) {
+  // get the attribute value
+  console.log(attrs.ngModel);
+
+  // change the attribute
+  attrs.$set('ngModel', 'new value');
+
+  // observe changes to interpolated attribute
+  attrs.$observe('ngModel', function(value) {
+    console.log('ngModel has changed value to ' + value);
+  });
+}
+
+ + +# Understanding Transclusion and Scopes + +It is often desirable to have reusable components. Below is a pseudo code showing how a simplified +dialog component may work. + +
+  
+ + + Body goes here: {{username}} is {{title}}. + +
+ +Clicking on the "show" button will open the dialog. The dialog will have a title, which is +data bound to `username`, and it will also have a body which we would like to transclude +into the dialog. + +Here is an example of what the template definition for the `dialog` widget may look like. + +
+  
+

{{title}}

+
+ +
+
+ +This will not render properly, unless we do some scope magic. + +The first issue we have to solve is that the dialog box template expect `title` to be defined, but +the place of instantiation would like to bind to `username`. Furthermore the buttons expect `onOk` +as well as `onCancel` functions to be present in the scope. This limits the usefulness of the +widget. To solve the mapping issue we use the `locals` to create local variables which the template +expects as follows: + +
+  scope: {
+    title: 'bind',          // set up title to accept data-binding
+    onOk: 'expression',     // create a delegate onOk function
+    onCancel: 'expression', // create a delegate onCancel function
+    show: 'accessor'        // create a getter/setter function for visibility.
+  }
+
+ +Creating local properties on widget scope creates two problems: + + 1. isolation - if the user forgets to set `title` attribute of the dialog widget the dialog + template will bind to parent scope property. This is unpredictable and undesirable. + + 2. transclusion - the transcluded DOM can see the widget locals, which may overwrite the + properties which the transclusion needs for data-binding. In our example the `title` + property of the widget clobbers the `title` property of the transclusion. + + +To solve the issue of lack of isolation, the directive declares a new `isolated` scope. An +isolated scope does not prototypically inherit from the child scope, and therefore we don't have +to worry about accidentally clobbering any properties. + +However 'isolated' scope creates a new problem: if a transcluded DOM is a child of the widget +isolated scope then it will not be able to bind to anything. For this reason the transcluded scope +is a child of the original scope, before the widget created an isolated scope for its local +variables. This makes the transcluded and widget isolated scope siblings. + +This may seem as unexpected complexity, but it gives the widget user and developer the least +surprise. + +Therefore the final directive definition looks something like this: + +
+transclude: true,
+scope: {
+  title: 'bind',          // set up title to accept data-binding
+  onOk: 'expression',     // create a delegate onOk function
+  onCancel: 'expression', // create a delegate onCancel function
+  show: 'accessor'        // create a getter/setter function for visibility.
+}
+
+ +# Creating Components + +It is often desirable to replace a single directive with a more complex DOM structure. This +allows the directives to become a short hand for reusable components from which applications +can be built. + +Following is an example of building a reusable widget. + + + + + + +
+ Title:
+ Text: +
+
{{text}}
+
+
+ + it('should bind and open / close', function() { + input('title').enter('TITLE'); + input('text').enter('TEXT'); + expect(element('.title').text()).toEqual('Details: TITLE...'); + expect(binding('text')).toEqual('TEXT'); + + expect(element('.zippy').prop('className')).toMatch(/closed/); + element('.zippy > .title').click(); + expect(element('.zippy').prop('className')).toMatch(/opened/); + }); + +
diff --git a/docs/content/guide/index.ngdoc b/docs/content/guide/index.ngdoc index 1870d1cc..77a16354 100644 --- a/docs/content/guide/index.ngdoc +++ b/docs/content/guide/index.ngdoc @@ -33,7 +33,7 @@ of the following documents before returning here to the Developer Guide: ## {@link dev_guide.compiler Angular HTML Compiler} -* {@link api/angular.module.ng.$compileProvider.directive Understanding Angular Directives} +* {@link guide/directive Understanding Angular Directives} ## {@link dev_guide.templates Angular Templates} diff --git a/docs/content/guide/type.ngdoc b/docs/content/guide/type.ngdoc new file mode 100644 index 00000000..7d576f28 --- /dev/null +++ b/docs/content/guide/type.ngdoc @@ -0,0 +1,3 @@ +@ngdoc overview +@name Developer Guide: Type +@description diff --git a/docs/content/misc/started.ngdoc b/docs/content/misc/started.ngdoc index 76bff181..e8110fdc 100644 --- a/docs/content/misc/started.ngdoc +++ b/docs/content/misc/started.ngdoc @@ -77,7 +77,7 @@ After the refresh, the page should look something like this: These are some of the important points to note from this example: -* The text input {@link api/angular.module.ng.$compileProvider.directive directive} +* The text input {@link guide/directive directive} is bound to a model variable called `yourname`. * The double curly braces notation binds the `yourname` model to the greeting text. diff --git a/docs/content/tutorial/index.ngdoc b/docs/content/tutorial/index.ngdoc index 1190aaf2..9bbe9e2f 100644 --- a/docs/content/tutorial/index.ngdoc +++ b/docs/content/tutorial/index.ngdoc @@ -7,7 +7,7 @@ the construction of an AngularJS web app. The app you will build is a catalog th of Android devices, lets you filter the list to see only devices that interest you, and then view details for any device. - + Work through the tutorial to see how Angular makes browsers smarter — without the use of extensions or plug-ins. As you work through the tutorial, you will: @@ -52,22 +52,22 @@ code management or to use scripts that copy snapshots of project files into your (`sandbox`) directory. Select one of the tabs below and follow the instructions for setting up your computer for your preferred option. - - +
+
  1. Verify that you have Java installed by running the following command in a terminal window:

    -
    java -version
    +
    java -version

    You will need Java to run unit tests.

  2. Download Git from the Git site.

    You can build Git from source or use the pre-compiled package.

  3. Clone the angular-phonecat repository located at Github by running the following command:

    -
    git clone git://github.com/angular/angular-phonecat.git
    +
    git clone git://github.com/angular/angular-phonecat.git

    This command creates the angular-phonecat directory in your current directory.

  4. Change your current directory to angular-phonecat:

    -
    cd angular-phonecat
    +
    cd angular-phonecat

    The tutorial instructions assume you are running all commands from the angular-phonecat directory.

  5. You will need an http server running on your system. Mac and Linux machines typically @@ -75,22 +75,22 @@ have Apache pre-installed, but If you don't already have one installed, you can href="http://nodejs.org/#download">install node.js. Use node to run scripts/web-server.js, a simple bundled http server.

- +
- +
  1. You will need Java to run unit tests, so run the following command to verify that you have Java installed and that the java executable is on your PATH.

    -
    java -version
    +
    java -version

  2. Install msysGit from the Git site.

  3. Open msysGit bash and clone the angular-phonecat repository located at Github by running the following command:

    -
    git clone git://github.com/angular/angular-phonecat.git
    +
    git clone git://github.com/angular/angular-phonecat.git

    This command creates the angular-phonecat directory in your current directory.

  4. Change your current directory to angular-phonecat.

    -
    cd angular-phonecat
    +
    cd angular-phonecat

    The tutorial instructions assume you are running all commands from the angular-phonecat directory.

    You should run all git commands from msysGit bash.

    @@ -101,18 +101,18 @@ already installed, you can install node.js nodejs\bin was added into your PATH. Use node to run scripts\web-server.js, a simple bundled http server.

- +
- +
  1. You need Java to run unit tests, so verify that you have Java installed by running the following command in a terminal window:

    -
    java -version
    +
    java -version
  2. Download the zip archive containing all of the files and unzip them into the [tutorial-dir] directory

    .
  3. Change your current directory to [tutorial-dir]/sandbox, as follows:

    -
    cd [tutorial-dir]/sandbox
    +
    cd [tutorial-dir]/sandbox

    The tutorial instructions assume you are running all commands from your sandbox directory.

  4. You need an http server running on your system and Mac and Linux machines typically @@ -120,29 +120,29 @@ have Apache pre-installed. If you don't have an http server installed, you can < href="http://nodejs.org/#download">install node.js and use it to run scripts/web-server.js, a simple bundled http server.

- +
- +
  1. Verify that you have Java installed and that the java executable is on your PATH by running the following command in the Windows command line:

    -
    java -version
    +
    java -version

    You need Java to run unit tests, so download the zip archive that contains all of the files and unzip the files into the [tutorial-dir] directory

  2. Change your current directory to [tutorial-dir]/sandbox, as follows:

    -
    cd [tutorial-dir]/sandbox
    +
    cd [tutorial-dir]/sandbox

    The tutorial instructions assume you are running all commands from this directory.

  3. You need an http server running on your system, but if you don't already have one already installed, you can install node.js. Make sure that nodejs\bin was added into your PATH. Use node to run scripts\web-server.js, a simple bundled http server.

- - +
+ The last thing to do is to make sure your computer has a web browser and a good text editor installed. Now, let's get some cool stuff done! -{@link step_00 Get Started!} +{@link step_00 Get Started!} diff --git a/docs/content/tutorial/step_00.ngdoc b/docs/content/tutorial/step_00.ngdoc index 3cf1c172..714f983e 100644 --- a/docs/content/tutorial/step_00.ngdoc +++ b/docs/content/tutorial/step_00.ngdoc @@ -2,7 +2,7 @@ @name Tutorial: 0 - Bootstrapping @description -
    +
      You are now ready to build the AngularJS phonecat app. In this step, you will become familiar @@ -10,11 +10,11 @@ with the most important source code files, learn how to start the development se angular-seed, and run the application in the browser. - - +
      +
      1. In angular-phonecat directory, run this command:

        -
        git checkout -f step-0
        +
        git checkout -f step-0

        This resets your workspace to step 0 of the tutorial app.

        You must repeat this for every future step in the tutorial and change the number to the number of the step you are on. This will cause any changes you made within @@ -41,13 +41,13 @@ directory.

      - +
      - +
      1. Open msysGit bash and run this command (in angular-phonecat directory):

        -
        git checkout -f step-0
        +
        git checkout -f step-0

        This resets your workspace to step 0 of the tutorial app.

        You must repeat this for every future step in the tutorial and change the number to the number of the step you are on. This will cause any changes you made within @@ -73,13 +73,13 @@ directory.

      - +
      - +
      1. In the angular-phonecat directory, run this command:

        -
        ./goto_step.sh 0
        +
        ./goto_step.sh 0

        This resets your workspace to step 0 of the tutorial app.

        You must repeat this for every future step in the tutorial and change the number to the number of the step you are on. This will cause any changes you made within @@ -105,13 +105,13 @@ href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html

      - +
      - +
      1. Open windows command line and run this command (in the angular-phonecat directory):

        -
        goto_step.bat 0
        +
        goto_step.bat 0

        This resets your workspace to step 0 of the tutorial app.

        You must repeat this for every future step in the tutorial and change the number to the number of the step you are on. This will cause any changes you made within @@ -137,8 +137,8 @@ href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html

      - - +
      +
      You can now see the page in your browser. It's not very exciting, but that's OK. @@ -233,7 +233,7 @@ in the view by updating all of the affected bindings. The structure of our application is currently very simple. The template contains just one directive and one static binding, and our model is empty. That will soon change! - + ## What are all these files in my working directory? @@ -265,7 +265,7 @@ For the purposes of this tutorial, we modified the angular-seed with the followi Now let's go to {@link step_01 step 1} and add some content to the web app. -
        +
          Note: During the bootstrap the injector and the root scope will then be associated with the diff --git a/docs/content/tutorial/step_01.ngdoc b/docs/content/tutorial/step_01.ngdoc index 11725031..a664c951 100644 --- a/docs/content/tutorial/step_01.ngdoc +++ b/docs/content/tutorial/step_01.ngdoc @@ -2,7 +2,7 @@ @name Tutorial: 1 - Static Template @description -
            +
              In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML @@ -12,7 +12,7 @@ dynamically display the same result with any set of data. In this step you will add some basic information about two cell phones to an HTML page. - +
              The page now contains a list with information about two phones. @@ -22,7 +22,6 @@ https://github.com/angular/angular-phonecat/compare/step-0...step-1 GitHub}: __`app/index.html`:__
              -...
                 
              • Nexus S @@ -37,7 +36,6 @@ __`app/index.html`:__

              -...
              @@ -54,4 +52,4 @@ This addition to your app uses static HTML to display the list. Now, let's go to step 2} to learn how to use AngularJS to dynamically generate the same list. -
                +
                  diff --git a/docs/content/tutorial/step_02.ngdoc b/docs/content/tutorial/step_02.ngdoc index d7e6a93f..bf7dc661 100644 --- a/docs/content/tutorial/step_02.ngdoc +++ b/docs/content/tutorial/step_02.ngdoc @@ -2,7 +2,7 @@ @name Tutorial: 2 - Angular Templates @description -
                    +
                      Now it's time to make the web page dynamic — with AngularJS. We'll also add a test that verifies the @@ -14,7 +14,7 @@ design pattern} to decouple the code and to separate concerns. With that in mind little Angular and JavaScript to add model, view, and controller components to our app. - +
                      The app now contains a list with three phones. @@ -64,7 +64,7 @@ tag as the template. bindings. As opposed to evaluating constants, these expression are refering to our application model, which was set up in our `PhoneListCtrl` controller. - + ## Model and Controller @@ -209,4 +209,4 @@ are testing as you go. Now, let's go to {@link step_03 step 3} to learn how to a to the app. -
                        +
                          diff --git a/docs/content/tutorial/step_03.ngdoc b/docs/content/tutorial/step_03.ngdoc index 60b4173b..26bb9d5f 100644 --- a/docs/content/tutorial/step_03.ngdoc +++ b/docs/content/tutorial/step_03.ngdoc @@ -2,7 +2,7 @@ @name Tutorial: 3 - Filtering Repeaters @description -
                            +
                              We did a lot of work in laying a foundation for the app in the last step, so now we'll do something @@ -11,7 +11,7 @@ test, because a good end-to-end test is a good friend. It stays with your app, k and quickly detects regressions. - +
                              The app now has a search box. Notice that the phone list on the page changes depending on what a @@ -31,7 +31,6 @@ We made no changes to the controller. __`app/index.html`:__
                              -...
                                 
                              @@ -53,7 +52,6 @@ __`app/index.html`:__
                              -...
                              We added a standard HTML `` tag and used angular's @@ -71,7 +69,7 @@ available as a filter input in the list repeater (`phone in phones | filter:`__` changes to the data model cause the repeater's input to change, the repeater efficiently updates the DOM to reflect the current state of the model. - + * Use of `filter` filter. The {@link api/angular.module.ng.$filter.filter filter} function uses the `query` value to create a new array that contains only those records that match the `query`. @@ -192,5 +190,5 @@ We have now added full text search and included a test to verify that search wor to {@link step_04 step 4} to learn how to add sorting capability to the phone app. -
                                +
                                  diff --git a/docs/content/tutorial/step_04.ngdoc b/docs/content/tutorial/step_04.ngdoc index 900a0340..ca452b59 100644 --- a/docs/content/tutorial/step_04.ngdoc +++ b/docs/content/tutorial/step_04.ngdoc @@ -2,7 +2,7 @@ @name Tutorial: 4 - Two-way Data Binding @description -
                                    +
                                      In this step, you will add a feature to let your users control the order of the items in the phone @@ -10,7 +10,7 @@ list. The dynamic ordering is implemented by creating a new model property, wiri the repeater, and letting the data binding magic do the rest of the work. - +
                                      You should see that in addition to the search box, the app displays a drop down menu that allows @@ -24,23 +24,20 @@ The most important differences between Steps 3 and 4 are listed below. You can s __`app/index.html`:__
                                      -...
                                      -        Search: 
                                      -        Sort by:
                                      -        
                                      -
                                      -...
                                      -
                                      -        
                                        -
                                      • - {{phone.name}} -

                                        {{phone.snippet}}

                                        -
                                      • -
                                      -... + Search: + Sort by: + + + +
                                        +
                                      • + {{phone.name}} +

                                        {{phone.snippet}}

                                        +
                                      • +
                                      We made the following changes to the `index.html` template: @@ -48,7 +45,7 @@ We made the following changes to the `index.html` template: * First, we added a `