diff options
| author | Misko Hevery | 2011-04-29 15:18:27 -0700 |
|---|---|---|
| committer | Igor Minar | 2011-06-06 22:28:38 -0700 |
| commit | 11e9572b952e49b01035e956c412d6095533031a (patch) | |
| tree | 04dbf96802f552693d44c541c0d825a2769e3d57 /docs/content/guide | |
| parent | b6bc6c2ddf1ae1523ec7e4cb92db209cd6501181 (diff) | |
| download | angular.js-11e9572b952e49b01035e956c412d6095533031a.tar.bz2 | |
Move documentation under individual headings
Diffstat (limited to 'docs/content/guide')
| -rw-r--r-- | docs/content/guide/bootstrap.ngdoc | 97 | ||||
| -rw-r--r-- | docs/content/guide/data-binding.ngdoc | 41 | ||||
| -rw-r--r-- | docs/content/guide/expression.ngdoc | 207 | ||||
| -rw-r--r-- | docs/content/guide/guide.compiler.ngdoc | 163 | ||||
| -rw-r--r-- | docs/content/guide/guide.css.ngdoc | 46 | ||||
| -rw-r--r-- | docs/content/guide/guide.di.ngdoc | 304 | ||||
| -rw-r--r-- | docs/content/guide/index.ngdoc | 37 | ||||
| -rw-r--r-- | docs/content/guide/overview.ngdoc | 337 | ||||
| -rw-r--r-- | docs/content/guide/template.ngdoc | 22 | ||||
| -rw-r--r-- | docs/content/guide/testing.ngdoc | 8 |
10 files changed, 1262 insertions, 0 deletions
diff --git a/docs/content/guide/bootstrap.ngdoc b/docs/content/guide/bootstrap.ngdoc new file mode 100644 index 00000000..12028796 --- /dev/null +++ b/docs/content/guide/bootstrap.ngdoc @@ -0,0 +1,97 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Bootstrap +@description + +# Bootstrap +This section explains how to bootstrap your application to the angular environment using either +the `angular.js` or `angular.min.js` script. + +## The bootstrap code + +Note that there are two versions of the bootstrap code that you can use: + +* `angular-0.0.0.js` - this file is unobfuscated, uncompressed, and thus human-readable. +* `angular-0.0.0.min.js` - this is a compressed and obfuscated version of angular-debug.js. + +In this section and throughout the Developer Guide, feel free to use `angular.min.js` instead of +`angular.js` when working through code examples. + +## ng:autobind + +The simplest way to get an angular application up and running is by inserting a script tag in your +HTML file that bootstraps the `angular.js` code and uses the special `ng:autobind` attribute, +like in this snippet of HTML: + +<doc:example> + <doc:source> + Hello {{'World'}}! + </doc:source> +</doc:example> + +The `ng:autobind` attribute tells angular to compile and manage the whole HTML document. The +compilation occurs in the page's onLoad handler. Note that you don't need to explicitly add an +onLoad event; auto bind mode takes care of all the magic for you. + +## Manual bind + +Using autobind mode is a handy way to start using angular, but advanced users who want more +control over the initialization process might prefer to use manual bind mode instead. + +The best way to get started with manual bind mode is to look at the magic behind `ng:autobind` +by writing out each step of the autobind process explicitly. Note that the following code is +equivalent to the code in the previous section. + +<pre> +<!DOCTYPE HTML> +<html xmlns:ng="http://angularjs.org"> + <script type="text/javascript" src="http://code.angularjs.org/angular-0.0.0.min.js"></script> + <script type="text/javascript"> + (function(window, previousOnLoad){ + window.onload = function(){ + try { (previousOnLoad||angular.noop)(); } catch(e) {} + angular.compile(window.document)(); + }; + })(window, window.onload); + </script> + <body> + Hello {{'World'}}! + </body> +</html> +</pre> + +This is the sequence that your code should follow if you're writing your own manual binding code: + + * After the page is loaded, find the root of the HTML template, which is typically the root of + the document. + * Run the HTML compiler, which converts the templates into an executable, bi-directionally + bound application. + + +# XML Namespace + +**IMPORTANT:** When using angular you must declare the `ng` namespace using the `xmlns` tag. + If you don't declare the namespace, Internet Explorer does not render widgets properly. + +<pre> +<html xmlns:ng="http://angularjs.org"> +</pre> + + +# Create your own namespace + +If you want to define your own widgets, you must create your own namespace and use that namespace +to form the fully qualified widget name. 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: + +<pre> +<html xmlns:my="http://mydomain.com"> +</pre> + + +# Global Object + +The angular script creates a single global variable `angular` in the global namespace. All APIs are +bound to fields of this global object. + diff --git a/docs/content/guide/data-binding.ngdoc b/docs/content/guide/data-binding.ngdoc new file mode 100644 index 00000000..12a926bd --- /dev/null +++ b/docs/content/guide/data-binding.ngdoc @@ -0,0 +1,41 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Data Binding +@description + +# Data Binding + +Data-binding allows you to treat the model as the single-source-of-truth of your application, and +consider the view as only a projection of the model, at all times. The process of copying the model +values to the view, and any changes to the view by the user to the model, is known as data-binding. + +## Classical Template Systems + +<img class="right" src="img/One_Way_Data_Binding.png"/> +At the highest level, angular looks like a just another templating system. But there is one +important reason why angular templating system is different and makes it very good fit for +application development: two-way data binding. + +Most templating systems bind data in only one direction: they merge a template and model together +into a view, as illustrated in the diagram to the right. After the merge occurs, any changes to +the model or in 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. + + +# angular Template Systems +<img class="right" src="img/Two_Way_Data_Binding.png"/> +The way angular templates works is different, as illustrated in the diagram on the right. 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. + +For details about how data binding works in angular, see {@link angular.scope Scope}. diff --git a/docs/content/guide/expression.ngdoc b/docs/content/guide/expression.ngdoc new file mode 100644 index 00000000..421dd9c7 --- /dev/null +++ b/docs/content/guide/expression.ngdoc @@ -0,0 +1,207 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Expression +@description + +# Expressions +Expressions are the bindings that you write in HTML and embed in templates in order to create +views in angular. They are 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 you want to run arbitrary JavaScript code, 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 are 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. E.g. 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 (e.g. 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 $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: + +<pre> +name | uppercase +</pre> + +The expression evaluator simply passes the value of name to angular.filter.uppercase. + +Chain filters using this syntax: + +<pre> +value | filter1 | filter2 +</pre> + +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 chooses 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 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. + + diff --git a/docs/content/guide/guide.compiler.ngdoc b/docs/content/guide/guide.compiler.ngdoc new file mode 100644 index 00000000..8896db43 --- /dev/null +++ b/docs/content/guide/guide.compiler.ngdoc @@ -0,0 +1,163 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Compiler +@description + +#Compiler + +While angular might look like just a cool way to build web applications, the core of angular is +actually an HTML compiler. The default HTML transformations that this compiler provides are useful +for building generic apps, but you can also use them to create a domain-specific language for +building specific types of web applications. + +The compiler allows you to add behavior to existing HTML through widgets, directives, and text +markup. + +All of this compilation happens in the web browser, meaning no server is involved. + +# The compilation process +This section describes the steps that angular's HTML compiler goes through. If you use +`ng:autobind` in your application, this compilation process happens automatically when the +application is initialized (e.g. when the user loads the app in a browser). If you're an advanced +user using manual bind mode, you can decide when and how often the compilation happens. + +First, a bit of background of what the compilation step is for. Every type of +{@link angular.widget widget}, {@link angular.markup markup}, and +{@link angular.directive directive} in angular is defined with a compile function, and that +compile function returns an optional link function. Here is the relationship between the two: + + * **compile function** - registers a listener for the widget, markup, or directive's expression. + This function is called exactly once. + * **link function** - sets up the listener. This function can be called multiple times, once per + cloned DOM element (e.g. repeating element). + +Note that angular's built-in widgets, markup, and directives have predefined compile and link +functions that you don't need to modify. However, if you're writing your own widgets, markup, or +directives, you write compile and link functions. Refer to the Compiler API for more information. + +When the HTML compiler compiles a page, it goes through 3 phases: Compile, Create Root Scope, and +Link. + +## 1. Compile Phase + + * Recursively traverse the DOM, depth-first. + * Look for a matching compile function of type widget, then markup, then directive. + * If a compile function is found then execute it. + * When the compile function completes, it should return a link function. Aggregate this link + function with all link functions returned previously by step 1c. + * Repeat steps 1c and 1d for all compile functions found. The result of the compilation step is + the aggregate link function, which comprises all of the individual link functions. + +## 2. Create Root Scope + + * Inject all of the services into the root scope. + +## 3. Link Phase + + * Execute the aggregate link function with the root scope. The aggregate link function calls all + the individual link functions that were generated in the compile phase. + * 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: once for each iteration in a repeater. + +# Example + +The compilation process is best understood through example. Let's say that in your namespace my, +you want to create a new DOM element <my:greeter/>, which should display a greeting. + +If 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> + +Write this widget definition (assuming you've already declared the my namespace 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 angular.widget Widget}. + +## Compilation process for this example + +Here are the steps that the compiler goes through for the page that contains this widget definition: + +### Compile Phase + + * Recursively traverse the DOM depth-first. + * Find the angular.widget definition. + * Find and execute the widget's compileElement function, which includes the following steps: + * 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)). + * Extract the salutation and name HTML attributes as angular expressions. + * Return the aggregate link function, which includes just one link function in this example. + +### Link Phase + + * Execute the aggregate link function, which includes the following steps: + * Create a <span> element set to the salutation class + * Create a <span> element set to the name class. + * Add the span elements to the linkElement. (Note: be careful not to add them to the + compileElement, because that's the template.) + * Set up watches on the expressions. When an expression changes, copy the data to the + corresponding spans. + + +## Compiler API + +If you define your own widgets, markup, or directives, you need to access the compiler API. +This section describes the methods on the compiler that you can call. + +Note: As of 12 August 2010, these methods are subject to change. + +Recall that the compile function's this is a reference to the compiler. + + * `compile(element)` - returns `linker` - Invoke new instance of compiler to compile a DOM element + and return a linker function. You can apply the linker function to the original element or a + clone of the original element. The linker function returns a scope. + * `comment(commentText)` - returns `element` - Create a comment element. + * `element(elementName)` - returns `element` - Create an element by name. + * `text(text)` - returns `element` - Create a text element. + * `descend([set])` - returns `descend` - State Get or set the current descend state. If true the + compiler will descend to children elements. + * `directives([set])` - returns `directive` - State Get or set the current directives processing + state. The compiler will process directives only when directives set to true. + diff --git a/docs/content/guide/guide.css.ngdoc b/docs/content/guide/guide.css.ngdoc new file mode 100644 index 00000000..6e028f30 --- /dev/null +++ b/docs/content/guide/guide.css.ngdoc @@ -0,0 +1,46 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: CSS +@description + +# CSS +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 angualr.expression expression} 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 angular.widget.@ng:validate ng:validate example}. + +## How to override the styles for built-in classes + +To override the styles for these built-in 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> diff --git a/docs/content/guide/guide.di.ngdoc b/docs/content/guide/guide.di.ngdoc new file mode 100644 index 00000000..2d1f92eb --- /dev/null +++ b/docs/content/guide/guide.di.ngdoc @@ -0,0 +1,304 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Dependency Injection +@description +Dependency injection (DI) is one of the core design patterns in angular and angular applications. DI +allows you to replace almost any part of angular framework or angular application with a custom +implementation, allowing for a highly flexible, maintainable and testable code-base. + +Dependency injection is a very common pattern in Java and other statically typed languages. While +undervalued among JavaScript developers, we feel strongly that DI in JavaScript allows us to achieve +the same benefits as in other languages. + +This document will focus on using dependency injection in angular. It is outside of the scope of +this document to explain details of dependency injection. For more information on this topic, please +refer to these links: + + * {@link http://en.wikipedia.org/wiki/Dependency_injection DI - Wikipedia} + * {@link http://martinfowler.com/articles/injection.html Inversion of Control by Martin Fowler} + * Java + * {@link http://code.google.com/p/google-guice/ Guice} + * {@link http://www.devshed.com/c/a/Java/The-Spring-Framework-Understanding-IoC/ Spring} + * {@link http://picocontainer.org/injection.html picoContainer} + * .NET + * {@link http://msdn.microsoft.com/en-us/magazine/cc163739.aspx MSDN Design Patterns - Dependency Inject} + * {@link http://www.springframework.net/ Spring.NET} + + + +# Dependency Injection in angular + +Angular's dependency injection story begins with a `service`. Service in angular lingo is a +JavaScript object, function, or value that is created by angular's injector via a provided factory +function. The factory function is registered with angular via {@link angular.service}. + +<pre> +// register a factory for a uniqueId service. +angular.service('uniqueId', function(){ + // calling the factory function creates the instance function + var id = 0; + return function(){ + // calling the counter instance function will return and increment the count + return ++id; + } +}); +</pre> + +At run-time we can access the `uniqueId` service by looking it up with the service locator like +this: + +<pre> +// create new root scope which has the injector function `$service()` +var scope = angular.scope(); + +// use the `$service` function to look up the service instance function +var idGenerator = scope.$service('uniqueId'); +expect(idGenerator()).toBe(1); + +// subsequent lookups using the same root scope return the service instance +var idGenerator2 = scope.$service('uniqueId'); +expect(idGenerator).toBe(idGenerator2); + +// since it is same instance calling idGenerator2 returns 2; +expect(idGenerator2()).toBe(2); +</pre> + +The {@link angular.service service} registry seems like a lot of work, so what are the benefits? To +answer this question, it’s important to realize that in large scale applications there are a lot of +services which are often dependent on each other, as in this example: + +<pre> +angular.service('gadgetFactory', function(uniqueId){ + return function(){ + return {gadgetId: uniqueId()}; + }; +}, {$inject: ['uniqueId']}); +</pre> + +Specifically, notice that the `gadgetFactory` takes `uniqueId` service in its arguments. It also +declares this dependency with the `$inject` property. There are several benefits to this approach: + +* There is no need for a `main` method for an application responsible for instantiating and wiring +these services. The order of service instantiation and wiring can be inferred by examining the +`$inject` annotations. +* It is easy to replace any one service with a different implementation without having to track down +all of the dependencies. This is useful in: + * Tests: when mocks of services are needed (for example using mock {@link angular.service.$xhr}.) + * Customization: when the service bundled with angular does not do exactly what the application +requires. + +More importantly, as we'll soon learn, controllers and other components of angular applications can +also declare their dependencies on services and these will be provided without explicitly looking +them up, but let's not get ahead of ourselves. + +Lastly, it is important to realize that all angular services are singletons – application singletons +to be more precise. This means that there is only one instance of a given service per injector. And +since angular is lethally allergic to the global state, it's absolutely possible to create multiple +injectors each with its own instance of a given service (but that is not typically needed, except in +tests where this property is crucially important). + + +## Service Locator and Scope + +The {@link 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 in your application. +The injector is responsible for caching the instances of services, but this cache is bound to the +scope. This means that different root scopes will 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 get this isolation by having each test create its own separate root scope. + +<pre> +// crate a root scope +var rootScope = angular.scope(); +// accesss the service locator +var myService = rootScope.$service('myService'); +</pre> + + + +# Dependency Injection in Controllers + +So far we have been talking about injector as a service locator. This is because we have been +explicitly calling the `$service` method to gain access to the service. Service locator is not +dependency injection since the caller is still responsible for retrieving the dependencies. *True +dependency injection is like Chuck Norris. Chuck does not ask for dependencies; he declares them.* + +The most common place to use dependency injection in angular applications is in +{@link angular.ng:controller controllers}. Here’s 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 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, such as: + +<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 angular.injector injector} to call the +function with the correct arguments. + + + +# Using Dependency Injection pragmatically + +At times you’ll need to use dependency injection pragmatically, usually when instantiating +controllers manually or writing unit tests. This section explains how to go about it. + +## Retrieving Services + +The simplest form of dependency injection is manual retrieval of scopes, known as service locator. +We say manual because we are asking the injector for an instance of the service (rather then having +the injector provide them to the function). This should be rare since most of the time the dependent +services should be injected into the controller using the `$inject` property array. + +<pre> +// create a root scope. The root scope will automatically have +// `$service` method defined which is configured with all services. +// Each instance of root scope will have separate instances of services. +var rootScope = angular.scope(); + +// ask for a service explicitly +var $window = rootScope.$service('$window'); +</pre> + + +## Creating Controllers using Dependency Injection + +In a typical angular application the dependency injection is most commonly used when creating +controllers. +<pre> +// declare our own service by registering a factory function. +angular.service('counter', function(){ + var count = 0; + return function(){ return count++; }; +}); + +// example of a controller which depends on '$window' and 'counter' service +// notice that there is an extra unbound parameter 'name' which will not +// be injected and must be supplied by the caller. +function MyController($window, counter, name) { +} + +// we must declare the dependencies explicitly and in the same order as in +// the constructor function. This information is used by the dependency +// injection to supply the arguments. +// Notice the lack of 'name' argument which makes it an unbound argument. +MyController.$inject = ['$window', 'counter']; + + +// Create a root scope which creates the the injector +var rootScope = angular.scope(); + +// use the '$new()' method instead of standard 'new' keyword operator to +// create an instance of MyController and have the dependency injection +// supply the arguments to the controller. The dependency injection only +// supplies the bound arguments in `$inject` all addition arguments are +// curried from the '$new', in our case 'Alexandria' is the argument which +// will be curried to the 'name' argument, while '$window' and 'counter' +// are supplied by the dependency injection. +var myController = rootScope.$new(MyController, 'Alexandria'); +// NOTE: the returning controller will be a child scope of parent scope, +// in this case the root scope. +</pre> + + +## Calling functions and Curring of arguments + +NOTE: this section is quite lame. The concept it is trying to describe is more closely related to +scope#new than scope#$service. We need a better example to discuss here. Ideally a parent controller +creating a child controller imperatively via $new where the child controller's constructor function +declares a portion of its dependencies via $inject property, but another portion is supplied by the +caller of $new (e.g. parentCtrl.$new(ChildCtrl, configParam1, configParam2); + +Finally, you may need to call functions but have the `$inject` properties of the function be +supplied by the injector. + +<pre> +// create a root scope with the `$service` injector. +var rootScope = angular.scope(); + +// given a function such as +function greet ($window, name) { + $window.alert(this.salutation + ' ' + name); +} +greet.$inject = ['$window']; + +// you can call function 'greet' such that the injector supplies the +// '$window' and the caller supplies the function 'this' and the 'name' +// argument. +var fnThis = {salutation: 'Hello'} +rootScope.$service(greet, fnThis, 'world'); +</pre> + + + +# Inferring `$inject` + +**EXPERIMENTAL: 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 an `$inject` annotation on the function, then it calls the `.toString()` +and tries to infer what should be injected using the following rules: + +* any argument starting with `$` is angular service and will be added to `$inject` property array. +* any argument ending with `_` will be added to the `$inject` property array but we strip 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 curring}) + +**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. diff --git a/docs/content/guide/index.ngdoc b/docs/content/guide/index.ngdoc new file mode 100644 index 00000000..2798210d --- /dev/null +++ b/docs/content/guide/index.ngdoc @@ -0,0 +1,37 @@ +@workInProgress +@ngdoc overview +@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) +* {@link downloading Downloading} - How to download, compile, and host the angular + environment on your own server. +* {@link guide.contribute Contributing} - How to contribute to angular project. diff --git a/docs/content/guide/overview.ngdoc b/docs/content/guide/overview.ngdoc new file mode 100644 index 00000000..61c58435 --- /dev/null +++ b/docs/content/guide/overview.ngdoc @@ -0,0 +1,337 @@ +@ngdoc overview +@name Developer Guide: Overview +@description + + +* <a href="#H1_1">What Is Angular?</a> +* <a href="#H1_3">The Angular Philosophy</a> +* <a href="#H1_2">Anatomy Of An Angular App</a> +* <a href="#H1_4">Why You Want Angular</a> +* <a href="#H1_5">Angular's Ancestors</a> +* <a href="#H1_6">Watch a Presentation About Angular</a> + + +<a name="H1_1"></a> +# 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 kind of depends on where you're coming from... + +* If you're a web designer, you might perceive angular to be a sweet {@link guide.template +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 +guide.compiler compiler} that runs in your browser. This compiler teaches your browser new tricks. + +So then, angular's not just a templating system, but you can create fantastic templates with it; +angular's not just a web framework, but it has a very nice one; and angular's not just an +extensible HTML compiler, but it has one of those too. Let's put it this way: angular includes +these parts along with some others; it evolved naturally from earlier occurrences of these forms; +and thus angular is something far greater than the sum of its parts. It sounds like... it's alive! + +## An Intro By Way of 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 doing DOM updates, writing listeners, and +writing input validators, all to do something as simple as implementing a form!? You either don't +want to go there in the first place or you've been there and the thrill is gone. + +You could even be muttering to yourself as you hack another callback, "This is like building my own +bike from scratch every time I want to ride to the store." But let's say a clever friend, who keeps +tabs on these sorts of things, told you to check out angular. + +So now here you are checking out angular, and here is a simple example. Note that it features only +the templating aspect of angular, but this should suffice for now to quickly demonstrates how much +easier life can be with angular: + +<doc:example> +<doc:source> + <h2>Bigg Bike Shop</h2> + <hr> + <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}} + <hr> +</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> + +Go ahead, try out the Live Preview above. "Well I _declare_! It's a fully functioning form, with +an instantly updating display, and input validation." Speaking of being declarative, let's walk +through the example and look at the angular-related lines to see what's going on around here. + +In line __2__ of the example, we let the browser know about the angular namespace: + + 2 <html xmlns:ng="http://angularjs.org"> + +This ensures angular runs nicely in all major browsers. + +In line __3__ we do two angular setup tasks inside a `<script>` tag: + +1. We pull in `angular.js`. +2. The angular {@link angular.directive.ng:autobind ng:autobind} directive tells angular to {@link +guide.compiler compile} and manage the whole HTML document. + + 3 <script src="file:///Users/krculp/angular.js/build/angular.min.js" ng:autobind></script> + +Lines __14__ and __15__ set up one side of angular's very cool two-way data binding, as well as +demonstrate some easy input validation: + + 14 Quantity: <input name="qty" value="1" ng:validate="integer:0" ng:required/> + 15 Cost: <input name="cost" value="199.95" ng:validate="number" ng:required/> + +These input widgets look normal enough, but consider these points: + +* Remember the `ng:autobind` directive from line 3? 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" part of the Model-View-Controller design pattern. +* Note the angular directives, {@link angular.widget.@ng:validate ng:validate} and {@link +ngular.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 a plainly irritated 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 line #__19__: + + 19 Total: {{qty * cost | currency}} + +What's with the curly braces? Those curly braces are your friend. This notation, `{{ _expression_ +}}`, is a bit of built-in angular {@link angular.markup markup}, a shortcut that you use to display +data. The expression within curly braces gets transformed by the angular compiler into an angular +directive ({@link angular.directive.ng:bind ng:bind}). The expression itself can be a combination +of both an expression and a {@link angular.filter filter}: `{{ expression | filter }}`. + +In our example above, we're saying, "Bind the data we got from the input widgets to the display, +multiply them together, and format the resulting number into something that looks like money." + + +<a name="H1_3"></a> +# 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 clearly the way to +go 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 it by simply adding text to the HTML template, saving the code, and refreshing your +browser (this here is declarative): + +<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 looks like, let's see, do some math, factor out the `<pre>`s, carry the one, ummm... a little +bit 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 +what angular isn't: + +* 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 with 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. + + +<a name="H1_2"></a> +# Anatomy Of An Angular App + +This section describes the parts of an angular app in more detail. + +## Templates + +{@link guide.template Templates} are the part of angular that makes it easy and fun to create the +UI for your web apps. With angular's templates you can create a dynamic UI using only HTML and +CSS, but now you can add your own elements, attributes, and markup. The angular compiler reads the +"angularized" HTML when your page loads, and follows the instructions in there to generate a +dynamic page for you. This is the View part of MVC. "But wait there's more": since the compiler is +extensible, you can build your own declarative language on top of HTML! + +## Application Logic and Behavior + +Application Logic and Behavior, which you define in JavaScript, is the C in MVC. With angular you +write the logic (the controllers) for your app, but because angular takes care of reflecting the +state of the model in the view, you don't have to write listeners or DOM manipulators. This feature +makes your application logic very easy to write, test, maintain, and understand. + +## Data + +In an angular app, all of your data is referenced from inside of a {@link angular.scope scope}. +The scope is the data Model, the M in the MVC pattern. A scope is a JavaScript object that has +watcher functions that keep tabs on the data that is referenced from that scope. The data could be +one or more Javascript objects, arrays, or primitives, it doesn't matter. What matters is that +these are all referenced by the scope. + +This "scope thing" is how angular takes care of keeping your data model and your UI in sync. +Whenever something occurs to change the state of the scope, angular immediately reflects that +change in the UI, and vice versa. + +In addition to the three components described above (the MVC bits), angular comes with a set of +{@link angular.service Services} that are very helpful for building web apps. The services include +the following features: + +* You can extend and add application-specific behavior to services. +* Services include Dependency-Injection, XHR, caching, URL routing, and browser abstraction. + +The following illustration shows the parts of an angular application and how they work together: + +<img class="left" src="img/angular_parts.png" border="0" /> + + +<a name="H1_4"></a> +# 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, knock yourself out. +* **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 (gah!) 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. + + +<a name="H1_5"></a> +# Angular's Ancestors + +Where does angular come from? What events led to the inevitability of the appearance of something +like angular? + +## First There Was HTML + +HTML was initially designed long, long ago, in the great year of 1989, with the intention to create +a markup language for sharing scientific documents over the network. Yes, yes, certainly there was +SGML even before that, but it was so difficult that even esteemed scientists balked at using it. +Thankfully, Tim Berners-Lee saved all of us from that pain with his much friendlier HTML. +`<HTML><BODY>Thank You, TB-L!</BODY></HTML>`. + +## Then There Was JavaScript + +Fast forward to 1995: JavaScript was invented. This was done with the best of intentions! But in +practice it initially served mainly to annoy Internet users with cheap effects that "enhanced" +static HTML documents. + +Fast forward to the mid 2000s, when a new breed of back-then-considered-rich web applications +started to appear on the web. These were built with HTML, JavaScript, and CSS, and featured less +annoying and more impressive effects. Can you recall the first time you saw apps like Gmail, or +Google Maps, and you couldn't believe everything that was going on in the browser? + +## And JavaScript Prevailed + +As of this writing, in 2011, people are building still richer and more interactive web applications +that often rival their desktop counterparts. And yet they are essentially still working with +technology and programming primitives that were used decades ago for the creation of static +documents with cheap graphic effects. At the same time, the web is HUGE now, and we +can't just abandon the technologies it was built with. Applets, Flash and Silverlight tried it, and +in some ways succeeded. Yet many would argue that in reality they failed, because they tried to +work _around_ the web instead of working _with_ it. + +## And Then There Was Angular + +Angular recognizes the strengths of the existing "static" web technologies, as well as their +deficiencies. At the same time, angular is learning from the failures of other technologies that +tried, or are trying, to work around the web. + +For these reasons angular plays to the strengths of established web technologies, instead of +bypassing them. Angular sets out the goal of increasing the abstraction and programming primitives +that developers use to build web applications, so as to better reflect the needs of modern web +applications and their developers. + + +<a name="H1_6"></a> +# 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/template.ngdoc b/docs/content/guide/template.ngdoc new file mode 100644 index 00000000..ae9bba92 --- /dev/null +++ b/docs/content/guide/template.ngdoc @@ -0,0 +1,22 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Template +@description +#Template + +You can think of a template in angular as a domain-specific language that you can use to easily +build the view of your web application. You create a template by writing HTML and CSS, and you can +add any constructs that you want to the HTML. This means that you can attach rendering and behavior +to any HTML element, attribute or markup text. + +In addition to writing HTML and CSS, you can also use the following angular constructs to create +your template: + + * **Directive** - XML attributes that augment an existing DOM element. + * **Markup** - Lets you 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. + * **Filter** - Lets you format your data for display to the user. + * **Widget** - Lets you create new DOM elements that the browser doesn't already understand. + * **Validator** - Lets you validate user input. + * **Formatter** - Lets you format the input object into a user readable view. diff --git a/docs/content/guide/testing.ngdoc b/docs/content/guide/testing.ngdoc new file mode 100644 index 00000000..bb3a1441 --- /dev/null +++ b/docs/content/guide/testing.ngdoc @@ -0,0 +1,8 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Testing +@description + +# Testing Angular Applications + +to be written... |
