diff options
Diffstat (limited to 'docs/content/guide')
48 files changed, 4237 insertions, 29 deletions
diff --git a/docs/content/guide/dev_guide.bootstrap.auto_bootstrap.ngdoc b/docs/content/guide/dev_guide.bootstrap.auto_bootstrap.ngdoc new file mode 100644 index 00000000..1c5e3e26 --- /dev/null +++ b/docs/content/guide/dev_guide.bootstrap.auto_bootstrap.ngdoc @@ -0,0 +1,130 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Initializing Angular: Automatic Initiialization +@description + + +Angular initializes automatically when you load the angular script into your page, specifying +angular's `ng:autobind` attribute with no arguments: + + + <script src="angular.js" ng:autobind> + + +From a high-level view, this is what happens during angular's automatic initialization process: + + +1. The browser loads the page, and then runs the angular script. + + + The `ng:autobind` attribute tells angular to compile and manage the whole HTML document. The +compilation phase is initiated in the page's `onLoad()` handler. Angular doesn't begin processing +the page until after the page load is complete. + + +2. Angular finds the root of the HTML document and creates the global variable `angular` in the +global namespace. Everything that angular subsequently creates is bound to fields in this global +object. + + +3. Angular walks the DOM looking for angular widgets, directives, and markup (such as `ng:init` or +`ng:repeat`). As angular encounters these, it creates child scopes as necessary and attaches them +to the DOM, registers listeners on those scopes, associates any controller functions with their +data and their part of the view, and ultimately constructs a runnable application. The resulting +app features two-way data-binding and a nice separation between data, presentation, and business +logic. + + +4. For the duration of the application session (while the page is loaded), angular monitors the +state of the application, and updates the view and the data model whenever the state of either one +changes. + + +For details on how the compiler works, see {@link dev_guide.compiler Angular HTML Compiler}. + + + + +## Initialization Options + + +The reason why `ng:autobind` exists is because angular should not assume that the entire HTML +document should be processed just because the `angular.js` script is included. In order to compile +only a part of the document, specify the ID of the element you want to use for angular's root +element as the value of the `ng:autobind` attribute: + + + ng:autobind="angularContent" + + + + +## Auto-bootstrap with `#autobind` + + +In some rare cases you can't define the `ng:` prefix before the script tag's attribute (for +example, in some CMS systems). In those situations it is possible to auto-bootstrap angular by +appending `#autobind` to the `<script src=...>` URL, like in this snippet: + + +<pre> + <!doctype html> + <html> + <head> + <script type="text/javascript" + src="http://code.angularjs.org/angular.js#autobind"></script> + </head> + <body> + <div xmlns:ng="http://angularjs.org"> + Hello {{'world'}}! + </div> + </body> + </html> +</pre> + + +As with `ng:autobind`, you can specify an element id that should be exclusively targeted for +compilation as the value of the `#autobind`, for example: `#autobind=angularContent`. + + +## Filename Restrictions for Auto-bootstrap + + +In order for us to find the auto-bootstrap from a script attribute or URL fragment, the value of +the `script` `src` attribute that loads the angular script must match one of these naming +conventions: + + +- `angular.js` +- `angular-min.js` +- `angular-x.x.x.js` +- `angular-x.x.x.min.js` +- `angular-x.x.x-xxxxxxxx.js` (dev snapshot) +- `angular-x.x.x-xxxxxxxx.min.js` (dev snapshot) +- `angular-bootstrap.js` (used for development of angular) + + +Optionally, any of the filename formats above can be prepended with a relative or absolute URL that +ends with `/`. + + +## Global Angular Object + + +The angular script creates a single global variable `angular` in the global namespace. All angular +APIs are bound to fields of this global object. + + + + +## Related Topics + + +* {@link dev_guide.bootstrap Initializing Angular} +* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization} + + +## Related API + + +{@link api/angular.compile Compiler API} diff --git a/docs/content/guide/dev_guide.bootstrap.manual_bootstrap.ngdoc b/docs/content/guide/dev_guide.bootstrap.manual_bootstrap.ngdoc new file mode 100644 index 00000000..2cce7b31 --- /dev/null +++ b/docs/content/guide/dev_guide.bootstrap.manual_bootstrap.ngdoc @@ -0,0 +1,58 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Initializing Angular: Manual Initialization +@description + + +Letting angular handle the initialization process (bootstrapping) is a handy way to start using +angular, but advanced users who want more control over the initialization process can choose to use +the manual bootstrapping method instead. + + +The best way to get started with manual bootstrapping is to look at the what happens when you use +{@link api/angular.directive.ng:autobind ng:autobind}, by showing each step of the process +explicitly. + + +<pre> +<!doctype html> +<html xmlns:ng="http://angularjs.org"> +<head> + <script type="text/javascript" src="http://code.angularjs.org/angular.js" + ng:autobind></script> + <script type="text/javascript"> + (angular.element(document).ready(function() { + angular.compile(document)(); + })(document); + </script> +</head> +<body> +Hello {{'World'}}! +</body> +</html> +</pre> + + +This is the sequence that your code should follow if you bootstrap angular on your own: + + +1. After the page is loaded, find the root of the HTML template, which is typically the root of +the document. +2. Run angular's {@link dev_guide.compiler Angular HTML compiler}, which converts a template into +an executable, bi-directionally bound application. + + + + +## Related Topics + + +* {@link dev_guide.bootstrap Initializing Angular} +* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization} +* {@link dev_guide.compiler Angular HTML compiler} + + +## Related API + + +{@link api/angular.compile Compiler API} diff --git a/docs/content/guide/dev_guide.bootstrap.ngdoc b/docs/content/guide/dev_guide.bootstrap.ngdoc new file mode 100644 index 00000000..49bb3a77 --- /dev/null +++ b/docs/content/guide/dev_guide.bootstrap.ngdoc @@ -0,0 +1,86 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Initializing Angular +@description + + +Initializing angular consists of loading the `angular.js` script in your page, and specifying how +angular should process and manage the page. To initialize angular you do the following: + + +* Specify the angular namespace in the `<html>` page +* Choose which flavor of angular script to load (debug or production) +* Specify whether or not angular should process and manage the page automatically (`ng:autobind`) + + +The simplest way to initialize angular is to load the angular script and tell angular to compile +and manage the whole page. You do this as follows: + + +<pre> +<!doctype html> +<html xmlns:ng="http://angularjs.org"> + <head> + ... + </head> + <body> + ... + <script src="angular.js" ng:autobind> + </body> +</pre> + + + + +## Specifying the Angular Namespace + + + <html xmlns:ng="http://angularjs.org"> + + +You need to declare the angular namespace declaration in the following cases: + + +* For all types of browser if you are using XHTML. +* For Internet Explorer older than version 9 (because older versions of IE do not render widgets +properly for either HTML or XHTML). + + + + +## Creating Your Own Namespaces + + +When you are ready to define your own {@link dev_guide.compiler.widgets widgets}, you must create +your own namespace in addition to specifying the angular namespace. You use your own namespace to +form the fully qualified name for widgets that you create. + + +For example, you could map the alias `my` to your domain, and create a widget called `my:widget`. +To create your own namespace, simply add another `xmlns` tag to your page, create an alias, and set +it to your unique domain: + + + <html xmlns:ng="http://angularjs.org" xmlns:my="http://mydomain.com"> + + + + +## Loading the Angular Bootstrap Script + + +The angular bootstrap script comes in two flavors; a debug script, and a production script: + + +* angular-[version].js - This is a human-readable file, suitable for development and debugging. +* angular-[version].min.js - This is a compressed and obfuscated file, suitable for use in +production. + + + + +## Related Topics + + +* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization} +* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization} diff --git a/docs/content/guide/dev_guide.compiler.directives.creating_directives.ngdoc b/docs/content/guide/dev_guide.compiler.directives.creating_directives.ngdoc new file mode 100644 index 00000000..570de384 --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.directives.creating_directives.ngdoc @@ -0,0 +1,49 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Directives: Creating Custom Angular Directives +@description + + +The following code snippet shows how to define a custom directive. You define a new directive by +extending the {@link dev_guide.compiler Angular HTML compiler}. The code snippet below is a +simplified definition of the built-in {@link api/angular.directive.ng:bind ng:bind} directive: + + +<pre> +angular.directive('ng:bind', function(expression, compiledElement) { + var compiler = this; + return function(linkElement) { + var currentScope = this; + currentScope.$watch(expression, function(value) { + linkElement.text(value); + }); + }; +}); +</pre> + + +# Additional Compiler Methods for Custom Directives + + +The angular compiler exposes methods that you may need to use when writing your own widgets and +directives. For example, the `descend()` method lets you control whether the compiler ignores or +processes child elements of the element it is compiling. For information on this and other +compiler methods, see the {@link api/angular.compile Compiler API doc}. + + + + +## Related Docs + + +* {@link dev_guide.compiler.directives Understanding Angular Directives} +* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets} +* {@link dev_guide.compiler Angular HTML Compiler} + + + + +## Related API + + +* {@link api/angular.directive Angular Directive API}. diff --git a/docs/content/guide/dev_guide.compiler.directives.ngdoc b/docs/content/guide/dev_guide.compiler.directives.ngdoc new file mode 100644 index 00000000..f853d5e8 --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.directives.ngdoc @@ -0,0 +1,61 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Understanding Angular Directives +@description + + +An angular directive is a custom HTML attribute that angular knows how to process. You add them to +a template element like any other attribute. Angular directives all have a `ng:` prefix. In the +following example, the angular directive (`ng:controller`) is a div tag: + + + <div ng:controller> + + +You use angular directives to modify DOM element properties. The element you modify can be an +existing HTML element type or a custom DOM element type that you created. You can use any number of +directives per element. + + +You add angular directives to a standard HTML tag as in the following example, in which we have +added the {@link api/angular.directive.ng:click ng:click} directive to a button tag: + + + <button name="button1" ng:click="foo()">Click This</button> + + +In the example above, `name` is the standard HTML attribute, and `ng:click` is the angular +directive. The `ng:click` directive lets you implement custom behavior in an associated controller +function. + + +In the next example, we add the {@link api/angular.directive.ng:bind ng:bind} directive to a +`<span>` tag: + + + <span ng:bind="1+2"></span> + + +The `ng:bind` directive tells angular to set up {@link dev_guide.templates.databinding data +binding} between the data model and the view for the specified expression. When the angular {@link +dev_guide.compiler compiler} encounters an `ng:bind` directive in a template, it passes the +attribute value to the `ng:bind` function, which in turn sets up the data binding. On any change to +the expression in the model, the view is updated to display the span text with the changed +expression value. + + + + +## Related Topics + + +* {@link dev_guide.compiler Angular HTML Compiler} +* {@link dev_guide.compiler.directives.creating_directives Creating Angular Directives} +* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets} + + +## Related API: + + +* {@link api/angular.directive Directive API} +* {@link api/angular.widget Widget API} diff --git a/docs/content/guide/dev_guide.compiler.directives_widgets.ngdoc b/docs/content/guide/dev_guide.compiler.directives_widgets.ngdoc new file mode 100644 index 00000000..53da202c --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.directives_widgets.ngdoc @@ -0,0 +1,59 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Comparing Directives and Attribute Widgets +@description + + +Although directives and {@link dev_guide.compiler.widgets attribute widgets} appear the same in a +template (`ng:init` is a directive, `ng:repeat` is an attribute widget), there is a difference in +the order in which they are evaluated. The user of existing directives or widgets cannot determine +the order of evaluation. The evaluation order is the responsibility of the developer creating +custom directives and widgets. + + +For example, consider this piece of HTML, which uses the `ng:repeat`, `ng:init`, and `ng:bind` +widget and directives: + + +<pre> +<ul ng:init="people=['mike', 'mary']"> +<li ng:repeat="person in people" + ng:init="a=a+1" + ng:bind="person"> +</li> +</ul> +</pre> + + +Notice that the order of execution matters here. Because we want to run the `ng:init="a=a+1` and +`ng:bind="person"` once for each `person in people`, we need to execute {@link +api/angular.widget.@ng:repeat ng:repeat} to make copies of the `<li>` element before we run the +{@link api/angular.directive.ng:init ng:init}, and {@link api/angular.directive.ng:bind ng:bind} +for each of the `<li>`copies. + + +If you implemented `ng:repeat` as a directive, there would be no guarantee that the attributes +`ng:repeat`, `ng:init`, and `ng:bind` would be evaluated in the order they are declared, because +the order of element attributes in HTML is not significant to the browser. + + +So, when creating a custom HTML attribute, you will have to consider whether a directive or a +widget is more appropriate. When the order of execution doesn't matter, directives are the right +choice. In a situation where the order matters and one attribute should be processed with a higher +priority than others, use a widget for the attribute that must be processed first. + + + + +## Related Topics + + +* {@link dev_guide.compiler.directives Understanding Angular Directives} +* {@link dev_guide.compiler.widgets Understanding Angular Widgets} + + +## Related API: + + +* {@link api/angular.directive Directive API} +* {@link api/angular.widget Widget API} diff --git a/docs/content/guide/dev_guide.compiler.extending_compiler.ngdoc b/docs/content/guide/dev_guide.compiler.extending_compiler.ngdoc new file mode 100644 index 00000000..ea0a063c --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.extending_compiler.ngdoc @@ -0,0 +1,115 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Extending the Angular Compiler +@description + + +Let's say that we want to create a new DOM element called `<my:greeter/>` that displays a greeting. +We want this HTML source: + + +<pre> +<div ng:init="salutation='Hello'; name='World'"> +<my:greeter salutation="salutation" name="name"/> +</div> +</pre> + + +to produce this DOM: + + +<pre> +<div ng:init="salutation='Hello'; name='World'"> +<my:greeter salutation="salutation" name="name"/> + <span class="salutation">Hello</span> + <span class="name">World</span>! +</my:greeter> +</div> +</pre> + + +That is, the new `<my:greeter/>` tag's `salutation` and `name` attributes should be transformed by +the compiler such that two `<span>` tags display the values of the attributes, with CSS classes +applied to the output. + + +The following code snippet shows how to write a following widget definition that will be processed +by the compiler. Note that you have to declare the {@link dev_guide.bootstrap namespace} `my` in +the page: + + +<pre> +angular.widget('my:greeter', function(compileElement){ +var compiler = this; +compileElement.css('display', 'block'); +var salutationExp = compileElement.attr('salutation'); +var nameExp = compileElement.attr('name'); +return function(linkElement){ + var salutationSpan = angular.element('<span class="salutation"></span'); + var nameSpan = angular.element('<span class="name"></span>'); + linkElement.append(salutationSpan); + linkElement.append(compiler.text(' ')); + linkElement.append(nameSpan); + linkElement.append(compiler.text('!')); + this.$watch(salutationExp, function(value){ + salutationSpan.text(value); + }); + this.$watch(nameExp, function(value){ + nameSpan.text(value); + }); +}; +}); +</pre> + + +Note: For more about widgets, see {@link dev_guide.compiler.widgets Understanding Angular Widgets} +and the {@link api/angular.widget widget API reference page}. + + +# Compilation process for `<my:greeter>` + + +Here are the steps that the compiler takes in processing the page that contains the widget +definition above: + + +## Compile Phase + + +1. Recursively traverse the DOM depth-first. +2. Find the angular.widget definition. +3. Find and execute the widget's compileElement function, which includes the following steps: + 1. Add a style element with attribute display: block; to the template DOM so that the browser +knows to treat the element as block element for rendering. (Note: because this style element was +added on the template compileElement, this style is automatically applied to any clones of the +template (i.e. any repeating elements)). + 2. Extract the salutation and name HTML attributes as angular expressions. +4. Return the aggregate link function, which includes just one link function in this example. + + +## Link Phase + + +1. Execute the aggregate link function, which includes the following steps: + 1. Create a <span> element set to the salutation class + 2. Create a <span> element set to the name class. +2. Add the span elements to the linkElement. (Note: be careful not to add them to the +compileElement, because that's the template.) +3. Set up watches on the expressions. When an expression changes, copy the data to the +corresponding spans. + + + + +## Related Topics + + +* {@link dev_guide.compiler Angular HTML Compiler} +* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works} +* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element} + + +## Related API + + +* {@link api/angular.compile angular.compile()} diff --git a/docs/content/guide/dev_guide.compiler.markup.ngdoc b/docs/content/guide/dev_guide.compiler.markup.ngdoc new file mode 100644 index 00000000..64a3940b --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.markup.ngdoc @@ -0,0 +1,120 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Understanding Angular Markup +@description + + +Markup in angular is a feature that you can use in templates to transform the content of DOM +elements prior to the compile phase (in which elements are compiled and link functions are +returned. See the {@link dev_guide.compiler compiler docs} for details on how the compiler +works.) The ability to make pre-compile changes to DOM elements lets you create shorthand for +{@link api/angular.widget widget} and {@link api/angular.directive directive} declarations. + + +Angular provides one built-in markup feature: the double curly-braces used to declare binding +points (between the model and view) for angular expressions. You can also create your own custom +markup. + + +# Using Double Curly-brace Markup (`{{ }}`) + + +The double curly-brace (`{{ }}`) markup translates an enclosed expression into an {@link +api/angular.directive.ng:bind ng:bind} directive: + + +<pre> +{{expression}} +</pre> + + +is transformed to: + + +<pre> +<span ng:bind="expression"></span> +</pre> + + +Markup is useful for the simple reason that `{{1+2}}` is easier to write and understand than `<span +ng:bind="1+2"></span>`. After markup shorthand is expanded into the DOM elements it represents, the +expanded elements are then {@link dev_guide.compiler compiled} normally. + + + + +# Creating Custom Markup + + +Let's say you want to define markup that transforms `---` into a horizontal rule (`<hr/>`): + + +<pre> +header +--- +footer +</pre> + + +should translate to: +<pre> +header +<hr/> +footer +</pre> + + +Here is how you could extend the angular compiler to create the "---" markup: + + +<pre> +angular.markup('---', function(text, textNode, parentElement) { + var compiler = this; + var index = text.indexOf('---'); + if (index > -1) { + var before = compiler.text(text.substring(0, index)); + var hr = compiler.element('hr'); + var after = compiler.text(text.substring(index + 3)); + textNode.after(after); + textNode.after(hr); + textNode.after(before); + textNode.remove(); + } +}); +</pre> + + +Unlike the way the compiler processes {@link api/angular.widget widgets} and {@link +api/angular.directive directives} (matching the name of the handler function to a DOM element or +attribute name), the compiler calls every markup handler for every text node, giving the handler a +chance to transform the text. The markup handler needs to find all the matches in the text. + + +## Attribute Markup + + +Attribute markup extends the angular compiler in a very similar way to markup, except that it +allows you to modify the state of attribute text rather then the content of a node. + + +<pre> +angular.attrMarkup('extraClass', function(attrValue, attrName, element){ + if (attrName == 'additional-class') { + element.addClass(attrValue); + } +}); +</pre> + + + + +## Related Topics + + +* {@link dev_guide.compiler Angular HTML Compiler} + + +## Related API + + +* {@link api/angular.compile Compiler API Reference} diff --git a/docs/content/guide/dev_guide.compiler.ngdoc b/docs/content/guide/dev_guide.compiler.ngdoc new file mode 100644 index 00000000..08c40a56 --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.ngdoc @@ -0,0 +1,35 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler +@description + + +The core of angular is its HTML compiler. The compiler processes angular directives, widgets, and +markup 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 +apps, but you can also extend the compiler to create a domain-specific language for building +specific types of web applications. + + +All compilation takes place in the web browser; no server is involved. + + + + +## Related Topics + + +* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works} +* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler} +* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element} +* {@link dev_guide.compiler.widgets Understanding Angular Widgets} +* {@link dev_guide.compiler.directives Understanding Angular Directives} +* {@link dev_guide.compiler.markup Understanding Angular Markup} + + +## Related API + + +* {@link api/angular.compile Angular Compiler API} diff --git a/docs/content/guide/dev_guide.compiler.testing_dom_element.ngdoc b/docs/content/guide/dev_guide.compiler.testing_dom_element.ngdoc new file mode 100644 index 00000000..bd290f0d --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.testing_dom_element.ngdoc @@ -0,0 +1,25 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Testing a New DOM Element +@description + + + + +"Testing, testing, come in, over?" + + + + +## Related Topics + + +* {@link dev_guide.compiler Angular HTML Compiler} +* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works} +* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler} + + +## Related API + + +* {@link api/angular.compile angular.compile()} diff --git a/docs/content/guide/dev_guide.compiler.understanding_compiler.ngdoc b/docs/content/guide/dev_guide.compiler.understanding_compiler.ngdoc new file mode 100644 index 00000000..714ef9c0 --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.understanding_compiler.ngdoc @@ -0,0 +1,88 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Understanding How the Compiler Works +@description + + +Every {@link api/angular.widget widget}, {@link api/angular.directive directive} and {@link +dev_guide.compiler.markup markup} is defined with a compile function, which the angular compiler +executes on each widget or directive it encounters. The compile function optionally returns a link +function. This compilation process happens automatically when the page is loaded when you specify +`ng:autobind` in the script tag from which you load the angular script file. (See {@link +dev_guide.bootstrap Initializing Angular}.) + + +The compile and link functions are related as follows: + + +* **compile function** — Registers a listener for the widget, directive, or markup expression. The +compiler calls this function exactly once. +* **link function** — Sets up the listener registered by the compile function. This function can be +called multiple times, once per cloned DOM element. For example, in the case of the {@link +api/angular.widget.@ng:repeat repeater widget} used in a list element (`<li ng:repeat="[item in +dataset]"`), the link function gets called to set up a listener on each element in the list. + + +Note that angular's built-in widgets, directives, and markup have predefined compile and link +functions that you don't need to modify. When you create your own widgets, directives, or markup, +you must write compile and link functions for them. Refer to the {@link api/angular.compile +Compiler API} for details. + + +When the angular compiler compiles a page, it proceeds through 3 phases: Compile, Create Root +Scope, and Link: + + +1. Compile Phase + + + 1. Recursively traverse the DOM, depth-first. + 2. Look for a matching compile function of type widget, then markup, then directive. + 3. If a compile function is found then execute it. + 4. When the compile function completes, it should return a link function. Aggregate this link +function with all link functions returned previously by step 3. + 5. Repeat steps 3 and 4 for all compile functions found. + + +The result of the compilation phase is an aggregate link function, which comprises all of the +individual link functions. + + +2. Create Root Scope Phase + + +* Inject all services into the root scope. + + +3. Link Phase + + + 1. Execute the aggregate link function with the root scope. The aggregate link function calls +all of the individual link functions that were generated in the compile phase. + 2. If there are any clones of the DOM caused by repeating elements, call the link function +multiple times, one for each repeating item. + + +Note that while the compile function is executed exactly once, the link function can be executed +multiple times, for example, once for each iteration in a repeater. + + +The angular compiler exposes methods that you will need to make use of when writing your own +widgets and directives. For information on these methods, see the {@link api/angular.compile +Compiler API doc}. + + + + +## Related Topics + + +* {@link dev_guide.compiler Angular HTML Compiler} +* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler} +* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element} + + +## Related API + + +* {@link api/angular.compile angular.compile()} diff --git a/docs/content/guide/dev_guide.compiler.widgets.creating_widgets.ngdoc b/docs/content/guide/dev_guide.compiler.widgets.creating_widgets.ngdoc new file mode 100644 index 00000000..15ac368c --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.widgets.creating_widgets.ngdoc @@ -0,0 +1,116 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Widgets: Creating Custom Widgets +@description + + +When you create your own widgets, you must set up your own namespace for them. (See +dev_guide.bootstrap Initializing Angular} for information about namespaces in angular.) + + +Let's say we would like to create a new element type in the namespace `my` that can watch an +expression and `alert()` the user with each new value: + + +<pre> +// An element widget +<my:watch exp="name"/> +</pre> + + +You can implement `my:watch` like this: + + +<pre> +angular.widget('my:watch', function(compileElement) { + var compiler = this; + var exp = compileElement.attr('exp'); + return function(linkElement) { + var currentScope = this; + currentScope.$watch(exp, function(value){ + alert(value); + }); + }; +}); +</pre> + + + + +# Creating a Custom Attribute Widget + + +Let's implement the same widget as in the example in Defining an Element Widget, but this time as +an attribute that can be added to any existing DOM element: + + +<pre> +// An attribute widget (my-watch) in a div tag +<div my-watch="name">text</div> +</pre> +You can implement `my:watch` attribute like this: +<pre> +angular.widget('@my:watch', function(expression, compileElement) { +var compiler = this; +return function(linkElement) { +var currentScope = this; +currentScope.$watch(expression, function(value){ + alert(value); +}); +}; +}); +</pre> + + + + +# Live Example of a Custom Element Widget + + +<doc:example> +<doc:source> +<script> +angular.widget('my:time', function(compileElement){ + compileElement.css('display', 'block'); + return function(linkElement){ + function update(){ + linkElement.text('Current time is: ' + new Date()); + setTimeout(update, 1000); + } + update(); + }; +}); +</script> +<my:time></my:time> +</doc:source> +<doc:scenario> +</doc:scenario> +</doc:example> + + + + +# Additional Compiler Methods for Custom Widgets + + +The angular compiler exposes methods that you may need to use of when writing your own widgets and +directives. For example, the `descend()` method lets you control whether the compiler ignores or +processes child elements of the element it is compiling. For information on this and other +compiler methods, see the {@link api/angular.compile Compiler API doc}. + + + + +## Related Topics + + +* {@link dev_guide.compiler Angular HTML Compiler} +* {@link dev_guide.compiler.directives Angular Directives} +* {@link dev_guide.compiler.widgets Angular Widgets} +* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives} + + +## Related API + + +* {@link api/angular.compile Compiler API} diff --git a/docs/content/guide/dev_guide.compiler.widgets.ngdoc b/docs/content/guide/dev_guide.compiler.widgets.ngdoc new file mode 100644 index 00000000..dbe082a6 --- /dev/null +++ b/docs/content/guide/dev_guide.compiler.widgets.ngdoc @@ -0,0 +1,47 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular HTML Compiler: Understanding Angular Widgets +@description + + +Widgets are DOM elements that the browser doesn't already understand. Angular provides some +built-in widgets (such as {@link api/angular.widget.@ng:repeat ng:repeat}), and you can create your +own custom widgets. + + +Widgets are intended to manipulate the DOM tree by adding new elements (unlike {@link +dev_guide.compiler.directives angular directives}, which are intended to modify only element +properties). + + +Widgets come in two types: + + +* Element Widget — A custom DOM element. An example of a custom element is shown in {@link +dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}. + + +* Attribute Widget — A custom attribute on an existing DOM element. An attribute widget is similar +to an angular directive, with the main difference being that an attribute widget will always be +processed before any directives that are specified on the same element. Only one attribute widget +is allowed per element. An example of an attribute widget is shown in {@link +dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}. + + + + + + +## Related Topics + + +* {@link dev_guide.compiler Angular HTML Compiler} +* {@link dev_guide.compiler.directives Angular Directives} +* {@link dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets} +* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives} + + +## Related API + + +* {@link api/angular.compile Compiler API} diff --git a/docs/content/guide/dev_guide.di.ngdoc b/docs/content/guide/dev_guide.di.ngdoc new file mode 100644 index 00000000..a2352cc3 --- /dev/null +++ b/docs/content/guide/dev_guide.di.ngdoc @@ -0,0 +1,43 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: About Dependency Injection (DI) +@description + + +Dependency Injection (DI) is an object-oriented software design pattern that supports the +decoupling and dependency management of application components. + + +The idea behind DI is to decouple each component from all of the other components that it depends +on to do its particular job. The way this is done in DI is by moving the responsibility for +managing dependencies out of each individual component and into a provider component. The provider +(or injector) component manages the life cycles and dependencies for all of the other components in +an application. + + +Angular has a built-in dependency management subsystem that helps to make your applications easier +to develop, understand, and test. + + +For more information on DI in general, see {@link http://en.wikipedia.org/wiki/Dependency_injection +Dependency Injection} at Wikipedia, and {@link http://martinfowler.com/articles/injection.html +Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern +book. + + + + +## Related Topics + + +* {@link dev_guide.di.understanding_di Understanding DI in Angular} +* {@link dev_guide.services Angular Services} + + + + +## Related API + + +* {@link api/angular.service Service API} +* {@link api/angular.injector Angular Injector API} diff --git a/docs/content/guide/dev_guide.di.understanding_di.ngdoc b/docs/content/guide/dev_guide.di.understanding_di.ngdoc new file mode 100644 index 00000000..1b131eaf --- /dev/null +++ b/docs/content/guide/dev_guide.di.understanding_di.ngdoc @@ -0,0 +1,141 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: DI: Understanding DI in Angular +@description + + + + +While DI is widely used in statically typed languages such as Java or C++, it has not been widely +used in JavaScript. Angular brings the benefits of DI into JavaScript apps. + + +In angular, DI is implemented as a subsystem that manages dependencies between services, +controllers, widgets, and filters. The most important of these are {@link api/angular.service +services}. + + +Services are objects that handle common tasks in web applications. Angular provides several{@link +api/angular.service built-in services}, and you can create your own custom services. + + +The main job of angular's DI subsystem is to provide services to angular components that depend on +them. The way the DI subsystem provides services is as follows: all services are registered with +angular's {@link api/angular.service service API}, and all components that depend on services +define those dependencies as a property (`$inject`). With this information, the DI subsystem +manages the creation of service objects and the provision of those objects to the components that +need them, at the time they need them. The following illustration steps through the sequence of +events: + + +<img src="img/guide/di_sequence_final.png"> + + +In the illustration above, the dependency injection sequence proceeds as follows: + + +1. Service factory functions are registered with angular's service factory repository. +2. `ng:autobind` triggers angular's bootstrap sequence, during which angular compiles the template, +creates the root scope, and creates the dependency injector. +3. The `ng:controller` directive implicitly creates a new child scope, augmented by the application +of the `PhoneListCtrl` controller function. +4. The Injector identifies the `$xhr` service as `PhoneListCtrl` controller's only dependency. +5. The Injector checks if the `$xhr` service has already been instantiated, and if not uses the +factory function from the service factory repository to construct it. +6. DI provides the instance of $xhr service to the PhoneListCtrl controller constructor + + + + +## How Scope Relates to DI + + +The {@link api/angular.injector injector} is responsible for resolving the service dependencies in +the application. It gets created and configured with the creation of a root scope. The injector +caches instances of services, with the services cache bound to the root scope. + + +Different root scopes have different instances of the injector. While typical angular applications +will only have one root scope (and hence the services will act like application singletons), in +tests it is important to not share singletons across test invocations for isolation reasons. We +achieve the necessary isolation by having each test create its own separate root scope. + + +<pre> +// create a root scope +var rootScope = angular.scope(); +// access the service locator +var myService = rootScope.$service('myService'); +</pre> + + +## Inferring dependencies from the signature of the factory function or constructor + + +**EXPERIMENTAL FEATURE**: This is an experimental feature. See the important note at the end of +this section for drawbacks. + + +We resort to `$inject` and our own annotation because there is no way in JavaScript to get a list +of arguments. Or is there? It turns out that calling `.toString()` on a function returns the +function declaration along with the argument names as shown below: + + +<pre> +function myFn(a,b){} +expect(myFn.toString()).toEqual('function myFn(a,b){}'); +</pre> + + +This means that angular can infer the function names after all and use that information to generate +the `$inject` annotation automatically. Therefore the following two function definitions are +equivalent: + + +<pre> +// given a user defined service +angular.service('serviceA', ...); + + +// inject '$window', 'serviceA', curry 'name'; +function fnA($window, serviceA, name){}; +fnA.$inject = ['$window', 'serviceA']; + + +// inject '$window', 'serviceA', curry 'name'; +function fnB($window, serviceA_, name){}; +// implies: fnB.$inject = ['$window', 'serviceA']; +</pre> + + +If angular does not find a `$inject` annotation on the function, then it calls the `.toString()` +method and tries to infer what should be injected using the following rules: + + +* Any argument starting with `$` is an angular service and will be added to the `$inject` property +array +* Any argument ending with `_` will be added to the `$inject` property array (angular strips the +`_`) +* All arguments following an argument which has neither `$` nor `_` , must not have `$` nor `_` +(these are free arguments for {@link http://en.wikipedia.org/wiki/Currying currying}) + + +**IMPORTANT** +Minifiers/obfuscators change the names of function arguments and will therefore break the `$inject` +inference. For this reason, either explicitly declare the `$inject` or do not use +minifiers/obfuscators. In the future, we may provide a pre-processor which will scan the source +code and insert the `$inject` into the source code so that it can be minified/obfuscated. + + + + +## Related Topics + + +* {@link dev_guide.services Angular Services} + + +## Related API + + +* {@link api/angular.service Services API} diff --git a/docs/content/guide/dev_guide.di.using_di_controllers.ngdoc b/docs/content/guide/dev_guide.di.using_di_controllers.ngdoc new file mode 100644 index 00000000..ea1cb965 --- /dev/null +++ b/docs/content/guide/dev_guide.di.using_di_controllers.ngdoc @@ -0,0 +1,66 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: DI: Using DI in Controllers +@description + + +The most common place to use dependency injection in angular applications is in {@link +dev_guide.mvc.understanding_controller controllers}. Here is a simple example: + + +<pre> +function MyController($route){ + // configure the route service + $route.when(...); +} +MyController.$inject = ['$route']; +</pre> + + +In this example, the `MyController` constructor function takes one argument, the {@link +api/angular.service.$route $route} service. Angular is then responsible for supplying the instance +of `$route` to the controller when the constructor is instantiated. There are two ways to cause +controller instantiation – by configuring routes with the `$route` service, or by referencing the +controller from the HTML template, as follows: + + +<pre> +<!doctype html> +<html xmlns:ng="http://angularjs.org" ng:controller="MyController"> +<script src="http://code.angularjs.org/angular.min.js" ng:autobind></script> +<body> + ... +</body> +</html> +</pre> + + +When angular is instantiating your controller, it needs to know what services, if any, should be +injected (passed in as arguments) into the controller. Since there is no reflection in JavaScript, +we have to supply this information to angular in the form of an additional property on the +controller constructor function called `$inject`. Think of it as annotations for JavaScript. + + +<pre> +MyController.$inject = ['$route']; +</pre> + + +The information in `$inject` is then used by the {@link api/angular.injector injector} to call the +function with the correct arguments. + + + + +## Related Topics + + +* {@link dev_guide.di About Dependency Injection} +* {@link dev_guide.di.understanding_di Understanding Dependency Injection in Angular} +* {@link dev_guide.services Angular Services} + + +## Related API + + +* {@link api/angular.injector Angular Injector API} diff --git a/docs/content/guide/dev_guide.expressions.ngdoc b/docs/content/guide/dev_guide.expressions.ngdoc new file mode 100644 index 00000000..b0a268e6 --- /dev/null +++ b/docs/content/guide/dev_guide.expressions.ngdoc @@ -0,0 +1,270 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Understanding Angular Expressions +@description + + +Expressions are {@link dev_guide.templates.databinding bindings} that you write in HTML and embed +in templates in order to create views in angular. Angular expressions are similar but not +equivalent to JavaScript expressions. + + +For example, these are all valid expressions in angular: + + +* `1+2={{1+2}}` +* `3*10|currency` +* `Hello {{name}}!` +* `Hello {{'World'}}!` + + + + +## Angular Expressions vs. JS Expressions + + +It might be tempting to think of angular view expressions as JavaScript expressions, but that is +not entirely correct. Angular does not use a simple JavaScript eval of the expression text. You can +think of angular expressions as JavaScript expressions with these differences: + + +* **Attribute Evaluation:** evaluation of all attributes are against the current scope, not to the +global window as in JavaScript. +* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript. +* **No Control Flow Statements:** you cannot do the following from an angular expression: +conditionals, loops, or throw. +* **Type Augmentation:** the scope expression evaluator augments built-in types. +* **Filters:** you can add filters to an expression, for example to convert raw data into a +human-readable format. +* **The $:** angular reserves this prefix to differentiate its API names from others. + + +If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a +controller method and call that. If you want to `eval()` an angular expression from JavaScript, use +the `Scope:$eval()` method. + + +## Example +<doc:example> +<doc:source> + 1+2={{1+2}} +</doc:source> +<doc:scenario> + it('should calculate expression in binding', function(){ + expect(binding('1+2')).toEqual('3'); + }); +</doc:scenario> +</doc:example> + + +You can try evaluating different expressions here: + + +<doc:example> +<doc:source> + <div ng:init="exprs=[]" class="expressions"> + Expression: + <input type='text' name="expr" value="3*10|currency" size="80"/> + <button ng:click="exprs.$add(expr)">Evaluate</button> + <ul> + <li ng:repeat="expr in exprs"> + [ <a href="" ng:click="exprs.$remove(expr)">X</a> ] + <tt>{{expr}}</tt> => <span ng:bind="$parent.$eval(expr)"></span> + </li> + </ul> + </div> +</doc:source> +<doc:scenario> + it('should allow user expression testing', function(){ + element('.expressions :button').click(); + var li = using('.expressions ul').repeater('li'); + expect(li.count()).toBe(1); + expect(li.row(0)).toEqual(["3*10|currency", "$30.00"]); + }); +</doc:scenario> +</doc:example> + + + + +# Attribute Evaluation + + +Evaluation of all attributes takes place against the current scope. Unlike JavaScript, where names +default to global window properties, angular expressions have to use `$window` to refer to the +global object. For example, if you want to call `alert()`, which is defined on `window`, an +expression must use `$window.alert()`. This is done intentionally to prevent accidental access to +the global state (a common source of subtle bugs). + + +<doc:example> +<doc:source> + <div class="example2" ng:init="$window = $service('$window')"> + Name: <input name="name" type="text" value="World"/> + <button ng:click="($window.mockWindow || $window).alert('Hello ' + name)">Greet</button> + </div> +</doc:source> +<doc:scenario> + it('should calculate expression in binding', function(){ + var alertText; + this.addFutureAction('set mock', function($window, $document, done) { + $window.mockWindow = { + alert: function(text){ alertText = text; } + }; + done(); + }); + element(':button:contains(Greet)').click(); + expect(this.addFuture('alert text', function(done) { + done(null, alertText); + })).toBe('Hello World'); + }); +</doc:scenario> +</doc:example> + + +## Forgiving + + +Expression evaluation is forgiving to undefined and null. In JavaScript, evaluating `a.b.c` throws +an exception if `a` is not an object. While this makes sense for a general purpose language, the +expression evaluations are primarily used for data binding, which often look like this: + + + {{a.b.c}} + + +It makes more sense to show nothing than to throw an exception if `a` is undefined (perhaps we are +waiting for the server response, and it will become defined soon). If expression evaluation wasn't +forgiving we'd have to write bindings that clutter the code, for example: `{{((a||{}).b||{}).c}}` + + +Similarly, invoking a function `a.b.c()` on undefined or null simply returns undefined. + + +Assignments work the same way in reverse: + + + a.b.c = 10 + + +...creates the intermediary objects even if a is undefined. + + + + +## No Control Flow Statements + + +You cannot write a control flow statement in an expression. The reason behind this is core to the +angular philosophy that application logic should be in controllers, not in the view. If you need a +conditional (including ternary operators), loop, or to throw from a view expression, delegate to a +JavaScript method instead. + + + + +## Type Augmentation + + +Built-in types have methods like `[].push()`, but the richness of these methods is limited. +Consider the example below, which allows you to do a simple search over a canned set of contacts. +The example would be much more complicated if we did not have the `Array:$filter()`. There is no +built-in method on `Array` called {@link api/angular.array.filter $filter} and angular doesn't add +it to `Array.prototype` because that could collide with other JavaScript frameworks. + + +For this reason the scope expression evaluator augments the built-in types to make them act like +they have extra methods. The actual method for `$filter()` is `angular.Array.filter()`. You can +call it from JavaScript. + + +Extensions: You can further extend the expression vocabulary by adding new methods to +`angular.Array` or `angular.String`, etc. + + +<doc:example> +<doc:source> + <div ng:init="friends = [ + {name:'John', phone:'555-1212'}, + {name:'Mary', phone:'555-9876'}, + {name:'Mike', phone:'555-4321'}, + {name:'Adam', phone:'555-5678'}, + {name:'Julie', phone:'555-8765'}]"></div> + Search: <input name="searchText"/> + <table class="example3"> + <tr><th>Name</th><th>Phone</th><tr> + <tr ng:repeat="friend in friends.$filter(searchText)"> + <td>{{friend.name}}</td> + <td>{{friend.phone}}</td> + </tr> + </table> +</doc:source> +<doc:scenario> + it('should filter the list', function(){ + var tr = using('table.example3').repeater('tr.ng-attr-widget'); + expect(tr.count()).toBe(5); + input('searchText').enter('a'); + expect(tr.count()).toBe(2); + + + }); +</doc:scenario> +</doc:example> + + +## Filters + + +When presenting data to the user, you might need to convert the data from its raw format to a +user-friendly format. For example, you might have a data object that needs to be formatted +according to the locale before displaying it to the user. You can pass expressions through a chain +of filters like this: + + + name | uppercase + + +The expression evaluator simply passes the value of name to angular.filter.uppercase. + + +Chain filters using this syntax: + + + value | filter1 | filter2 + + +You can also pass colon-delimited arguments to filters, for example, to display the number 123 with +2 decimal points: + + + 123 | number:2 + + +# The $ + + +You might be wondering, what is the significance of the $ prefix? It is simply a prefix that +angular uses, to differentiate its API names from others. If angular didn't use $, then evaluating +`a.length()` would return undefined because neither a nor angular define such a property. + + +Consider that in a future version of angular we might choose to add a length method, in which case +the behavior of the expression would change. Worse yet, you the developer could create a length +property and then we would have a collision. This problem exists because angular augments existing +objects with additional behavior. By prefixing its additions with $ we are reserving our namespace +so that angular developers and developers who use angular can develop in harmony without collisions. + + + + +## Related Topics + + +* {@link dev_guide.compiler.markup Understanding Angular Markup} +* {@link dev_guide.templates.filters Understanding Angular Filters} + + +## Related API + + +* {@link api/angular.compile Angular Compiler API} diff --git a/docs/content/guide/dev_guide.introduction.ngdoc b/docs/content/guide/dev_guide.introduction.ngdoc new file mode 100644 index 00000000..0a41cc9b --- /dev/null +++ b/docs/content/guide/dev_guide.introduction.ngdoc @@ -0,0 +1,53 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Introduction +@description + + +Angular is pure client-side technology, written entirely in JavaScript. It works with the +long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of web +apps easier and faster than ever before. + + +One important way that angular simplifies web development is by increasing the level of abstraction +between the developer and most low-level web app development tasks. Angular automatically takes +care of many of these tasks, including: + + +* DOM Manipulation +* Setting Up Listeners and Notifiers +* Input Validation + + +Because angular handles much of the work involved in these tasks, developers can concentrate more +on application logic and less on repetitive, error-prone, lower-level coding. + + +At the same time that angular simplifies the development of web apps, it brings relatively +sophisticated techniques to the client-side, including: + + +* Separation of data, application logic, and presentation components +* Data Binding between data and presentation components +* Services (common web app operations, implemented as substitutable objects) +* Dependency Injection (used primarily for wiring together services) +* An extensible HTML compiler (written entirely in JavaScript) +* Ease of Testing + + +These techniques have been for the most part absent from the client-side for far too long. + + +## Single-page / Round-trip Applications + + +You can use angular to develop both single-page and round-trip apps, but angular is designed +primarily for developing single-page apps. Angular supports browser history, forward and back +buttons, and bookmarking in single-page apps. + + +You normally wouldn't want to load angular with every page change, as would be the case with using +angular in a round-trip app. However, it would make sense to do so if you were adding a subset of +angular's features (for example, templates to leverage angular's data-binding feature) to an +existing round-trip app. You might follow this course of action if you were migrating an older app +to a single-page angular app. diff --git a/docs/content/guide/dev_guide.mvc.ngdoc b/docs/content/guide/dev_guide.mvc.ngdoc new file mode 100644 index 00000000..93ad63f5 --- /dev/null +++ b/docs/content/guide/dev_guide.mvc.ngdoc @@ -0,0 +1,33 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: About MVC in Angular +@description + + +While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it +first appeared, angular incorporates the basic principles behind the original {@link +http://en.wikipedia.org/wiki/Model–view–controller MVC} software design pattern into its way of +building client-side web applications. + + +The MVC pattern greatly summarized: + + +* Separate applications into distinct presentation, data, and logic components +* Encourage loose coupling between these components + + +Along with {@link dev_guide.services services} and {@link dev_guide.di dependency injection}, MVC +makes angular applications better structured, easier to maintain and more testable. + + +The following topics explain how angular incorporates the MVC pattern into the angular way of +developing web applications: + + +* {@link dev_guide.mvc.understanding_model Understanding the Model Component} +* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component} +* {@link dev_guide.mvc.understanding_view Understanding the View Component} + + + diff --git a/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc b/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc new file mode 100644 index 00000000..18e74edc --- /dev/null +++ b/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc @@ -0,0 +1,323 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: About MVC in Angular: Understanding the Controller Component +@description + + +In angular, a controller is a JavaScript function (type/class) that is used to augment instances of +angular {@link dev_guide.scopes Scope}, excluding the root scope. When you or angular create a new +child scope object via the {@link api/angular.scope.$new scope.$new} API , there is an +option to pass in a controller as a method argument. This will tell angular to associate the +controller with the new scope and to augment its behavior. + + +Use controllers to: + + +- Set up the initial state of a scope object. +- Add behavior to the scope object. + + +# Setting up the initial state of a scope object + + +Typically, when you create an application you need to set up an initial state for an angular scope. + + +Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function +to a new angular scope object, which sets up an initial scope state. This means that angular never +creates instances of the controller type (by invoking the `new` operator on the controller +constructor). Constructors are always applied to an existing scope object. + + +You set up the initial state of a scope by creating model properties. For example: + + +function GreetingCtrl() { + this.greeting = 'Hola!'; +} + + +The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template. + + +When a controller function is applied to an angular scope object, the `this` of the controller +function becomes the scope of the angular scope object, so any assignment to `this` within the +controller function happens on the angular scope object. + + +# Adding Behavior to a Scope Object + + +Behavior on an angular scope object is in the form of scope method properties available to the +template/view. This behavior interacts with and modifies the application model. + + +As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any +objects (or primitives) assigned to the scope become model properties. Any functions assigned to +the scope, along with any prototype methods of the controller type, become functions available in +the template/view, and can be invoked via angular expressions and `ng:` event handlers (e.g. {@link +api/angular.directive.ng:click ng:click}). These controller methods are always evaluated within the +context of the angular scope object that the controller function was applied to (which means that +the `this` keyword of any controller method is always bound to the scope that the controller +augments). This is how the second task of adding behavior to the scope is accomplished. + + + + +# Using Controllers Correctly + + +In general, a controller shouldn't try to do too much. It should contain only the business logic +needed for a single view. + + +The most common way to keep controllers slim is by encapsulating work that doesn't belong to +controllers into services and then using these services in controllers via dependency injection. +This is discussed in the {@link dev_guide.di Dependency Injection} {@link dev_guide.services +Services} sections of this guide. + + +Do not use controllers for: + + +- Any kind of DOM manipulation — Controllers should contain only business logic. DOM +manipulation—the presentation logic of an application—is well known for being hard to test. +Putting any presentation logic into controllers significantly affects testability of the business +logic. Angular offers {@link dev_guide.templates.databinding} for automatic DOM manipulation. If +you have to perform your own manual DOM manipulation, encapsulate the presentation logic in {@link +dev_guide.compiler.widgets widgets} and {@link dev_guide.compiler.directives directives}. +- Input formatting — Use {@link dev_guide.templates.formatters angular formatters} instead. +- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead. +- Run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular +services} instead. +- Instantiate or manage the life-cycle of other components (for example, to create service +instances). + + + + +# Associating Controllers with Angular Scope Objects + + +You can associate controllers with scope objects explicitly via the {@link api/angular.scope.$new +scope.$new} api or implicitly via the {@link api/angular.directive.@ng:controller ng:controller +directive} or {@link api/angular.service.$route $route service}. + + + + +## Controller Constructor and Methods Example + + +To illustrate how the controller component works in angular, let's create a little app with the +following components: + + +- A {@link dev_guide.templates template} with two buttons and a simple message +- A model consisting of a string named `spice` +- A controller with two functions that set the value of `spice` + + +The message in our template contains a binding to the `spice` model, which by default is set to the +string "very". Depending on which button is clicked, the `spice` model is set to `chili` or +`jalapeño`, and the message is automatically updated by data-binding. + + + + +## A Spicy Controller Example + + +<pre> +<body ng:controller="SpicyCtrl"> + <button ng:click="chiliSpicy()">Chili</button> + <button ng:click="jalapenoSpicy()">Jalapeño</button> + <p>The food is {{spice}} spicy!</p> +</body> + + +function SpicyCtrl() { + this.spice = 'very'; + this.chiliSpicy = function() { + this.spice = 'chili'; + } +} + + +SpicyCtrl.prototype.jalapenoSpicy = function() { + this.spice = 'jalapeño'; +} +</pre> + + +Things to notice in the example above: + + +- The `ng:controller` directive is used to (implicitly) create a scope for our template, and the +scope is augmented (managed) by the `SpicyCtrl` controller. +- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name +starts with capital letter and ends with "Ctrl" or "Controller". +- The JavaScript keyword `this` in the `SpicyCtrl` function is bound to the scope that the +controller augments. +- Assigning a property to `this` creates or updates the model. +- Controller methods can be created through direct assignment to scope (the `chiliSpicy` method) or +as prototype methods of the controller constructor function (the `jalapenoSpicy` method) +- Both controller methods are available in the template (for the `body` element and and its +children). + + +Controller methods can also take arguments, as demonstrated in the following variation of the +previous example. + + +## Controller Method Arguments Example + + +<pre> +<body ng:controller="SpicyCtrl"> + <input name="customSpice" value="wasabi"> + <button ng:click="spicy('chili')">Chili</button> + <button ng:click="spicy(customSpice)">Custom spice</button> + <p>The food is {{spice}} spicy!</p> +</body> + + +function SpicyCtrl() { + this.spice = 'very'; + this.spicy = function(spice) { + this.spice = spice; + } +} +</pre> + + +Notice that the `SpicyCtrl` controller now defines just one method called `spicy`, which takes one +argument called `spice`. The template then refers to this controller method and passes in a string +constant `'chili'` in the binding for the first button and a model property `spice` (bound to an +input box) in the second button. + + + + +## Controller Inheritance Example + + +Controller inheritance in angular is based on {@link api/angular.scope Scope} inheritance. Let's +have a look at an example: + + +<pre> +<body ng:controller="MainCtrl"> + <p>Good {{timeOfDay}}, {{name}}!</p> + <div ng:controller="ChildCtrl"> + <p>Good {{timeOfDay}}, {{name}}!</p> + <p ng:controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p> +</body> + + +function MainCtrl() { + this.timeOfDay = 'morning'; + this.name = 'Nikki'; +} + + +function ChildCtrl() { + this.name = 'Mattie'; +} + + +function BabyCtrl() { + this.timeOfDay = 'evening'; + this.name = 'Gingerbreak Baby'; +} +</pre> + + +Notice how we nested three `ng:controller` directives in our template. This template construct will +result in 4 scopes being created for our view: + + +- The root scope +- The `MainCtrl` scope, which contains `timeOfDay` and `name` models +- The `ChildCtrl` scope, which shadows the `name` model from the previous scope and inherits the +`timeOfDay` model +- The `BabyCtrl` scope, which shadows both the `timeOfDay` model defined in `MainCtrl` and `name` +model defined in the ChildCtrl + + +Inheritance works between controllers in the same way as it does with models. So in our previous +examples, all of the models could be replaced with controller methods that return string values. + + +Note: Standard prototypical inheritance between two controllers doesn't work as one might expect, +because as we mentioned earlier, controllers are not instantiated directly by angular, but rather +are applied to the scope object. + + + + +## Testing Controllers + + +The way to test a controller depends upon how complicated the controller is. + + +- If your controller doesn't use DI or scope methods — create the controller with the `new` +operator and test away. For example: + + +Controller Function: +<pre> +function myController() { + this.spices = [{"name":"pasilla", "spiciness":"mild"}, + {"name":"jalapeno", "spiceiness":"hot hot hot!"}, + {"name":"habanero", "spiceness":"LAVA HOT!!"}]; + + + this.spice = "habanero"; +} +</pre> + + +Controller Test: +<pre> +describe('myController function', function() { + + + describe('myController', function(){ + var ctrl; + + + beforeEach(function() { + ctrl = new myController(); + }); + + + it('should create "spices" model with 3 spices', function() { + expect(ctrl.spices.length).toBe(3); + }); + + + it('should set the default value of spice', function() { + expect(ctrl.spice).toBe('habanero'); + }); + }); +}); +</pre> + + +- If your controller does use DI or scope methods — create a root scope, then create the controller +in the root scope with `scope.$new(MyController)`. Test the controller using `$eval`, if necessary. +- If you need to test a nested controller that depends on its parent's state — create a root scope, +create a parent scope, create a child scope, and test the controller using $eval if necessary. + + + + +## Related Topics + + +* {@link dev_guide.mvc About MVC in Angular} +* {@link dev_guide.mvc.understanding_model Understanding the Model Component} +* {@link dev_guide.mvc.understanding_view Understanding the View Component} diff --git a/docs/content/guide/dev_guide.mvc.understanding_model.ngdoc b/docs/content/guide/dev_guide.mvc.understanding_model.ngdoc new file mode 100644 index 00000000..15d8bcb2 --- /dev/null +++ b/docs/content/guide/dev_guide.mvc.understanding_model.ngdoc @@ -0,0 +1,96 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: About MVC in Angular: Understanding the Model Component +@description + + +Depending on the context of the discussion in angular documentation, the term _model_ can refer to +either a single object representing one entity (for example, a model called "phones" with its value +being an array of phones) or the entire data model for the application (all entities). + + +In angular, a model is any data that is reachable as a property of an angular {@link +dev_guide.scopes Scope} object. The name of the property is the model identifier and the value is +any JavaScript object (including arrays and primitives). + + +The only requirement for a JavaScript object to be a model in angular is that the object must be +referenced by an angular scope as a property of that scope object. This property reference can be +created explicitly or implicitly. + + +You can create models by explicitly creating scope properties referencing JavaScript objects in the +following ways: + + +* Make a direct property assignment to the scope object in JavaScript code; this most commonly +occurs in controllers: + + + function MyCtrl() { + // create property 'foo' on the MyCtrl's scope + // and assign it an initial value 'bar' + this.foo = 'bar'; + } + + +* Use an {@link dev_guide.expressions angular expression} with an assignment operator in templates: + + + <button ng:click="{{foos='ball'}}">Click me</button> + + +* Use {@link api/angular.directive.ng:init ng:init directive} in templates (for toy/example apps +only, not recommended for real applications): + + + <body ng:init=" foo = 'bar' "> + + +Angular creates models implicitly (by creating a scope property and assigning it a suitable value) +when processing the following template constructs: + + +* Form input, select, and textarea elements: + + + <input name="query" value="fluffy cloud"> + + The code above creates a model called "query" on the current scope with the value set to "fluffy +cloud". + + +* An iterator declaration in {@link api/angular.widget.@ng:repeat ng:repeater}: + + + <p ng:repeat="phone in phones"></p> + + + The code above creates one child scope for each item in the "phones" array and creates a "phone" +object (model) on each of these scopes with its value set to the value of "phone" in the array. + + +In angular, a JavaScript object stops being a model when: + + +* No angular scope contains a property that references the object. + + +* All angular scopes that contain a property referencing the object become stale and eligible for +garbage collection. + + +The following illustration shows a simple data model created implicitly from a simple template: + + +<img src="img/guide/about_model_final.png"> + + + + +## Related Topics + + +* {@link dev_guide.mvc About MVC in Angular} +* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component} +* {@link dev_guide.mvc.understanding_view Understanding the View Component} diff --git a/docs/content/guide/dev_guide.mvc.understanding_view.ngdoc b/docs/content/guide/dev_guide.mvc.understanding_view.ngdoc new file mode 100644 index 00000000..ff202688 --- /dev/null +++ b/docs/content/guide/dev_guide.mvc.understanding_view.ngdoc @@ -0,0 +1,29 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: About MVC in Angular: Understanding the View Component +@description + + +In angular, the view is the DOM loaded and rendered in the browser, after angular has transformed +the DOM based on information in the template, controller and model. + + +<img src="img/guide/about_view_final.png"> + + +In the angular implementation of MVC, the view has knowledge of both the model and the controller. +The view knows about the model where two-way data-binding occurs. The view has knowledge of the +controller through angular directives, such as {@link api/angular.directive.@ng:controller +ng:controller} and {@link api/angular.widget.ng:view ng:view}, and through bindings of this form: +`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated +controller function. + + + + +## Related Topics + + +* {@link dev_guide.mvc About MVC in Angular} +* {@link dev_guide.mvc.understanding_model Understanding the Model Component} +* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component} diff --git a/docs/content/guide/dev_guide.overview.ngdoc b/docs/content/guide/dev_guide.overview.ngdoc new file mode 100644 index 00000000..7eb56470 --- /dev/null +++ b/docs/content/guide/dev_guide.overview.ngdoc @@ -0,0 +1,288 @@ +@ngdoc overview +@name Developer Guide: Overview +@description + + + + +# What Is Angular? + + +The short answer: angular is a new, powerful, client-side technology that makes it much easier for +you to create dynamic web sites and complex web apps, all without leaving the comfort of your HTML +/ JavaScript home. + + +The long answer: it depends on where you're coming from... + + +* If you're a web designer, you might perceive angular to be a sweet {@link dev_guide.templates +templating} system, that doesn't get in your way and provides you with lots of nice built-ins that +make it easier to do what you want to do. + + +* If you're a web developer, you might be thrilled that angular functions as an excellent web +framework, one that assists you all the way through the development cycle. + + +* If you want to go deeper, you can immerse yourself in angular's extensible HTML {@link +dev_guide.compiler compiler} that runs in your browser. The angular compiler teaches your browser +new tricks. + + +Angular is not just a templating system, but you can create fantastic templates with it. Angular is +not just a web framework, but it features a very nice framework. Angular is not just an extensible +HTML compiler, but the compiler is at the core of Angular. Angular includes all of these +components, along with others. Angular is far greater than the sum of its parts. It is a new, +better way to develop web applications! + + + + +## An Introductory Angular Example + + +Let's say that you are a web designer, and you've spent many thous — erm, hundreds of hours +designing web sites. But at this point, the thought of manipulating the DOM, writing listeners and +input validators, all just to implement a simple form? No. You either don't want to go there in +the first place or you've been there and the thrill is gone. + + +So look over the following simple example written using angular. Note that it features only the +templating aspect of angular, but this should suffice for now to quickly demonstrate how much +easier a web developer's life can if they're using angular: + + +<doc:example> +<doc:source> + <b>Invoice:</b> + <br/> + <br/> + <table> + <tr><td> </td><td> </td> + <tr><td>Quantity</td><td>Cost</td></tr> + <tr> + <td><input name="qty" value="1" +ng:validate="integer:0" +ng:required/></td> + <td><input name="cost" value="19.95" +ng:validate="number" +ng:required/></td> + </tr> + </table> + <hr> + <b>Total:</b> {{qty * cost | currency}} +</doc:source> +<!-- +<doc:scenario> + it('should show of angular binding', function(){ + expect(binding('qty * cost')).toEqual('$19.95'); + input('qty').enter('2'); + input('cost').enter('5.00'); + expect(binding('qty * cost')).toEqual('$10.00'); + }); +</doc:scenario> +--> +</doc:example> + + +Try out the Live Preview above, and then let's walk through the example and describe what's going +on. + + +In the `<html>` tag, we add an attribute to let the browser know about the angular namespace: + + + <html xmlns:ng="http://angularjs.org"> + + +This ensures angular runs nicely in all major browsers. + + +In the `<script>` tag we do two angular setup tasks: + + +1. We load `angular.js`. +2. The angular {@link api/angular.directive.ng:autobind ng:autobind} directive tells angular to +{@link dev_guide.compiler compile} and manage the whole HTML document. + + + `<script src="http://code.angularjs.org/0.9.15/angular-0.9.15.min.js" + ng:autobind></script>` + + +From the `name` attribute of the `<input>` tags, angular automatically sets up two-way data +binding, and we also demonstrate some easy input validation: + + + Quantity: <input name="qty" value="1" ng:validate="integer:0" ng:required/> + Cost: <input name="cost" value="199.95" ng:validate="number" ng:required/> + + +These input widgets look normal enough, but consider these points: + + +* When this page loaded, angular bound the names of the input widgets (`qty` and `cost`) to +variables of the same name. Think of those variables as the "Model" component of the +Model-View-Controller design pattern. +* Note the angular directives, {@link api/angular.widget.@ng:validate ng:validate} and {@link +api/angular.widget.@ng:required ng:required}. You may have noticed that when you enter invalid data +or leave the the input fields blank, the borders turn red color, and the display value disappears. +These `ng:` directives make it easier to implement field validators than coding them in JavaScript, +no? Yes. + + +And finally, the mysterious `{{ double curly braces }}`: + + + Total: {{qty * cost | currency}} + + +This notation, `{{ _expression_ }}`, is a bit of built-in angular {@link dev_guide.compiler.markup +markup}, a shortcut for displaying data to the user. The expression within curly braces gets +transformed by the angular compiler into an angular directive ({@link api/angular.directive.ng:bind +ng:bind}). The expression itself can be a combination of both an expression and a {@link +dev_guide.templates.filters filter}: `{{ expression | filter }}`. Angular provides filters for +formatting display data. + + +In the example above, the expression in double-curly braces directs angular to, "Bind the data we +got from the input widgets to the display, multiply them together, and format the resulting number +into output that looks like money." + + + + +# The Angular Philosophy + + +Angular is built around the belief that declarative code is better than imperative when it comes to +building UIs and wiring software components together, while imperative code is excellent for +expressing business logic. + + +Not to put too fine a point on it, but if you wanted to add a new label to your application, you +could do so by simply adding text to the HTML template, saving the code, and refreshing your +browser: + + +<pre> +<span class="label">Hello</span> +</pre> + + +Or, as in programmatic systems (like {@link http://code.google.com/webtoolkit/ GWT}), you would +have to write the code and then run the code like this: + + +<pre> +var label = new Label(); +label.setText('Hello'); +label.setClass('label'); +parent.addChild(label); +</pre> + + +That's one line of markup versus four times as much code. + + + + +## More Angular Philosophy + + +* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves +the testability of the code. +* It is a really, _really_ good idea to regard app testing as equal in importance to app writing. +Testing difficulty is dramatically affected by the way the code is structured. +* It is an excellent idea to decouple the client side of an app from the server side. This allows +development work to progress in parallel, and allows for reuse of both sides. +* It is very helpful indeed if the framework guides developers through the entire journey of +building an app: from designing the UI, through writing the business logic, to testing. +* It is always good to make common tasks trivial and difficult tasks possible. + + +Now that we're homing in on what angular is, perhaps now would be a good time to list a few things +that angular is not: + + +* It's not a Library. You don't just call its functions, although it does provide you with some +utility APIs. +* It's not a DOM Manipulation Library. Angular uses jQuery to manipulate the DOM behind the scenes, +rather than give you functions to manipulate the DOM yourself. +* It's not a Widget Library. There are lots of existing widget libraries that you can integrate +with angular. +* It's not "Just Another Templating System". A part of angular is a templating system. The +templating subsystem of angular is different from the traditional approach for these reasons: + * It Uses HTML/CSS syntax: This makes it easy to read and can be edited with existing HTML/CSS +authoring tools. + * It Extends HTML vocabulary: Angular allows you to create new HTML tags, which expand into +dynamic UI components. + * It Executes in the browser: Removes the round trip to the server for many operations and +creates instant feedback for users as well as developers. + * It Has Bidirectional data binding: The model is the single source of truth. Programmatic +changes to the model are automatically reflected in the view. Any changes by the user to the view +are automatically reflected in the model. + + + + +# Why You Want Angular + + +Angular frees you from the following pain: + + +* **Registering callbacks:** Registering callbacks clutters your code, making it hard to see the +forest for the trees. Removing common boilerplate code such as callbacks is a good thing. It vastly +reduces the amount of JavaScript coding _you_ have to do, and it makes it easier to see what your +application does. +* **Manipulating HTML DOM programatically:** Manipulating HTML DOM is a cornerstone of AJAX +applications, but it's cumbersome and error-prone. By declaratively describing how the UI should +change as your application state changes, you are freed from low level DOM manipulation tasks. Most +applications written with angular never have to programatically manipulate the DOM, although you +can if you want to. +* **Marshaling data to and from the UI:** CRUD operations make up the majority of AJAX +applications. The flow of marshaling data from the server to an internal object to an HTML form, +allowing users to modify the form, validating the form, displaying validation errors, returning to +an internal model, and then back to the server, creates a lot of boilerplate code. Angular +eliminates almost all of this boilerplate, leaving code that describes the overall flow of the +application rather than all of the implementation details. +* **Writing tons of initialization code just to get started:** Typically you need to write a lot of +plumbing just to get a basic "Hello World" AJAX app working. With angular you can bootstrap your +app easily using services, which are auto-injected into your application in a {@link +http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you to +get started developing features quickly. As a bonus, you get full control over the initialization +process in automated tests. + + + + +# Watch a Presentation About Angular + + +Here is an early presentation on angular, but note that substantial development has occurred since +the talk was given in July of 2010. + + +<object width="480" height="385"> + <param name="movie" value="http://www.youtube.com/v/elvcgVSynRg&hl=en_US&fs=1"></param> + <param name="allowFullScreen" value="true"></param> + <param name="allowscriptaccess" value="always"></param> + <embed src="http://www.youtube.com/v/elvcgVSynRg&hl=en_US&fs=1" + type="application/x-shockwave-flash" allowscriptaccess="always" + allowfullscreen="true" width="480" height="385"></embed> +</object> + + +{@link + +https://docs.google.com/present/edit?id=0Abz6S2TvsDWSZDQ0OWdjaF8yNTRnODczazdmZg&hl=en&authkey=CO-b7oID + +Presentation} +| +{@link + +https://docs.google.com/document/edit?id=1ZHVhqC0apbzPRQcgnb1Ye-bAUbNJ-IlFMyPBPCZ2cYU&hl=en&authkey=CInnwLYO + +Source} diff --git a/docs/content/guide/dev_guide.scopes.controlling_scopes.ngdoc b/docs/content/guide/dev_guide.scopes.controlling_scopes.ngdoc new file mode 100644 index 00000000..ca63cbc3 --- /dev/null +++ b/docs/content/guide/dev_guide.scopes.controlling_scopes.ngdoc @@ -0,0 +1,50 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Scopes: Applying Controllers to Scopes +@description + + +When a controller function is applied to a scope, the scope is augmented with the behavior defined +in the controller. The end result is that the scope behaves as if it were the controller: + + +<pre> +var scope = angular.scope(); +scope.salutation = 'Hello'; +scope.name = 'World'; + + +expect(scope.greeting).toEqual(undefined); + + +scope.$watch('name', function(){ +this.greeting = this.salutation + ' ' + this.name + '!'; +}); + + +expect(scope.greeting).toEqual('Hello World!'); +scope.name = 'Misko'; +// scope.$eval() will propagate the change to listeners +expect(scope.greeting).toEqual('Hello World!'); + + +scope.$eval(); +expect(scope.greeting).toEqual('Hello Misko!'); +</pre> + + + + +## Related Topics + + +* {@link dev_guide.scopes Angular Scope Objects} +* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scopes} +* {@link dev_guide.scopes.working_scopes Working With Angular Scopes} +* {@link dev_guide.scopes.updating_scopes Updating Angular Scopes} + + +## Related API + + +* {@link api/angular.scope Angular Scope API} diff --git a/docs/content/guide/dev_guide.scopes.ngdoc b/docs/content/guide/dev_guide.scopes.ngdoc new file mode 100644 index 00000000..730ac348 --- /dev/null +++ b/docs/content/guide/dev_guide.scopes.ngdoc @@ -0,0 +1,51 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Scopes +@description + + + + +An angular scope is a JavaScript type defined by angular. Instances of this type are objects that +serve as the context within which all model and controller methods live and get evaluated. + + +Angular links scope objects to specific points in a compiled (processed) template. This linkage +provides the contexts in which angular creates data-bindings between the model and the view. You +can think of angular scope objects as the medium through which the model, view, and controller +communicate. + + +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.scope.$watch $watch}, bindings created by +{@link api/angular.directive.ng:bind ng:bind}, or HTML input elements). + + +Angular scope objects are responsible for: + + +* Gluing the model, controller and view template together. +* Providing the mechanism to watch for model changes ({@link api/angular.scope.$watch}). +* Notifying interested components when the model changes ({@link api/angular.scope.$eval}). +* Providing the context in which all controller functions and angular expressions are evaluated. + + + + +## Related Topics + + +* {@link dev_guide.scopes.understanding_scopes Understanding Scopes} +* {@link dev_guide.scopes.working_scopes Working With Scopes} +* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes} +* {@link dev_guide.scopes.updating_scopes Updating Scopes} + + +## Related API + + +* {@link api/angular.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 new file mode 100644 index 00000000..b258f867 --- /dev/null +++ b/docs/content/guide/dev_guide.scopes.understanding_scopes.ngdoc @@ -0,0 +1,83 @@ +@workInProgress +@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 `<html>`). 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. + + +<img src="img/guide/simple_scope_final.png"> + + +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: + + +<doc:example> +<doc:source> + <ul ng:init="name='Hank'; names=['Igor', 'Misko', 'Gail', 'Kai']"> + <li ng:repeat="name in names"> + Name = {{name}}! + </li> + </ul> +<pre>Name={{name}}</pre> +</doc:source> +<doc:scenario> + 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']);g/@ + + + 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'); + }); +</doc:scenario> +</doc:example> + + +The angular {@link api/angular.widget.@ng:repeat ng:repeat} directive creates a new scope for each +element that it repeats (in this example the elements are list items). In the `<ul>` element, we +initialized `name` to "Hank", and we created an array called `names` to use as the data source for +the list items. In each `<li>` element, `name` is overridden. Outside of the `<li>` repeater, the +original value of `name` is displayed. + + +The following illustration shows the DOM and angular scopes for the example above: + + +<img src="img/guide/dom_scope_final.png"> + + + + +## Related Topics + + +* {@link dev_guide.scopes Angular Scope Objects} +* {@link dev_guide.scopes.working_scopes Working With Scopes} +* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes} +* {@link dev_guide.scopes.updating_scopes Updating Scopes} + + +## Related API + + +* {@link api/angular.scope Angular Scope API} diff --git a/docs/content/guide/dev_guide.scopes.updating_scopes.ngdoc b/docs/content/guide/dev_guide.scopes.updating_scopes.ngdoc new file mode 100644 index 00000000..ff6734cc --- /dev/null +++ b/docs/content/guide/dev_guide.scopes.updating_scopes.ngdoc @@ -0,0 +1,47 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Scopes: Updating Scope Properties +@description + + +You can update a scope by calling its {@link api/angular.scope.$eval $eval()} method, but usually +you do not have to do this explicitly. In most cases, angular intercepts all external events (such +as user interactions, XHRs, and timers) and calls the `$eval()` method on the scope object for you +at the right time. The only time you might need to call `$eval()` explicitly is when you create +your own custom widget or service. + + +The reason it is unnecessary to call `$eval()` from within your controller functions when you use +built-in angular widgets and services is because a change in the data model triggers a call to the +`$eval()` method on the scope object where the data model changed. + + +When a user inputs data, angularized widgets copy the data to the appropriate scope and then call +the `$eval()` method on the root scope to update the view. It works this way because scopes are +inherited, and a child scope `$eval()` overrides its parent's `$eval()` method. Updating the whole +page requires a call to `$eval()` on the root scope as `$root.$eval()`. Similarly, when a request +to fetch data from a server is made and the response comes back, the data is written into the model +and then `$eval()` is called to push updates through to the view and any other dependents. + + +A widget that creates scopes (such as {@link api/angular.widget.@ng:repeat ng:repeat}) is +responsible for forwarding `$eval()` calls from the parent to those child scopes. That way, calling +`$eval()` on the root scope will update the whole page. This creates a spreadsheet-like behavior +for your app; the bound views update immediately as the user enters data. + + + + +## Related Documents + + +* {@link dev_guide.scopes Angular Scope Objects} +* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects} +* {@link dev_guide.scopes.working_scopes Working With Angular Scopes} +* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes} + + +## Related API + + +* {@link api/angular.scope Angular Scope API} diff --git a/docs/content/guide/dev_guide.scopes.working_scopes.ngdoc b/docs/content/guide/dev_guide.scopes.working_scopes.ngdoc new file mode 100644 index 00000000..ab507e16 --- /dev/null +++ b/docs/content/guide/dev_guide.scopes.working_scopes.ngdoc @@ -0,0 +1,65 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Scopes: Working With Angular Scopes +@description + + +When you use {@link api/angular.directive.ng:autobind ng:autobind} to bootstrap your application, +angular creates the root scope automatically for you. If you need more control over the +bootstrapping process, or if you need to create a root scope for a test, you can do so using the +{@link api/angular.scope angular.scope()} API. + + +Here is a simple code snippet that demonstrates how to create a scope object, assign model +properties to it, and register listeners to watch for changes to the model properties: + + +<pre> +var scope = angular.scope(); +scope.salutation = 'Hello'; +scope.name = 'World'; + + +// Verify that greeting is undefined +expect(scope.greeting).toEqual(undefined); + + +// Set up the watcher... +scope.$watch('name', function(){ +// when 'name' changes, set 'greeting'... +this.greeting = this.salutation + ' ' + this.name + '!'; +} +); + + +// verify that 'greeting' was set... +expect(scope.greeting).toEqual('Hello World!'); + + +// 'name' changed! +scope.name = 'Misko'; + + +// scope.$eval() will propagate the change to listeners +expect(scope.greeting).toEqual('Hello World!'); + + +scope.$eval(); +// verify that '$eval' propagated the change +expect(scope.greeting).toEqual('Hello Misko!'); +</pre> + + +## Related Topics + + +* {@link dev_guide.scopes Angular Scope Objects} +* {@link dev_guide.scopes.understanding_scopes Understanding Scopes} +* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes} +* {@link dev_guide.scopes.updating_scopes Updating Scopes} + + +## Related API + + +* {@link api/angular.scope Angular Scope API} diff --git a/docs/content/guide/dev_guide.services.creating_services.ngdoc b/docs/content/guide/dev_guide.services.creating_services.ngdoc new file mode 100644 index 00000000..d36c9d67 --- /dev/null +++ b/docs/content/guide/dev_guide.services.creating_services.ngdoc @@ -0,0 +1,71 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services: Creating Angular Services +@description + + +While angular offers several useful services, for any nontrivial application you'll find it useful +to write your own custom services. To do this you begin by registering a service factory function +that angular's DI will use to create the service object when it is needed. + + +The `angular.service` method accepts three parameters: + + +- `{string} name` - Name of the service. +- `{function()} factory` - Factory function (called just once by DI). +- `{Object} config` - Configuration object with the following properties: + - `$inject` - {Array.<string>} - Array of service ids this service depends on. These services +will be passed as arguments into the factory function in the same order specified in the `$inject` +array. Defaults to `[]`. + - `$eager` - {boolean} - If true, the service factory will be called and the service will be +instantiated when angular boots. If false, the service will be lazily instantiated when it is first +requested during instantiation of a dependant. Defaults to `false`. + + +The `this` of the factory function is bound to the root scope of the angular application. + + +All angular services participate in {@link dev_guide.di dependency injection (DI)} by registering +themselves with angular's DI system (injector) under a `name` (id) as well as by declaring +dependencies which need to be provided for the factory function of the registered service. The +ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly +testable. + + +Following is an example of a very simple service. This service depends on the `$window` service +(which is passed as a parameter to the factory function) and is just a function. The service simply +stores all notifications; after the third one, the service displays all of the notifications by +window alert. + + +<pre> + angular.service('notify', function(win) { + var msgs = []; + return function(msg) { + msgs.push(msg); + if (msgs.length == 3) { + win.alert(msgs.join("\n")); + msgs = []; + } + }; + }, {$inject: ['$window']}); +</pre> + + + + +## Related Topics + + +* {@link dev_guide.services.understanding_services Understanding Angular Services} +* {@link dev_guide.services.registering_services Registering Angular Services} +* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} +* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers } +* {@link dev_guide.services.testing_services Testing Angular Services} + + +## Related API + + +* {@link api/angular.service Angular Service API} diff --git a/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc b/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc new file mode 100644 index 00000000..75630b32 --- /dev/null +++ b/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc @@ -0,0 +1,91 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services: Injecting Services Into Controllers +@description + + +Using services as dependencies for controllers is very similar to using services as dependencies +for another service. + + +Since JavaScript is a dynamic language, DI can't figure out which services to inject by static +types (like in static typed languages). Therefore, you must specify the service name by using the +`$inject` property, which is an array containing strings with names of services to be injected. +The name must match the corresponding service ID registered with angular. The order of the service +IDs matters: the order of the services in the array will be used when calling the factory function +with injected parameters. The names of parameters in factory function don't matter, but by +convention they match the service IDs. + + +<pre> +function myController($loc, $log) { +this.firstMethod = function() { + // use $location service + $loc.setHash(); +}; +this.secondMethod = function() { + // use $log service + $log.info('...'); +}; +} +// which services to inject ? +myController.$inject = ['$location', '$log']; +</pre> + + +<doc:example> +<doc:source> +<script type="text/javascript"> +angular.service('notify', function(win) { + var msgs = []; + return function(msg) { + msgs.push(msg); + if (msgs.length == 3) { + win.alert(msgs.join("\n")); + msgs = []; + } + }; +}, {$inject: ['$window']}); + + +function myController(notifyService) { + this.callNotify = function(msg) { + notifyService(msg); + }; +} + + +myController.$inject = ['notify']; +</script> + + +<div ng:controller="myController"> +<p>Let's try this simple notify service, injected into the controller...</p> +<input ng:init="message='test'" type="text" name="message" /> +<button ng:click="callNotify(message);">NOTIFY</button> +</div> +</doc:source> +<doc:scenario> +it('should test service', function(){ + expect(element(':input[name=message]').val()).toEqual('test'); +}); +</doc:scenario> +</doc:example> + + + + +## Related Topics + + +{@link dev_guide.services.understanding_services Understanding Angular Services} +{@link dev_guide.services.creating_services Creating Angular Services} +{@link dev_guide.services.registering_services Registering Angular Services} +{@link dev_guide.services.managing_dependencies Managing Service Dependencies} +{@link dev_guide.services.testing_services Testing Angular Services} + + +## Related API + + +{@link api/angular.service Angular Service API} diff --git a/docs/content/guide/dev_guide.services.managing_dependencies.ngdoc b/docs/content/guide/dev_guide.services.managing_dependencies.ngdoc new file mode 100644 index 00000000..c1abf789 --- /dev/null +++ b/docs/content/guide/dev_guide.services.managing_dependencies.ngdoc @@ -0,0 +1,96 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services: Managing Service Dependencies +@description + + +Angular allows services to declare other services as dependencies needed for construction of their +instances. + + +To declare dependencies, you specify them in the factory function signature and via the `$inject` +property, as an array of string identifiers. Optionally the `$inject` property declaration can be +dropped (see "Inferring `$inject`" but note that that is currently an experimental feature). + + +Here is an example of two services that depend on each other, as well as on other services that are +provided by angular's web framework: + + +<pre> +/** +* batchLog service allows for messages to be queued in memory and flushed +* to the console.log every 50 seconds. +* +* @param {*} message Message to be logged. +*/ +angular.service('batchLog', function($defer, $log) { +var messageQueue = []; + + +function log() { + if (messageQueue.length) { + $log('batchLog messages: ', messageQueue); + messageQueue = []; + } + $defer(log, 50000); + } + + +return function(message) { + messageQueue.push(message); +} +}, {$inject: ['$defer', '$log']); +// note how we declared dependency on built-in $defer and $log services above + + +/** +* routeTemplateMonitor monitors each $route change and logs the current +* template via the batchLog service. +*/ +angular.service('routeTemplateMonitor', function($route, batchLogbatchLog) { +$route.onChange(function() { + batchLog($route.current ? $route.current.template : null); +}); +}, {$inject: ['$route', 'batchLog'], $eager: true}); +</pre> + + +Things to notice in this example: + + +* The `batchLog` service depends on the built-in `{@link api/angular.service.$defer $defer}` and +`{@link api/angular.service.$log $log}` services, and allows messages to be logged into the +`console.log` in batches. +* The `routeTemplateMonitor` service depends on the built-in `{@link api/angular.service.$route +$route}` service as well as our custom `batchLog` service. +* The `routeTemplateMonitor` service is declared to be eager, so that it is started as soon as the +application starts. +* To underline the need for the eager instantiation of the `routeTemplateMonitor` service, nothing +else in the application depends on this service, and in this particular case the factory function +of this service doesn't return anything at all. +* Both of our services use the factory function signature as well as the `$inject` property to +declare their dependencies. It is important that the order of the string identifiers in the array +associated with the `$inject` property is the same as the order of argument names in the signature +of the factory function. Unless the dependencies are inferred from the function signature, it is +this array with IDs and their order that the injector uses to determine which services and in which +order to inject. + + + + +## Related Topics + + +* {@link dev_guide.services.understanding_services Understanding Angular Services} +* {@link dev_guide.services.creating_services Creating Angular Services} +* {@link dev_guide.services.registering_services Registering Services} +* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers } +* {@link dev_guide.services.testing_services Testing Angular Services} + + +## Related API + + +* {@link api/angular.service Angular Service API} +* {@link api/angular.injector Angular Injector API} diff --git a/docs/content/guide/dev_guide.services.ngdoc b/docs/content/guide/dev_guide.services.ngdoc new file mode 100644 index 00000000..57449edc --- /dev/null +++ b/docs/content/guide/dev_guide.services.ngdoc @@ -0,0 +1,29 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services +@description + + +Services are a feature that angular brings to client-side web apps from the server side, where +services have been commonly used for a long time. Services in angular apps are substitutable +objects that are wired together using {@link dev_guide.di dependency injection (DI)}. Services are +most often used with {@link dev_guide.di dependency injection}, also a key feature of angular apps. + + + + +## Related Topics + + +* {@link dev_guide.services.understanding_services Understanding Angular Services} +* {@link dev_guide.services.creating_services Creating Angular Services} +* {@link dev_guide.services.registering_services Registering Angular Services} +* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} +* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers} +* {@link dev_guide.services.testing_services Testing Angular Services} + + +## Related API + + +* {@link api/angular.service Angular Service API} diff --git a/docs/content/guide/dev_guide.services.registering_services.ngdoc b/docs/content/guide/dev_guide.services.registering_services.ngdoc new file mode 100644 index 00000000..2a2117ca --- /dev/null +++ b/docs/content/guide/dev_guide.services.registering_services.ngdoc @@ -0,0 +1,86 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services: Registering Angular Services +@description + + +To register a service, register a factory function that creates the service with angular's +Injector. The Injector is exposed as `{@link api/angular.scope.$service scope.$service}`. The +following pseudo-code shows a simple service registration: + + +<pre> +angular.service('service id', function() { + var shinyNewServiceInstance; + //factory function body that constructs shinyNewServiceInstance + return shinyNewServiceInstance; +}); +</pre> + + +Note that you are not registering a service instance, but rather a factory function that will +create this instance when called. + + +# Instantiating Angular Services + + +A service can be instantiated eagerly or lazily. By default angular instantiates services lazily, +which means that a service will be created only when it is needed for instantiation of a service or +an application component that depends on it. In other words, angular won't instantiate lazy +services unless they are requested directly or indirectly by the application. + + +Eager services on the other hand, are instantiated right after the injector itself is created, +which happens when the angular {@link dev_guide.bootstrap application initializes}. + + +To override the default, you can request that a service is eagerly instantiated as follows: + + +<pre> +angular.service('service id', function() { + var shinyNewServiceInstance; + //factory function body that constructs shinyNewServiceInstance + return shinyNewServiceInstance; +}, {$eager: true}); +</pre> + + +While it is tempting to declare services as eager, only in few cases it is actually useful. If you +are unsure whether to make a service eager, it likely doesn't need to be. To be more specific, a +service should be declared as eager only if it fits one of these scenarios: + + +* Nothing in your application declares this service as its dependency, and this service affects the +state or configuration of the application (e.g. a service that configures `$route` or `$resource` +services) +* A guarantee is needed that the service will be instantiated at application boot time, usually +because the service passively observes the application and it is optional for other application +components to depend on it. An example of this scenario is a service that monitors and logs +application memory usage. + + +Lastly, it is important to realize that all angular services are applicaiton singletons. This means +that there is only one instance of a given service per injector. Since angular is lethally allergic +to the global state, it is possible to create multiple injectors, each with its own instance of a +given service, but that is rarely needed, except in tests where this property is crucially +important. + + + + +## Related Topics + + +* {@link dev_guide.services.understanding_services Understanding Angular Services} +* {@link dev_guide.services.creating_services Creating Angular Services} +* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} +* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers } +* {@link dev_guide.services.testing_services Testing Angular Services} + + +## Related API + + +* {@link api/angular.service Angular Service API} diff --git a/docs/content/guide/dev_guide.services.testing_services.ngdoc b/docs/content/guide/dev_guide.services.testing_services.ngdoc new file mode 100644 index 00000000..65e1ab6d --- /dev/null +++ b/docs/content/guide/dev_guide.services.testing_services.ngdoc @@ -0,0 +1,70 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services: Testing Angular Services +@description + + +Following is a unit test for the service in the example in {@link +dev_guide.services.registering_services Registering Angular Services}. The unit test example uses +Jasmine spy (mock) instead of a real browser alert. + + +<pre> +var mock, notify; + + +beforeEach(function() { +mock = {alert: jasmine.createSpy()}; +notify = angular.service('notify')(mock); +}); + + +it('should not alert first two notifications', function() { +notify('one'); +notify('two'); +expect(mock.alert).not.toHaveBeenCalled(); +}); + + +it('should alert all after third notification', function() { +notify('one'); +notify('two'); +notify('three'); +expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree"); +}); + + +it('should clear messages after alert', function() { +notify('one'); +notify('two'); +notify('third'); +notify('more'); +notify('two'); +notify('third'); +expect(mock.alert.callCount).toEqual(2); +expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]); +}); +</pre> + + + + +## Related Topics + + +* {@link dev_guide.services.understanding_services Understanding Angular Services} +* {@link dev_guide.services.creating_services Creating Angular Services} +* {@link dev_guide.services.registering_services Registering Angular Services} +* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} +* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers} + + +## Related API + + +* {@link api/angular.service Angular Service API} + + + + + diff --git a/docs/content/guide/dev_guide.services.understanding_services.ngdoc b/docs/content/guide/dev_guide.services.understanding_services.ngdoc new file mode 100644 index 00000000..f7afc981 --- /dev/null +++ b/docs/content/guide/dev_guide.services.understanding_services.ngdoc @@ -0,0 +1,48 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services: Understanding Angular Services +@description + + +Angular services are singletons that carry out specific tasks common to web apps, such as the +{@link api/angular.service.$xhr $xhr service} that provides low level access to the browser's +`XMLHttpRequest` object. + + +To use an angular service, you identify it as a dependency for the dependent (a controller, or +another service) that depends on the service. Angular's dependency injection subsystem takes care +of the rest. The angular injector subsystem is in charge of service instantiation, resolution of +dependencies, and provision of dependencies to factory functions as requested. + + +Angular injects dependencies using "constructor" injection (the service is passed in via a factory +function). Because JavaScript is a dynamically typed language, angular's dependency injection +subsystem cannot use static types to identify service dependencies. For this reason a dependent +must explicitly define its dependencies by using the `$inject` property. For example: + + + myController.$inject = ['$location']; + + +The angular web framework provides a set of services for common operations. Like other core angular +variables and identifiers, the built-in services always start with `$` (such as `$xhr` mentioned +above). You can also create your own custom services. + + + + +## Related Topics + + +* {@link dev_guide.di About Angular Dependency Injection} +* {@link dev_guide.services.creating_services Creating Angular Services} +* {@link dev_guide.services.registering_services Registering Angular Services} +* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} +* {@link dev_guide.services.testing_services Testing Angular Services} + + +## Related API + + +* {@link api/angular.service Angular Service API} +* {@link api/angular.injector Injector API} diff --git a/docs/content/guide/dev_guide.templates.css.ngdoc b/docs/content/guide/dev_guide.templates.css.ngdoc new file mode 100644 index 00000000..90021b98 --- /dev/null +++ b/docs/content/guide/dev_guide.templates.css.ngdoc @@ -0,0 +1,70 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Working With CSS in Angular +@description + + + + +Angular includes built-in CSS classes, which in turn have predefined CSS styles. + + +# Built-in CSS classes + + +* `ng-exception` + + +**Usage:** angular applies this class to a DOM element if that element contains an Expression that +threw an exception when evaluated. + + +**Styling:** The built-in styling of the ng-exception class displays an error message surrounded +by a solid red border, for example: + + + <div class="ng-exception">Error message</div> + + +You can try to evaluate malformed expressions in {@link dev_guide.expressions expressions} to see +the `ng-exception` class' styling. + + +* `ng-validation-error` + + +**Usage:** angular applies this class to an input widget element if that element's input does not +pass validation. Note that you set the validation criteria on the input widget element using the +Ng:validate or Ng:required directives. + + +**Styling:** The built-in styling of the ng-validation-error class turns the border of the input +box red and includes a hovering UI element that includes more details of the validation error. You +can see an example in {@link api/angular.widget.@ng:validate ng:validate example}. + + +## Overriding Styles for Angular CSS Classes + + +To override the styles for angular's built-in CSS classes, you can do any of the following: + + +* Download the source code, edit angular.css, and host the source on your own server. +* Create a local CSS file, overriding any styles that you'd like, and link to it from your HTML file +as you normally would: + + +<pre> +<link href="yourfile.css" rel="stylesheet" type="text/css"> +</pre> + + + + +## Related Topics + + +* {@link dev_guide.templates Angular Templates} +* {@link dev_guide.templates.css Working With CSS in Angular} +* {@link dev_guide.templates.formatters Angular Formatters} +* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters} diff --git a/docs/content/guide/dev_guide.templates.databinding.ngdoc b/docs/content/guide/dev_guide.templates.databinding.ngdoc new file mode 100644 index 00000000..1459095e --- /dev/null +++ b/docs/content/guide/dev_guide.templates.databinding.ngdoc @@ -0,0 +1,48 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Data Binding in Angular +@description + + +Data-binding in angular web apps is the automatic syncing of data between the model and view +components. The way that angular implements data-binding lets you treat the model as the +single-source-of-truth in your application. The view is a projection of the model at all times. +When the model changes, the view reflects the change, and vice versa. + + +## Data Binding in Classical Template Systems + + +<img class="right" src="img/One_Way_Data_Binding.png"/> +Most templating systems bind data in only one direction: they merge template and model components +together into a view, as illustrated in the diagram. After the merge occurs, changes to the model +or related sections of the view are NOT automatically reflected in the view. Worse, any changes +that the user makes to the view are not reflected in the model. This means that the developer has +to write code that constantly syncs the view with the model and the model with the view. + + +## Data Binding in Angular Templates + + +<img class="right" src="img/Two_Way_Data_Binding.png"/> +The way angular templates works is different, as illustrated in the diagram. They are different +because first the template (which is the uncompiled HTML along with any additional markup or +directives) is compiled on the browser, and second, the compilation step produces a live view. We +say live because any changes to the view are immediately reflected in the model, and any changes in +the model are propagated to the view. This makes the model always the single-source-of-truth for +the application state, greatly simplifying the programing model for the developer. You can think of +the view as simply an instant projection of your model. + + +Because the view is just a projection of the model, the controller is completely separated from the +view and unaware of it. This makes testing a snap because it is easy to test your controller in +isolation without the view and the related DOM/browser dependency. + + + + +## Related Topics + + +* {@link dev_guide.scopes Angular Scopes} +* {@link dev_guide.templates Angular Templates} diff --git a/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc b/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc new file mode 100644 index 00000000..ca7fa2f2 --- /dev/null +++ b/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc @@ -0,0 +1,74 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Filters: Creating Angular Filters +@description + + +Writing your own filter is very easy: just define a JavaScript function on the `angular.filter` +object. +The framework passes in the input value as the first argument to your function. Any filter +arguments are passed in as additional function arguments. + + +You can use these variables in the function: + + +* `this` — The current scope. +* `this.$element` — The DOM element containing the binding. The `$element` variable allows the +filter to manipulate the DOM. + + +The following sample filter reverses a text string. In addition, it conditionally makes the +text upper-case and assigns color. + + +<doc:example> +<doc:source> +<script type="text/javascript"> + angular.filter('reverse', function(input, uppercase, color) { + var out = ""; + for (var i = 0; i < input.length; i++) { + out = input.charAt(i) + out; + } + // conditional based on optional argument + if (uppercase) { + out = out.toUpperCase(); + } + // DOM manipulation using $element + if (color) { + this.$element.css('color', color); + } + return out; + }); +</script> + + +<input name="text" type="text" value="hello" /><br> +No filter: {{text}}<br> +Reverse: {{text|reverse}}<br> +Reverse + uppercase: {{text|reverse:true}}<br> +Reverse + uppercase + blue: {{text|reverse:true:"blue"}} +</doc:source> +<doc:scenario> +it('should reverse text', function(){ +expect(binding('text|reverse')).toEqual('olleh'); +input('text').enter('ABC'); +expect(binding('text|reverse')).toEqual('CBA'); +}); +</doc:scenario> +</doc:example> + + + + +## Related Topics + + +* {@link dev_guide.templates.filters Understanding Angular Filters} +* {@link dev_guide.compiler Angular HTML Compiler} + + +## Related API + + +* {@link api/angular.filter Angular Filter API} diff --git a/docs/content/guide/dev_guide.templates.filters.ngdoc b/docs/content/guide/dev_guide.templates.filters.ngdoc new file mode 100644 index 00000000..fc0f8f84 --- /dev/null +++ b/docs/content/guide/dev_guide.templates.filters.ngdoc @@ -0,0 +1,38 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Understanding Angular Filters +@description + + +Angular filters format data for display to the user. In addition to formatting data, filters can +also modify the DOM. This allows filters to handle tasks such as conditionally applying CSS styles +to filtered output. + + +For example, you might have a data object that needs to be formatted according to the locale before +displaying it to the user. You can pass expressions through a chain of filters like this: + + + name | uppercase + + +The expression evaluator simply passes the value of name to `angular.filter.uppercase()`. + + +In addition to formatting data, filters can also modify the DOM. This allows filters to handle +tasks such as conditionally applying CSS styles to filtered output. + + + + +## Related Topics + + +* {@link dev_guide.templates.filters.using_filters Using Angular Filters} +* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters} + + +## Related API + + +* {@link api/angular.filter Angular Filter API} diff --git a/docs/content/guide/dev_guide.templates.filters.using_filters.ngdoc b/docs/content/guide/dev_guide.templates.filters.using_filters.ngdoc new file mode 100644 index 00000000..05da5e7d --- /dev/null +++ b/docs/content/guide/dev_guide.templates.filters.using_filters.ngdoc @@ -0,0 +1,55 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Filters: Using Angular Filters +@description + + +Filters can be part of any {@link api/angular.scope} evaluation but are typically used to format +expressions in bindings in your templates: + + + {{ expression | filter }} + + +Filters typically transform the data to a new data type, formatting the data in the process. +Filters can also be chained, and can take optional arguments. + + +You can chain filters using this syntax: + + + {{ expression | filter1 | filter2 }} + + +You can also pass colon-delimited arguments to filters, for example, to display the number 123 with +2 decimal points: + + + 123 | number:2 + + +Here are some examples that show values before and after applying different filters to an +expression in a binding: + + +* No filter: `{{1234.5678}}` => `1234.5678` +* Number filter: `{{1234.5678|number}}` => `1,234.57`. Notice the "," and rounding to two +significant digits. +* Filter with arguments: `{{1234.5678|number:5}}` => `1,234.56780`. Filters can take optional +arguments, separated by colons in a binding. For example, the "number" filter takes a number +argument that specifies how many digits to display to the right of the decimal point. + + + + +## Related Topics + + +* {@link dev_guide.templates.filters Understanding Angular Filters} +* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters} + + +## Related API + + +* {@link api/angular.filter Angular Filter API} diff --git a/docs/content/guide/dev_guide.templates.formatters.creating_formatters.ngdoc b/docs/content/guide/dev_guide.templates.formatters.creating_formatters.ngdoc new file mode 100644 index 00000000..08504bbc --- /dev/null +++ b/docs/content/guide/dev_guide.templates.formatters.creating_formatters.ngdoc @@ -0,0 +1,63 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Angular Formatters: Creating Angular Formatters +@description + + +To create your own formatter, you can simply register a pair of JavaScript functions with +`angular.formatter`. One of your functions is used to parse text from the input widget into the +data storage format; the other function is used to format stored data into user-readable text. + + +The following example demonstrates a "reverse" formatter. Data is stored in uppercase and in +reverse, but it is displayed in lower case and non-reversed. When a user edits the data model via +the input widget, the input is automatically parsed into the internal data storage format, and when +the data changes in the model, it is automatically formatted to the user-readable form for display +in the view. + + +<pre> +function reverse(text) { +var reversed = []; +for (var i = 0; i < text.length; i++) { +reversed.unshift(text.charAt(i)); +} +return reversed.join(''); +} + + +angular.formatter('reverse', { +parse: function(value){ +return reverse(value||'').toUpperCase(); +}, +format: function(value){ +return reverse(value||'').toLowerCase(); +} +}); +</pre> + + +<doc:example> +<doc:source> +<script type="text/javascript"> +function reverse(text) { +var reversed = []; +for (var i = 0; i < text.length; i++) { + reversed.unshift(text.charAt(i)); +} +return reversed.join(''); +} + + +angular.formatter('reverse', { +parse: function(value){ + return reverse(value||'').toUpperCase(); +}, +format: function(value){ + return reverse(value||'').toLowerCase(); +} +}); +</script> + + + diff --git a/docs/content/guide/dev_guide.templates.formatters.ngdoc b/docs/content/guide/dev_guide.templates.formatters.ngdoc new file mode 100644 index 00000000..4dd8f22b --- /dev/null +++ b/docs/content/guide/dev_guide.templates.formatters.ngdoc @@ -0,0 +1,26 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Angular Formatters +@description + + +In angular, formatters are responsible for translating user-readable text entered in an {@link +api/angular.widget.HTML input widget} to a JavaScript object in the data model that the application +can manipulate. + + +You can use formatters in a template, and also in JavaScript. Angular provides built-in +formatters, and of course you can create your own formatters. + + +## Related Topics + + +* {@link dev_guide.templates.formatters.using_formatters Using Angular Formatters} +* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters} + + +## Related API + + +* {@link api/angular.formatter Angular Formatter API} diff --git a/docs/content/guide/dev_guide.templates.formatters.using_formatters.ngdoc b/docs/content/guide/dev_guide.templates.formatters.using_formatters.ngdoc new file mode 100644 index 00000000..8e160317 --- /dev/null +++ b/docs/content/guide/dev_guide.templates.formatters.using_formatters.ngdoc @@ -0,0 +1,12 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Angular Formatters: Using Angular Formatters +@description + + +The following snippet shows how to use a formatter in a template. The formatter below is +`ng:format="reverse"`, added as an attribute to an `<input>` tag. + + +<pre> + diff --git a/docs/content/guide/dev_guide.templates.ngdoc b/docs/content/guide/dev_guide.templates.ngdoc new file mode 100644 index 00000000..59fed0fc --- /dev/null +++ b/docs/content/guide/dev_guide.templates.ngdoc @@ -0,0 +1,75 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Understanding Angular Templates +@description + + +An angular template is the declarative specification that, along with information from the model +and controller, becomes the rendered view that a user sees in the browser. It is the static DOM, +containing HTML, CSS, and angular-specific elements and angular-specific element attributes. The +angular elements and attributes direct angular to add behavior and transform the template DOM into +the dynamic view DOM. + + +These are the types of angular elements and element attributes you can use in a template: + + +* {@link dev_guide.compiler.directives Directive} — An attribute that augments an existing DOM +element. +* {@link dev_guide.compiler.widgets Widget} — A custom DOM element. An example of a built-in widget +is {@link api/angular.widget.@ng:repeat ng:repeat}. +* {@link dev_guide.compiler.markup Markup} — Shorthand for a widget or a directive. The double +curly brace notation `{{ }}` to bind expressions to elements is built-in angular markup. +* {@link dev_guide.templates.filters Filter} — Formats your data for display to the user. +* {@link dev_guide.templates.validators Validator} — Lets you validate user input. +* {@link dev_guide.templates.formatters Formatter} — Lets you format the input object into a user +readable view. + + +Note: In addition to declaring the elements above in templates, you can also access these elements +in JavaScript code. + + +The following code snippet shows a simple angular template made up of standard HTML tags along with +angular {@link dev_guide.compiler.directives directives}, {@link dev_guide.compiler.markup markup}, +and {@link dev_guide.expressions expressions}: + + +<pre> +<html> + <!-- Body tag augmented with ng:controller directive --> + <body ng:controller="MyController"> + <input name="foo" value="bar"> + <!-- Button tag with ng:click directive, and + string expression 'buttonText' + wrapped in "{{ }}" markup --> + <button ng:click="changeFoo()">{{buttonText}}</button> + <script src="angular.js" ng:autobind> + </body> +</html> +</pre> + + +In a simple single-page app, the template consists of HTML, CSS, and angular directives contained +in just one HTML file (usually `index.html`). In a more complex app, you can display multiple views +within one main page using "partials", which are segments of template located in separate HTML +files. You "include" the partials in the main page using the {@link api/angular.service.$route +$route} service in conjunction with the {@link api/angular.widget.ng:view ng:view} directive. An +example of this technique is shown in the {@link tutorial/ angular tutorial}, in steps seven and +eight. + + + + +## Related Topics + + +* {@link dev_guide.templates.filters Angular Filters} +* {@link dev_guide.templates.formatters Angular Formatters} +* {@link dev_guide.templates.validators Angular Validators} + + +## Related API + + +* {@link api/index API Reference} diff --git a/docs/content/guide/dev_guide.templates.validators.creating_validators.ngdoc b/docs/content/guide/dev_guide.templates.validators.creating_validators.ngdoc new file mode 100644 index 00000000..661ce744 --- /dev/null +++ b/docs/content/guide/dev_guide.templates.validators.creating_validators.ngdoc @@ -0,0 +1,100 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Validators: Creating Angular Validators +@description + + + + +To create a custom validator, you simply add your validator code as a method onto the +`angular.validator` object and provide input(s) for the validator function. Each input provided is +treated as an argument to the validator function. Any additional inputs should be separated by +commas. + + +The following bit of pseudo-code shows how to set up a custom validator: + + +<pre> +angular.validator('your_validator', function(input [,additional params]) { + [your validation code]; + if ( [validation succeeds] ) { + return false; + } else { + return true; // No error message specified + } +} +</pre> + + +Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true, +there was a problem with that input". If you prefer to provide more information when a validator +detects a problem with input, you can specify an error message in the validator that angular will +display when the user hovers over the input widget. + + +To specify an error message, replace "`return true;`" with an error string, for example: + + + return "Must be a value between 1 and 5!"; + + +Following is a sample UPS Tracking Number validator: + + +<doc:example> +<doc:source> +<script> +angular.validator('upsTrackingNo', function(input, format) { + var regexp = new RegExp("^" + format.replace(/9/g, '\\d') + "$"); + return input.match(regexp)?"":"The format must match " + format; +}); +</script> +<input type="text" name="trackNo" size="40" + ng:validate="upsTrackingNo:'1Z 999 999 99 9999 999 9'" + value="1Z 123 456 78 9012 345 6"/> +</doc:source> +<doc:scenario> +it('should validate correct UPS tracking number', function() { +expect(element('input[name=trackNo]').attr('class')). + not().toMatch(/ng-validation-error/); +}); + + +it('should not validate in correct UPS tracking number', function() { +input('trackNo').enter('foo'); +expect(element('input[name=trackNo]').attr('class')). + toMatch(/ng-validation-error/); +}); +</doc:scenario> +</doc:example> + + +In this sample validator, we specify a regular expression against which to test the user's input. +Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it +returns the specified error message ("true"). + + +Note: you can also access the current angular scope and DOM element objects in your validator +functions as follows: + + +* `this` === The current angular scope. +* `this.$element` === The DOM element that contains the binding. This allows the filter to +manipulate the DOM in addition to transforming the input. + + + + +## Related Topics + + +* {@link dev_guide.templates Angular Templates} +* {@link dev_guide.templates.filters Angular Filters} +* {@link dev_guide.templates.formatters Angular Formatters} + + +## Related API + + +* {@link api/angular.validator API Validator Reference} diff --git a/docs/content/guide/dev_guide.templates.validators.ngdoc b/docs/content/guide/dev_guide.templates.validators.ngdoc new file mode 100644 index 00000000..4976b8de --- /dev/null +++ b/docs/content/guide/dev_guide.templates.validators.ngdoc @@ -0,0 +1,160 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Templates: Understanding Angular Validators +@description + + +Angular validators are attributes that test the validity of different types of user input. Angular +provides a set of built-in input validators: + + +* {@link api/angular.validator.phone phone number} +* {@link api/angular.validator.number number} +* {@link api/angular.validator.integer integer} +* {@link api/angular.validator.date date} +* {@link api/angular.validator.email email address} +* {@link api/angular.validator.json JSON} +* {@link api/angular.validator.regexp regular expressions} +* {@link api/angular.validator.url URLs} +* {@link api/angular.validator.asynchronous asynchronous} + + +You can also create your own custom validators. + + +# Using Angular Validators + + +You can use angular validators in HTML template bindings, and in JavaScript: + + +* Validators in HTML Template Bindings + + +<pre> +<input ng:validator="validator_type:parameters" [...]> +</pre> + + +* Validators in JavaScript + + +<pre> +angular.validator.[validator_type](parameters) +</pre> + + +The following example shows how to use the built-in angular integer validator: + + +<doc:example> +<doc:source> + Change me: <input type="text" name="number" ng:validate="integer" value="123"> +</doc:source> +<doc:scenario> + it('should validate the default number string', function() { + expect(element('input[name=number]').attr('class')). + not().toMatch(/ng-validation-error/); + }); + it('should not validate "foo"', function() { + input('number').enter('foo'); + expect(element('input[name=number]').attr('class')). + toMatch(/ng-validation-error/); + }); +</doc:scenario> +</doc:example> + + +# Creating an Angular Validator + + +To create a custom validator, you simply add your validator code as a method onto the +`angular.validator` object and provide input(s) for the validator function. Each input provided is +treated as an argument to the validator function. Any additional inputs should be separated by +commas. + + +The following bit of pseudo-code shows how to set up a custom validator: + + +<pre> +angular.validator('your_validator', function(input [,additional params]) { + [your validation code]; + if ( [validation succeeds] ) { + return false; + } else { + return true; // No error message specified + } +} +</pre> + + +Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true, +there was a problem with that input". If you prefer to provide more information when a validator +detects a problem with input, you can specify an error message in the validator that angular will +display when the user hovers over the input widget. + + +To specify an error message, replace "`return true;`" with an error string, for example: + + + return "Must be a value between 1 and 5!"; + + +Following is a sample UPS Tracking Number validator: + + +<doc:example> +<doc:source> +<script> +angular.validator('upsTrackingNo', function(input, format) { + var regexp = new RegExp("^" + format.replace(/9/g, '\\d') + "$"); + return input.match(regexp)?"":"The format must match " + format; +}); +</script> +<input type="text" name="trackNo" size="40" + ng:validate="upsTrackingNo:'1Z 999 999 99 9999 999 9'" + value="1Z 123 456 78 9012 345 6"/> +</doc:source> +<doc:scenario> +it('should validate correct UPS tracking number', function() { + expect(element('input[name=trackNo]').attr('class')). + not().toMatch(/ng-validation-error/); +}); + + +it('should not validate in correct UPS tracking number', function() { + input('trackNo').enter('foo'); + expect(element('input[name=trackNo]').attr('class')). + toMatch(/ng-validation-error/); +}); +</doc:scenario> +</doc:example> + + +In this sample validator, we specify a regular expression against which to test the user's input. +Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it +returns the specified error message ("true"). + + +Note: you can also access the current angular scope and DOM element objects in your validator +functions as follows: + + +* `this` === The current angular scope. +* `this.$element` === The DOM element that contains the binding. This allows the filter to +manipulate the DOM in addition to transforming the input. + + + + +## Related Topics + + +* {@link dev_guide.templates Angular Templates} + + +## Related API + + +* {@link api/angular.validator Validator API} diff --git a/docs/content/guide/dev_guide.unit-testing.ngdoc b/docs/content/guide/dev_guide.unit-testing.ngdoc new file mode 100644 index 00000000..d26a904e --- /dev/null +++ b/docs/content/guide/dev_guide.unit-testing.ngdoc @@ -0,0 +1,323 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Unit Testing +@description + + +JavaScript is a dynamically typed language which comes with great power of expression, but it also +come with almost no-help from the compiler. For this reason we feel very strongly that any code +written in JavaScript needs to come with a strong set of tests. We have built many features into +angular which makes testing your angular applications easy. So there is no excuse for not do it. +# It is all about NOT mixing concerns +Unit testing as the name implies is about testing individual units of code. Unit tests try to +answer the question: Did I think about the logic correctly. Does the sort function order the list +in the right order. In order to answer such question it is very important that we can isolate it. +That is because when we are testing the sort function we don't want to be forced into crating +related pieces such as the DOM elements, or making any XHR calls in getting the data to sort. While +this may seem obvious it usually is very difficult to be able to call an individual function on a +typical project. The reason is that the developers often time mix concerns, and they end up with a +piece of code which does everything. It reads the data from XHR, it sorts it and then it +manipulates the DOM. With angular we try to make it easy for you to do the right thing, and so we +provide dependency injection for your XHR (which you can mock out) and we crated abstraction which +allow you to sort your model without having to resort to manipulating the DOM. So that in the end, +it is easy to write a sort function which sorts some data, so that your test can create a data set, +apply the function, and assert that the resulting model is in the correct order. The test does not +have to wait for XHR, or create the right kind of DOM, or assert that your function has mutated the +DOM in the right way. Angular is written with testability in mind, but it still requires that you +do the right thing. We tried to make the right thing easy, but angular is not magic, which means if +you don't follow these, you may very well end up with an untestable application. + + +## Dependency Inject +There are several ways in which you can get a hold of a dependency: +1. You could create it using the `new` operator. +2. You could look for it in a well know place, also known as global singleton. +3. You could ask a registry (also known as service registry) for it. (But how do you get a hold of +the registry? Must likely by looking it up in a well know place. See #2) +4. You could expect that the it be handed to you. + + +Out of the list above only the last of is testable. Lets look at why: + + +### Using the `new` operator + + +While there is nothing wrong with the `new` operator fundamentally the issue is that calling a new +on a constructor permanently binds the call site to the type. For example lets say that we are +trying to instantiate an `XHR` so that we can get some data from the server. + + +<pre> +function MyClass(){ + this.doWork = function(){ + var xhr = new XHR(); + xhr.open(method, url, true); + xhr.onreadystatechange = function(){...} + xhr.send(); + } +} +</pre> + + +The issue becomes, that in tests, we would very much like to instantiate a `MockXHR` which would +allow us to return fake data and simulate network failures. By calling `new XHR()` we are +permanently bound to the actual one, and there is no good way to replace it. Yes there is monkey +patching, that is a bad idea for many reasons, which is outside the scope of this document. + + +The class above is hard to test since we have to resort to monkey patching: +<pre> +var oldXHR = XHR; +XHR = function MockXHR(){}; +var myClass = new MyClass(); +myClass.doWork(); +// assert that MockXHR got called with the right arguments +XHR = oldXHR; // if you forget this bad things will happen +</pre> + + + + +### Global look-up: +Another way to approach the problem is look for the service in a well known location. + + +<pre> +function MyClass(){ + this.doWork = function(){ + global.xhr({ + method:'...', + url:'...', + complete:function(response){ ... } + }) + } +} +</pre> + + +While no new instance of dependency is being created, it is fundamentally the same as `new`, in +that there is no good way to intercept the call to `global.xhr` for testing purposes, other then +through monkey patching. The basic issue for testing is that global variable needs to be mutated in +order to replace it with call to a mock method. For further explanation why this is bad see: {@link +http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/ Brittle Global +State & Singletons} + + +The class above is hard to test since we have to change global state: +<pre> +var oldXHR = glabal.xhr; +glabal.xhr = function mockXHR(){}; +var myClass = new MyClass(); +myClass.doWork(); +// assert that mockXHR got called with the right arguments +global.xhr = oldXHR; // if you forget this bad things will happen +</pre> + + + + +### Service Registry: + + +It may seem as that this can be solved by having a registry for all of the services, and then +having the tests replace the services as needed. + + +<pre> +function MyClass() { + var serviceRegistry = ????; + this.doWork = function(){ + var xhr = serviceRegistry.get('xhr'); + xhr({ + method:'...', + url:'...', + complete:function(response){ ... } + }) +} +</pre> + + +However, where dose the serviceRegistry come from? if it is: +* `new`-ed up, the the test has no chance to reset the services for testing +* global look-up, then the service returned is global as well (but resetting is easier, since +there is only one global variable to be reset). + + +The class above is hard to test since we have to change global state: +<pre> +var oldServiceLocator = glabal.serviceLocator; +glabal.serviceLocator.set('xhr', function mockXHR(){}); +var myClass = new MyClass(); +myClass.doWork(); +// assert that mockXHR got called with the right arguments +glabal.serviceLocator = oldServiceLocator; // if you forget this bad things will happen +</pre> + + + + +### Passing in Dependencies: +Lastly the dependency can be passed in. + + +<pre> +function MyClass(xhr) { + this.doWork = function(){ + xhr({ + method:'...', + url:'...', + complete:function(response){ ... } + }) +} +</pre> + + +This is the proferred way since the code makes no assumptions as to where the `xhr` comes from, +rather that who-ever crated the class was responsible for passing it in. Since the creator of the +class should be different code the the user of the class, it separates the responsibility of +creation from the logic, and that is what dependency-injection is in a nutshell. + + +The class above is very testable, since in the test we can write: +<pre> +function xhrMock(args) {...} +var myClass = new MyClass(xhrMock); +myClass.doWork(); +// assert that xhrMock got called with the right arguments +</pre> + + +Notice that no global variables were harmed in the writing of this test. + + +Angular comes with {@link dev_guide.di dependency-injection} built in which makes the right thin +the easy thing to do, but you still need to do it if you wish to take advantage of the testability +story. + + +## Controllers +What makes each application unique is its logic, which is what we would like to test. If the logic +for your application is mixed in with DOM manipulation, it will be hard to test as in the example +below: + + +<pre> +function PasswordController(){ + // get references to DOM elements + var msg = $('.ex1 span'); + var input = $('.ex1 input'); + var strength; + + this.grade = function(){ + msg.removeClass(strength); + var pwd = input.val(); + password.text(pwd); + if (pwd.length > 8) { + strength = 'strong'; + } else if (pwd.length > 3) { + strength = 'medium'; + } else { + strength = 'weak'; + } + msg + .addClass(strength) + .text(strength); + } +} +</pre> + + +The code above is problematic from testability, since it requires your test to have the right kind +of DOM present when the code executes. The test would look like this: + + +<pre> +var input = $('<input type="text"/>'); +var span = $('<span>'); +$('body').html('<div class="ex1">') + .find('div') + .append(input) + .append(span); +var pc = new PasswordController(); +input.val('abc'); +pc.grade(); +expect(span.text()).toEqual('weak'); +$('body').html(''); +</pre> + + +In angular the controllers are strictly separated from the DOM manipulation logic which results in +a much easier testability story as can be seen in this example: + + +<pre> +function PasswordCntrl(){ + this.password = ''; + this.grade = function(){ + var size = this.password.length; + if (size > 8) { + this.strength = 'strong'; + } else if (size > 3) { + this.strength = 'medium'; + } else { + this.strength = 'weak'; + } + }; +} +</pre> + + +and the tests is straight forward + + +<pre> +var pc = new PasswordController(); +pc.password('abc'); +pc.grade(); +expect(span.strength).toEqual('weak'); +</pre> + + +Notice that the test is not only much shorter but it is easier to follow what is going on. We say +that such a test tells a story, rather then asserting random bits which don't seem to be related. + + + + +## Filters +{@link api/angular.filter Filters} are functions which transform the data into user readable +format. They are important because they remove the formatting responsibility from the application +logic, further simplifying the application logic. + + +<pre> +angular.filter('length', function(text){ + return (''+(text||'')).length; +}); + + +var length = angular.filter('length'); +expect(length(null)).toEqual(0); +expect(length('abc')).toEqual(3); +</pre> + + +## Directives +Directives in angular are responsible for updating the DOM when the state of the model changes. + + + + +## Mocks +oue +## Global State Isolation +oue +# Preferred way of Testing +uo +## JavaScriptTestDriver +ou +## Jasmine +ou +## Sample project +uoe diff --git a/docs/content/guide/index.ngdoc b/docs/content/guide/index.ngdoc index 1a9d2555..7ebeba67 100644 --- a/docs/content/guide/index.ngdoc +++ b/docs/content/guide/index.ngdoc @@ -3,32 +3,78 @@ @name Developer Guide @description -* {@link guide.overview Overview} - An overview of angular, including its philosophy and how it - works. -* {@link guide.bootstrap Bootstrap} - How to bootstrap your application to the angular environment. -* {@link guide.template Template} - How to define your application's view using HTML, CSS, and - other built-in angular constructs. -* {@link guide.compiler Compiler} - All about the HTML compiler that's at the core of angular. - * {@link angular.directive Directive} - How to use XML attributes to augment an existing DOM - element. - * {@link angular.markup Markup} - How to use markup to create shorthand for a widget or a - directive. For example, markup is what allows you to use the double curly brace notation - `{{}}` to bind expressions to elements. - * {@link guide.data-binding Data Binding} - About the mechanism that keeps the model the single - source of truth of your application at all times, with the view as a live projection of the - model. - * {@link angular.filter Filter} - How to format your data for display to the user. - * {@link angular.widget Widget} - How to create new DOM elements that the browser doesn't already - understand. - * {@link angular.validator Validator} - How to validate user input. - * {@link angular.formatter Formatter} - How to format stored data to user-readable text and - parse the text back to the stored form. - * {@link guide.css CSS} - Built-in CSS classes, when angular assigns them, and how to override - their styles. -* {@link angular.scope Scope} - The model in the model-view-controller design pattern. You can - think about scopes as the JavaScript objects that have extra APIs for registering watchers. - * {@link guide.expression Expression} - The bindings that are embedded in an angular View. -* {@link angular.service Service} - Objects that are wired through dependency injection and then - injected into the root scope. -* {@link guide.testing Testing} - * service:$browser(mock)
\ No newline at end of file + +Welcome to the angular Developer Guide. If you are here to learn the details of how to use angular +to develop web apps, you've come to the right place. + + +If you are completely or relatively unfamiliar with angular, you may want to check out one or both +of the following documents before returning here to the Developer Guide: + + +* {@link intro/started Getting Started} +* {@link tutorial/index Angular Tutorial} + + +<hr> + + +## {@link dev_guide.overview Overview of Angular} + + +## {@link dev_guide.bootstrap Initializing Angular} + + +* {@link dev_guide.bootstrap.auto_bootstrap Understanding Automatic Initialization} +* {@link dev_guide.bootstrap.manual_bootstrap Understanding Manual Initialization} + + +## {@link dev_guide.mvc About MVC in Angular} + + +* {@link dev_guide.mvc.understanding_model Understanding the Model Component} +* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component} +* {@link dev_guide.mvc.understanding_view Understanding the View Component} + + +## {@link dev_guide.scopes Angular Scope Objects} + + +* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects} +* {@link dev_guide.scopes.working_scopes Working With Angular Scopes} +* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes} +* {@link dev_guide.scopes.updating_scopes Updating Scope Properties} + + +## {@link dev_guide.compiler Angular HTML Compiler} + + +* {@link dev_guide.compiler.directives Understanding Angular Directives} +* {@link dev_guide.compiler.widgets Understanding Angular Widgets} +* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets} +* {@link dev_guide.compiler.markup Understanding Angular Markup} + + +## {@link dev_guide.templates Angular Templates} + + +* {@link dev_guide.templates.filters Understanding Angular Filters} +* {@link dev_guide.templates.formatters Understanding Angular Formatters} +* {@link dev_guide.templates.validators Understanding Angular Validators} + + +## {@link dev_guide.services Angular Services} + + +* {@link dev_guide.services.understanding_services Understanding Angular Services} +* {@link dev_guide.services.creating_services Creating Angular Services} +* {@link dev_guide.services.registering_services Registering Angular Services} +* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} +* {@link dev_guide.services.testing_services Testing Angular Services} + + +## {@link dev_guide.di About Dependency Injection} + + +* {@link dev_guide.di.understanding_di Understanding DI in Angular} +* {@link dev_guide.di.using_di_controllers Using DI in Controllers} |
