From 11e9572b952e49b01035e956c412d6095533031a Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 29 Apr 2011 15:18:27 -0700 Subject: Move documentation under individual headings --- docs/angular.attrMarkup.ngdoc | 15 -- docs/angular.directive.ngdoc | 53 ----- docs/angular.element.ngdoc | 49 ----- docs/angular.filter.ngdoc | 87 -------- docs/angular.formatter.ngdoc | 82 -------- docs/angular.markup.ngdoc | 66 ------ docs/angular.ngdoc | 4 - docs/angular.service.ngdoc | 175 ---------------- docs/angular.validator.ngdoc | 77 ------- docs/angular.widget.ngdoc | 78 ------- docs/content/api/angular.attrMarkup.ngdoc | 15 ++ docs/content/api/angular.directive.ngdoc | 53 +++++ docs/content/api/angular.element.ngdoc | 49 +++++ docs/content/api/angular.filter.ngdoc | 87 ++++++++ docs/content/api/angular.formatter.ngdoc | 82 ++++++++ docs/content/api/angular.markup.ngdoc | 66 ++++++ docs/content/api/angular.ngdoc | 4 + docs/content/api/angular.service.ngdoc | 175 ++++++++++++++++ docs/content/api/angular.validator.ngdoc | 77 +++++++ docs/content/api/angular.widget.ngdoc | 78 +++++++ docs/content/cookbook/buzz.ngdoc | 63 ++++++ docs/content/cookbook/deeplinking.ngdoc | 114 ++++++++++ docs/content/cookbook/form.ngdoc | 103 +++++++++ docs/content/cookbook/formadvanced.ngdoc | 105 ++++++++++ docs/content/cookbook/helloworld.ngdoc | 31 +++ docs/content/cookbook/index.ngdoc | 60 ++++++ docs/content/cookbook/mvc.ngdoc | 125 +++++++++++ docs/content/guide/bootstrap.ngdoc | 97 +++++++++ docs/content/guide/data-binding.ngdoc | 41 ++++ docs/content/guide/expression.ngdoc | 207 ++++++++++++++++++ docs/content/guide/guide.compiler.ngdoc | 163 +++++++++++++++ docs/content/guide/guide.css.ngdoc | 46 ++++ docs/content/guide/guide.di.ngdoc | 304 +++++++++++++++++++++++++++ docs/content/guide/index.ngdoc | 37 ++++ docs/content/guide/overview.ngdoc | 337 ++++++++++++++++++++++++++++++ docs/content/guide/template.ngdoc | 22 ++ docs/content/guide/testing.ngdoc | 8 + docs/content/intro/contribute.ngdoc | 233 +++++++++++++++++++++ docs/content/intro/downloading.ngdoc | 70 +++++++ docs/content/intro/faq.ngdoc | 81 +++++++ docs/content/intro/started.ngdoc | 146 +++++++++++++ docs/content/intro/testimonials.ngdoc | 33 +++ docs/content/tutorial/index.ngdoc | 172 +++++++++++++++ docs/content/tutorial/step_00.ngdoc | 77 +++++++ docs/content/tutorial/step_01.ngdoc | 88 ++++++++ docs/content/tutorial/step_02.ngdoc | 137 ++++++++++++ docs/content/tutorial/step_03.ngdoc | 108 ++++++++++ docs/content/tutorial/step_04.ngdoc | 161 ++++++++++++++ docs/content/tutorial/step_05.ngdoc | 147 +++++++++++++ docs/content/tutorial/step_06.ngdoc | 113 ++++++++++ docs/content/tutorial/step_07.ngdoc | 181 ++++++++++++++++ docs/content/tutorial/step_08.ngdoc | 148 +++++++++++++ docs/content/tutorial/step_09.ngdoc | 108 ++++++++++ docs/content/tutorial/step_10.ngdoc | 110 ++++++++++ docs/content/tutorial/step_11.ngdoc | 178 ++++++++++++++++ docs/contribute.ngdoc | 233 --------------------- docs/cookbook.buzz.ngdoc | 63 ------ docs/cookbook.deeplinking.ngdoc | 114 ---------- docs/cookbook.form.ngdoc | 103 --------- docs/cookbook.formadvanced.ngdoc | 105 ---------- docs/cookbook.helloworld.ngdoc | 31 --- docs/cookbook.mvc.ngdoc | 125 ----------- docs/cookbook.ngdoc | 60 ------ docs/downloading.ngdoc | 70 ------- docs/faq.ngdoc | 81 ------- docs/guide.bootstrap.ngdoc | 97 --------- docs/guide.compiler.ngdoc | 163 --------------- docs/guide.css.ngdoc | 46 ---- docs/guide.data-binding.ngdoc | 41 ---- docs/guide.di.ngdoc | 304 --------------------------- docs/guide.expression.ngdoc | 207 ------------------ docs/guide.ngdoc | 37 ---- docs/guide.overview.ngdoc | 337 ------------------------------ docs/guide.template.ngdoc | 22 -- docs/guide.testing.ngdoc | 8 - docs/service.template | 57 ----- docs/src/gen-docs.js | 2 +- docs/src/ngdoc.js | 43 +++- docs/src/reader.js | 23 +- docs/src/templates/docs.css | 27 ++- docs/src/templates/docs.js | 20 +- docs/src/templates/index.html | 44 ++-- docs/src/writer.js | 21 +- docs/started.ngdoc | 146 ------------- docs/testimonials.ngdoc | 33 --- docs/tutorial.ngdoc | 172 --------------- docs/tutorial.step_00.ngdoc | 78 ------- docs/tutorial.step_01.ngdoc | 88 -------- docs/tutorial.step_02.ngdoc | 137 ------------ docs/tutorial.step_03.ngdoc | 108 ---------- docs/tutorial.step_04.ngdoc | 161 -------------- docs/tutorial.step_05.ngdoc | 147 ------------- docs/tutorial.step_06.ngdoc | 113 ---------- docs/tutorial.step_07.ngdoc | 181 ---------------- docs/tutorial.step_08.ngdoc | 148 ------------- docs/tutorial.step_09.ngdoc | 108 ---------- docs/tutorial.step_10.ngdoc | 110 ---------- docs/tutorial.step_11.ngdoc | 178 ---------------- 98 files changed, 4973 insertions(+), 4945 deletions(-) delete mode 100644 docs/angular.attrMarkup.ngdoc delete mode 100644 docs/angular.directive.ngdoc delete mode 100644 docs/angular.element.ngdoc delete mode 100644 docs/angular.filter.ngdoc delete mode 100644 docs/angular.formatter.ngdoc delete mode 100644 docs/angular.markup.ngdoc delete mode 100644 docs/angular.ngdoc delete mode 100644 docs/angular.service.ngdoc delete mode 100644 docs/angular.validator.ngdoc delete mode 100644 docs/angular.widget.ngdoc create mode 100644 docs/content/api/angular.attrMarkup.ngdoc create mode 100644 docs/content/api/angular.directive.ngdoc create mode 100644 docs/content/api/angular.element.ngdoc create mode 100644 docs/content/api/angular.filter.ngdoc create mode 100644 docs/content/api/angular.formatter.ngdoc create mode 100644 docs/content/api/angular.markup.ngdoc create mode 100644 docs/content/api/angular.ngdoc create mode 100644 docs/content/api/angular.service.ngdoc create mode 100644 docs/content/api/angular.validator.ngdoc create mode 100644 docs/content/api/angular.widget.ngdoc create mode 100644 docs/content/cookbook/buzz.ngdoc create mode 100644 docs/content/cookbook/deeplinking.ngdoc create mode 100644 docs/content/cookbook/form.ngdoc create mode 100644 docs/content/cookbook/formadvanced.ngdoc create mode 100644 docs/content/cookbook/helloworld.ngdoc create mode 100644 docs/content/cookbook/index.ngdoc create mode 100644 docs/content/cookbook/mvc.ngdoc create mode 100644 docs/content/guide/bootstrap.ngdoc create mode 100644 docs/content/guide/data-binding.ngdoc create mode 100644 docs/content/guide/expression.ngdoc create mode 100644 docs/content/guide/guide.compiler.ngdoc create mode 100644 docs/content/guide/guide.css.ngdoc create mode 100644 docs/content/guide/guide.di.ngdoc create mode 100644 docs/content/guide/index.ngdoc create mode 100644 docs/content/guide/overview.ngdoc create mode 100644 docs/content/guide/template.ngdoc create mode 100644 docs/content/guide/testing.ngdoc create mode 100644 docs/content/intro/contribute.ngdoc create mode 100644 docs/content/intro/downloading.ngdoc create mode 100644 docs/content/intro/faq.ngdoc create mode 100644 docs/content/intro/started.ngdoc create mode 100644 docs/content/intro/testimonials.ngdoc create mode 100644 docs/content/tutorial/index.ngdoc create mode 100755 docs/content/tutorial/step_00.ngdoc create mode 100755 docs/content/tutorial/step_01.ngdoc create mode 100755 docs/content/tutorial/step_02.ngdoc create mode 100755 docs/content/tutorial/step_03.ngdoc create mode 100755 docs/content/tutorial/step_04.ngdoc create mode 100755 docs/content/tutorial/step_05.ngdoc create mode 100755 docs/content/tutorial/step_06.ngdoc create mode 100755 docs/content/tutorial/step_07.ngdoc create mode 100755 docs/content/tutorial/step_08.ngdoc create mode 100755 docs/content/tutorial/step_09.ngdoc create mode 100644 docs/content/tutorial/step_10.ngdoc create mode 100644 docs/content/tutorial/step_11.ngdoc delete mode 100644 docs/contribute.ngdoc delete mode 100644 docs/cookbook.buzz.ngdoc delete mode 100644 docs/cookbook.deeplinking.ngdoc delete mode 100644 docs/cookbook.form.ngdoc delete mode 100644 docs/cookbook.formadvanced.ngdoc delete mode 100644 docs/cookbook.helloworld.ngdoc delete mode 100644 docs/cookbook.mvc.ngdoc delete mode 100644 docs/cookbook.ngdoc delete mode 100644 docs/downloading.ngdoc delete mode 100644 docs/faq.ngdoc delete mode 100644 docs/guide.bootstrap.ngdoc delete mode 100644 docs/guide.compiler.ngdoc delete mode 100644 docs/guide.css.ngdoc delete mode 100644 docs/guide.data-binding.ngdoc delete mode 100644 docs/guide.di.ngdoc delete mode 100644 docs/guide.expression.ngdoc delete mode 100644 docs/guide.ngdoc delete mode 100644 docs/guide.overview.ngdoc delete mode 100644 docs/guide.template.ngdoc delete mode 100644 docs/guide.testing.ngdoc delete mode 100644 docs/service.template delete mode 100644 docs/started.ngdoc delete mode 100644 docs/testimonials.ngdoc delete mode 100644 docs/tutorial.ngdoc delete mode 100755 docs/tutorial.step_00.ngdoc delete mode 100755 docs/tutorial.step_01.ngdoc delete mode 100755 docs/tutorial.step_02.ngdoc delete mode 100755 docs/tutorial.step_03.ngdoc delete mode 100755 docs/tutorial.step_04.ngdoc delete mode 100755 docs/tutorial.step_05.ngdoc delete mode 100755 docs/tutorial.step_06.ngdoc delete mode 100755 docs/tutorial.step_07.ngdoc delete mode 100755 docs/tutorial.step_08.ngdoc delete mode 100755 docs/tutorial.step_09.ngdoc delete mode 100644 docs/tutorial.step_10.ngdoc delete mode 100644 docs/tutorial.step_11.ngdoc (limited to 'docs') diff --git a/docs/angular.attrMarkup.ngdoc b/docs/angular.attrMarkup.ngdoc deleted file mode 100644 index aad20866..00000000 --- a/docs/angular.attrMarkup.ngdoc +++ /dev/null @@ -1,15 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.attrMarkup - -@description -Attribute markup extends the angular compiler in a very similar way as {@link angular.markup} except -that it allows you to modify the state of the attribute text rather then the content of a node. - -
-angular.attrMarkup('extraClass', function(attrValue, attrName, element){
-  if (attrName == 'additional-class') {
-    element.addClass(attrValue);
-  }
-});
-
diff --git a/docs/angular.directive.ngdoc b/docs/angular.directive.ngdoc deleted file mode 100644 index 9a08e4c7..00000000 --- a/docs/angular.directive.ngdoc +++ /dev/null @@ -1,53 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.directive -@namespace Namespace for all directives. - -@description -A directive is an HTML attribute that you can use in an existing HTML element type or in a -DOM element type that you create as {@link angular.widget}, to modify that element's -properties. You can use any number of directives per element. - -For example, you can add the ng:bind directive as an attribute of an HTML span element, as in -``. How does this work? The compiler passes the attribute value -`1+2` to the ng:bind extension, which in turn tells the {@link angular.scope} to watch that -expression and report changes. On any change it sets the span text to the expression value. - -Here's how to define {@link angular.directive.ng:bind ng:bind}: -
-  angular.directive('ng:bind', function(expression, compiledElement) {
-    var compiler = this;
-    return function(linkElement) {
-      var currentScope = this;
-      currentScope.$watch(expression, function(value) {
-        linkElement.text(value);
-      });
-    };
-  });
-
- -# Directive vs. Attribute Widget -Both [attribute widgets](#!angular.widget) and directives can compile a DOM element -attribute. So why have two different ways to do the same thing? The answer is that order -matters, but we have no control over the order in which attributes are read. To solve this -we apply attribute widget before the directive. - -For example, consider this piece of HTML, which uses the directives `ng:repeat`, `ng:init`, -and `ng:bind`: -
-  
-
- -Notice that the order of execution matters here. We need to execute -{@link angular.directive.ng:repeat ng:repeat} before we run the -{@link angular.directive.ng:init ng:init} and `ng:bind` on the `
  • ;`. This is because we -want to run the `ng:init="a=a+1` and `ng:bind="person"` once for each person in people. We -could not have used directive to create this template because attributes are read in an -unspecified order and there is no way of guaranteeing that the repeater attribute would -execute first. Using the `ng:repeat` attribute directive ensures that we can transform the -DOM element into a template. - -Widgets run before directives. Widgets may manipulate the DOM whereas directives are not -expected to do so, and so they run last. diff --git a/docs/angular.element.ngdoc b/docs/angular.element.ngdoc deleted file mode 100644 index 2ce007fd..00000000 --- a/docs/angular.element.ngdoc +++ /dev/null @@ -1,49 +0,0 @@ -@workInProgress -@ngdoc function -@name angular.element -@function - -@description -Wraps a raw DOM element or HTML string as [jQuery](http://jquery.com) element. -`angular.element` is either an alias for [jQuery](http://api.jquery.com/jQuery/) function if -jQuery is loaded or a function that wraps the element or string in angular's jQuery lite -implementation. - -Real jQuery always takes precedence (as long as it was loaded before `DOMContentEvent`) - -Angular's jQuery lite implementation is a tiny API-compatible subset of jQuery which allows -angular to manipulate DOM. The jQuery lite implements only a subset of jQuery api, with the -focus on the most commonly needed functionality and minimal footprint. For this reason only a -limited number of jQuery methods, arguments and invocation styles are supported. - -NOTE: All element references in angular are always wrapped with jQuery (lite) and are never -raw DOM references. - -## Angular's jQuery lite implements these functions: - -- [addClass()](http://api.jquery.com/addClass/) -- [after()](http://api.jquery.com/after/) -- [append()](http://api.jquery.com/append/) -- [attr()](http://api.jquery.com/attr/) -- [bind()](http://api.jquery.com/bind/) -- [children()](http://api.jquery.com/children/) -- [clone()](http://api.jquery.com/clone/) -- [css()](http://api.jquery.com/css/) -- [data()](http://api.jquery.com/data/) -- [hasClass()](http://api.jquery.com/hasClass/) -- [parent()](http://api.jquery.com/parent/) -- [remove()](http://api.jquery.com/remove/) -- [removeAttr()](http://api.jquery.com/removeAttr/) -- [removeClass()](http://api.jquery.com/removeClass/) -- [removeData()](http://api.jquery.com/removeData/) -- [replaceWith()](http://api.jquery.com/replaceWith/) -- [text()](http://api.jquery.com/text/) -- [trigger()](http://api.jquery.com/trigger/) - -## Additionally these methods extend the jQuery and are available in both jQuery and jQuery lite -version: - -- `scope()` - retrieves the current angular scope of the element. - -@param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. -@returns {Object} jQuery object. diff --git a/docs/angular.filter.ngdoc b/docs/angular.filter.ngdoc deleted file mode 100644 index 5d4f5940..00000000 --- a/docs/angular.filter.ngdoc +++ /dev/null @@ -1,87 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.filter -@namespace Namespace for all filters. -@description -# Overview -Filters are a standard way to format your data for display to the user. For example, you -might have the number 1234.5678 and would like to display it as US currency: $1,234.57. -Filters allow you to do just that. In addition to transforming the data, filters also modify -the DOM. This allows the filters to for example apply css styles to the filtered output if -certain conditions were met. - - -# Standard Filters - -The Angular framework provides a standard set of filters for common operations, including: -{@link angular.filter.currency currency}, {@link angular.filter.json json}, -{@link angular.filter.number number}, and {@link angular.filter.html html}. You can also add -your own filters. - - -# Syntax - -Filters can be part of any {@link angular.scope} evaluation but are typically used with -{{bindings}}. Filters typically transform the data to a new data type, formating the data in -the process. Filters can be chained and take optional arguments. Here are few examples: - -* 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. To number, the argument “5” requests 5 digits - to the right of the decimal point. - - -# Writing your own Filters - -Writing your own filter is very easy: just define a JavaScript function on `angular.filter`. -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. This allows the filter to manipulate - the DOM in addition to transforming the input. - - -@example - The following example filter reverses a text string. In addition, it conditionally makes the - text upper-case (to demonstrate optional arguments) and assigns color (to demonstrate DOM - modification). - - - - - -
    - No filter: {{text}}
    - Reverse: {{text|reverse}}
    - Reverse + uppercase: {{text|reverse:true}}
    - Reverse + uppercase + blue: {{text|reverse:true:"blue"}} -
    - - it('should reverse text', function(){ - expect(binding('text|reverse')).toEqual('olleh'); - input('text').enter('ABC'); - expect(binding('text|reverse')).toEqual('CBA'); - }); - -
    - - diff --git a/docs/angular.formatter.ngdoc b/docs/angular.formatter.ngdoc deleted file mode 100644 index 4eef190e..00000000 --- a/docs/angular.formatter.ngdoc +++ /dev/null @@ -1,82 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.formatter -@namespace Namespace for all formats. -@description -# Overview -The formatters are responsible for translating user readable text in an input widget to a -data model stored in an application. - -# Writting your own Formatter -Writing your own formatter is easy. Just register a pair of JavaScript functions with -`angular.formatter`. One function for parsing user input text to the stored form, -and one for formatting the stored data to user-visible text. - -Here is an example of a "reverse" formatter: The data is stored in uppercase and in -reverse, while it is displayed in lower case and non-reversed. User edits are -automatically parsed into the internal form and data changes are automatically -formatted to the viewed form. - -
    -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();
    -  }
    -});
    -
    - -@example - - - - - Formatted: - -
    - - Stored: -
    -
    {{data}}
    -
    - - it('should store reverse', function(){ - expect(element('.doc-example-live input:first').val()).toEqual('angular'); - expect(element('.doc-example-live input:last').val()).toEqual('RALUGNA'); - - this.addFutureAction('change to XYZ', function($window, $document, done){ - $document.elements('.doc-example-live input:last').val('XYZ').trigger('change'); - done(); - }); - expect(element('.doc-example-live input:first').val()).toEqual('zyx'); - }); - -
    - diff --git a/docs/angular.markup.ngdoc b/docs/angular.markup.ngdoc deleted file mode 100644 index a40385c8..00000000 --- a/docs/angular.markup.ngdoc +++ /dev/null @@ -1,66 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.markup - -@description -#Overview -Markups allow the angular compiler to transform content of DOM elements or portions of this content -into other text or DOM elements for further compilation. Markup extensions do not themselves produce -linking functions. Think of markup as a way to produce shorthand for a {@link angular.widget widget} - or a {@link angular.directive directive}. - -#`{{}}` (double curly) built-in markup -`{{}}` markup is a built-in markup, which translates the enclosed expression into an -{@link angular.directive.ng:bind ng:bind} directive. It simply transforms - -
    -{{expression}}
    -
    - -to: - -
    -
    -
    - -For example `{{1+2}}` is easier to write and understand than ``. The -expanded elements are then {@link guide.compiler compiled} normally. - -# Custom markup -Let's say you want to define this shorthand for a horizontal rule: `---` for `
    `. - -In other words, this HTML: -
    -header
    ----
    -footer
    -
    - -should translate to: -
    -header
    -
    -footer -
    - -Here's how the angular compiler could be extended to achieve this: -
    -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();
    -  }
    -});
    -
    - -Unlike {@link angular.widget widgets} and {@link angular.directive directives}, in which the -compiler matches the name of handler function to a DOM element or attribute name, for markup 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. diff --git a/docs/angular.ngdoc b/docs/angular.ngdoc deleted file mode 100644 index 3f342d1b..00000000 --- a/docs/angular.ngdoc +++ /dev/null @@ -1,4 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular -@namespace The exported angular namespace. diff --git a/docs/angular.service.ngdoc b/docs/angular.service.ngdoc deleted file mode 100644 index 0d3406e5..00000000 --- a/docs/angular.service.ngdoc +++ /dev/null @@ -1,175 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.service - -@description -# Overview -Services are substituable objects, which are wired together using dependency injection (DI). -Each service could have dependencies (other services), which are passed in constructor. -Because JS is dynamicaly typed language, dependency injection can not use static types -to identify these dependencies, so each service must explicitely define its dependencies. -This is done by `$inject` property. - - -# Built-in services -angular provides a set of services for common operations. These services can be overriden by custom -services if needed. - -Like other core angular variables and identifiers, the built-in services always start with `$`. - - * {@link angular.service.$browser $browser} - * {@link angular.service.$window $window} - * {@link angular.service.$document $document} - * {@link angular.service.$location $location} - * {@link angular.service.$log $log} - * {@link angular.service.$exceptionHandler $exceptionHandler} - * {@link angular.service.$hover $hover} - * {@link angular.service.$invalidWidgets $invalidWidgets} - * {@link angular.service.$route $route} - * {@link angular.service.$xhr $xhr} - * {@link angular.service.$xhr.error $xhr.error} - * {@link angular.service.$xhr.bulk $xhr.bulk} - * {@link angular.service.$xhr.cache $xhr.cache} - * {@link angular.service.$resource $resource} - * {@link angular.service.$cookies $cookies} - * {@link angular.service.$cookieStore $cookieStore} - -# Writing your own custom services -angular provides only set of basic services, so for any nontrivial application it will be necessary -to write one or more custom services. To do so, a factory function that creates a services needs to -be registered with angular's dependency injector. This factory function must return an object - the -service (it is not called with the `new` operator). - -**angular.service** accepts three parameters: - - - `{string} name` - Name of the service. - - `{function()} factory` - Factory function (called just once by DI). - - `{Object} config` - Configuration object with following properties: - - `$inject` - {Array.} - Array of service ids that this service depends on. These - services will be passed as arguments into the factory function in the same order as specified - in the `$inject` array. Defaults to `[]`. - - `$eager` - {boolean} - If true, the service factory will be called and thus, the service will - be instantiated when angular boots. If false, 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. - -angular enables services to participate in 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. - -Here is an example of very simple service. This service requires $window service (it's -passed as a parameter to factory function) and it's just a function. - -This service simple stores all notifications and after third one, it displays all of them by -window alert. -
    -       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']});
    -
    - -And here is a unit test for this service. We use Jasmine spy (mock) instead of real browser's alert. -
    -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"]);
    -});
    -
    - -# Injecting services into controllers -Using services as dependencies for controllers is very similar to using them as dependencies for -another service. - -JavaScript is dynamic language, so DI is not able to figure out which services to inject by -static types (like in static typed languages). Therefore you must specify the service name -by the `$inject` property - it's an array that contains strings with names of services to be -injected. The name must match the id that service has been registered as with angular. -The order of the services in the array matters, because this order 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. -
    -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'];
    -
    - -@example - - - - -
    -

    Let's try this simple notify service, injected into the controller...

    - - -
    -
    - - it('should test service', function(){ - expect(element(':input[name=message]').val()).toEqual('test'); - }); - -
    diff --git a/docs/angular.validator.ngdoc b/docs/angular.validator.ngdoc deleted file mode 100644 index 96b1e76a..00000000 --- a/docs/angular.validator.ngdoc +++ /dev/null @@ -1,77 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.validator -@namespace Namespace for all filters. -@description -# Overview -Validators are a standard way to check the user input against a specific criteria. For -example, you might need to check that an input field contains a well-formed phone number. - -# Syntax -Attach a validator on user input widgets using the `ng:validate` attribute. - - - - Change me: - - - 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/); - }); - - - - -# Writing your own Validators -Writing your own validator is easy. To make a function available as a -validator, just define the JavaScript function on the `angular.validator` -object. passes in the input to validate as the first argument -to your function. Any additional validator arguments are passed in as -additional arguments to your function. - -You can use these variables in the function: - -* `this` — The current scope. -* `this.$element` — The DOM element containing the binding. This allows the filter to manipulate - the DOM in addition to transforming the input. - -In this example we have written a upsTrackingNo validator. -It marks the input text "valid" only when the user enters a well-formed -UPS tracking number. - -@css ng-validation-error - When validation fails, this css class is applied to the binding, making its borders red by - default. - -@example - - - - - - - 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/); - }); - - diff --git a/docs/angular.widget.ngdoc b/docs/angular.widget.ngdoc deleted file mode 100644 index 5fd7b259..00000000 --- a/docs/angular.widget.ngdoc +++ /dev/null @@ -1,78 +0,0 @@ -@workInProgress -@ngdoc overview -@name angular.widget -@namespace Namespace for all widgets. -@description -# Overview -Widgets allow you to create DOM elements that the browser doesn't -already understand. You create the widget in your namespace and -assign it behavior. You can only bind one widget per DOM element -(unlike directives, in which you can use any number per DOM -element). Widgets are expected to manipulate the DOM tree by -adding new elements whereas directives are expected to only modify -element properties. - -Widgets come in two flavors: element and attribute. - -# Element Widget -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. - -
    -<my:watch exp="name"/>
    -
    - -You can implement `my:watch` like this: -
    -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);
    -    });
    -  };
    -});
    -
    - -# Attribute Widget -Let's implement the same widget, but this time as an attribute -that can be added to any existing DOM element. -
    -<div my:watch="name">text</div>
    -
    -You can implement `my:watch` attribute like this: -
    -angular.widget('@my:watch', function(expression, compileElement) {
    -  var compiler = this;
    -  return function(linkElement) {
    -    var currentScope = this;
    -    currentScope.$watch(expression, function(value){
    -      alert(value);
    -    });
    -  };
    -});
    -
    - -@example - - - - - - - - diff --git a/docs/content/api/angular.attrMarkup.ngdoc b/docs/content/api/angular.attrMarkup.ngdoc new file mode 100644 index 00000000..aad20866 --- /dev/null +++ b/docs/content/api/angular.attrMarkup.ngdoc @@ -0,0 +1,15 @@ +@workInProgress +@ngdoc overview +@name angular.attrMarkup + +@description +Attribute markup extends the angular compiler in a very similar way as {@link angular.markup} except +that it allows you to modify the state of the attribute text rather then the content of a node. + +
    +angular.attrMarkup('extraClass', function(attrValue, attrName, element){
    +  if (attrName == 'additional-class') {
    +    element.addClass(attrValue);
    +  }
    +});
    +
    diff --git a/docs/content/api/angular.directive.ngdoc b/docs/content/api/angular.directive.ngdoc new file mode 100644 index 00000000..9a08e4c7 --- /dev/null +++ b/docs/content/api/angular.directive.ngdoc @@ -0,0 +1,53 @@ +@workInProgress +@ngdoc overview +@name angular.directive +@namespace Namespace for all directives. + +@description +A directive is an HTML attribute that you can use in an existing HTML element type or in a +DOM element type that you create as {@link angular.widget}, to modify that element's +properties. You can use any number of directives per element. + +For example, you can add the ng:bind directive as an attribute of an HTML span element, as in +``. How does this work? The compiler passes the attribute value +`1+2` to the ng:bind extension, which in turn tells the {@link angular.scope} to watch that +expression and report changes. On any change it sets the span text to the expression value. + +Here's how to define {@link angular.directive.ng:bind ng:bind}: +
    +  angular.directive('ng:bind', function(expression, compiledElement) {
    +    var compiler = this;
    +    return function(linkElement) {
    +      var currentScope = this;
    +      currentScope.$watch(expression, function(value) {
    +        linkElement.text(value);
    +      });
    +    };
    +  });
    +
    + +# Directive vs. Attribute Widget +Both [attribute widgets](#!angular.widget) and directives can compile a DOM element +attribute. So why have two different ways to do the same thing? The answer is that order +matters, but we have no control over the order in which attributes are read. To solve this +we apply attribute widget before the directive. + +For example, consider this piece of HTML, which uses the directives `ng:repeat`, `ng:init`, +and `ng:bind`: +
    +  
      +
    • +
    +
    + +Notice that the order of execution matters here. We need to execute +{@link angular.directive.ng:repeat ng:repeat} before we run the +{@link angular.directive.ng:init ng:init} and `ng:bind` on the `
  • ;`. This is because we +want to run the `ng:init="a=a+1` and `ng:bind="person"` once for each person in people. We +could not have used directive to create this template because attributes are read in an +unspecified order and there is no way of guaranteeing that the repeater attribute would +execute first. Using the `ng:repeat` attribute directive ensures that we can transform the +DOM element into a template. + +Widgets run before directives. Widgets may manipulate the DOM whereas directives are not +expected to do so, and so they run last. diff --git a/docs/content/api/angular.element.ngdoc b/docs/content/api/angular.element.ngdoc new file mode 100644 index 00000000..2ce007fd --- /dev/null +++ b/docs/content/api/angular.element.ngdoc @@ -0,0 +1,49 @@ +@workInProgress +@ngdoc function +@name angular.element +@function + +@description +Wraps a raw DOM element or HTML string as [jQuery](http://jquery.com) element. +`angular.element` is either an alias for [jQuery](http://api.jquery.com/jQuery/) function if +jQuery is loaded or a function that wraps the element or string in angular's jQuery lite +implementation. + +Real jQuery always takes precedence (as long as it was loaded before `DOMContentEvent`) + +Angular's jQuery lite implementation is a tiny API-compatible subset of jQuery which allows +angular to manipulate DOM. The jQuery lite implements only a subset of jQuery api, with the +focus on the most commonly needed functionality and minimal footprint. For this reason only a +limited number of jQuery methods, arguments and invocation styles are supported. + +NOTE: All element references in angular are always wrapped with jQuery (lite) and are never +raw DOM references. + +## Angular's jQuery lite implements these functions: + +- [addClass()](http://api.jquery.com/addClass/) +- [after()](http://api.jquery.com/after/) +- [append()](http://api.jquery.com/append/) +- [attr()](http://api.jquery.com/attr/) +- [bind()](http://api.jquery.com/bind/) +- [children()](http://api.jquery.com/children/) +- [clone()](http://api.jquery.com/clone/) +- [css()](http://api.jquery.com/css/) +- [data()](http://api.jquery.com/data/) +- [hasClass()](http://api.jquery.com/hasClass/) +- [parent()](http://api.jquery.com/parent/) +- [remove()](http://api.jquery.com/remove/) +- [removeAttr()](http://api.jquery.com/removeAttr/) +- [removeClass()](http://api.jquery.com/removeClass/) +- [removeData()](http://api.jquery.com/removeData/) +- [replaceWith()](http://api.jquery.com/replaceWith/) +- [text()](http://api.jquery.com/text/) +- [trigger()](http://api.jquery.com/trigger/) + +## Additionally these methods extend the jQuery and are available in both jQuery and jQuery lite +version: + +- `scope()` - retrieves the current angular scope of the element. + +@param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. +@returns {Object} jQuery object. diff --git a/docs/content/api/angular.filter.ngdoc b/docs/content/api/angular.filter.ngdoc new file mode 100644 index 00000000..5d4f5940 --- /dev/null +++ b/docs/content/api/angular.filter.ngdoc @@ -0,0 +1,87 @@ +@workInProgress +@ngdoc overview +@name angular.filter +@namespace Namespace for all filters. +@description +# Overview +Filters are a standard way to format your data for display to the user. For example, you +might have the number 1234.5678 and would like to display it as US currency: $1,234.57. +Filters allow you to do just that. In addition to transforming the data, filters also modify +the DOM. This allows the filters to for example apply css styles to the filtered output if +certain conditions were met. + + +# Standard Filters + +The Angular framework provides a standard set of filters for common operations, including: +{@link angular.filter.currency currency}, {@link angular.filter.json json}, +{@link angular.filter.number number}, and {@link angular.filter.html html}. You can also add +your own filters. + + +# Syntax + +Filters can be part of any {@link angular.scope} evaluation but are typically used with +{{bindings}}. Filters typically transform the data to a new data type, formating the data in +the process. Filters can be chained and take optional arguments. Here are few examples: + +* 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. To number, the argument “5” requests 5 digits + to the right of the decimal point. + + +# Writing your own Filters + +Writing your own filter is very easy: just define a JavaScript function on `angular.filter`. +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. This allows the filter to manipulate + the DOM in addition to transforming the input. + + +@example + The following example filter reverses a text string. In addition, it conditionally makes the + text upper-case (to demonstrate optional arguments) and assigns color (to demonstrate DOM + modification). + + + + + +
    + No filter: {{text}}
    + Reverse: {{text|reverse}}
    + Reverse + uppercase: {{text|reverse:true}}
    + Reverse + uppercase + blue: {{text|reverse:true:"blue"}} +
    + + it('should reverse text', function(){ + expect(binding('text|reverse')).toEqual('olleh'); + input('text').enter('ABC'); + expect(binding('text|reverse')).toEqual('CBA'); + }); + +
    + + diff --git a/docs/content/api/angular.formatter.ngdoc b/docs/content/api/angular.formatter.ngdoc new file mode 100644 index 00000000..4eef190e --- /dev/null +++ b/docs/content/api/angular.formatter.ngdoc @@ -0,0 +1,82 @@ +@workInProgress +@ngdoc overview +@name angular.formatter +@namespace Namespace for all formats. +@description +# Overview +The formatters are responsible for translating user readable text in an input widget to a +data model stored in an application. + +# Writting your own Formatter +Writing your own formatter is easy. Just register a pair of JavaScript functions with +`angular.formatter`. One function for parsing user input text to the stored form, +and one for formatting the stored data to user-visible text. + +Here is an example of a "reverse" formatter: The data is stored in uppercase and in +reverse, while it is displayed in lower case and non-reversed. User edits are +automatically parsed into the internal form and data changes are automatically +formatted to the viewed form. + +
    +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();
    +  }
    +});
    +
    + +@example + + + + + Formatted: + +
    + + Stored: +
    +
    {{data}}
    +
    + + it('should store reverse', function(){ + expect(element('.doc-example-live input:first').val()).toEqual('angular'); + expect(element('.doc-example-live input:last').val()).toEqual('RALUGNA'); + + this.addFutureAction('change to XYZ', function($window, $document, done){ + $document.elements('.doc-example-live input:last').val('XYZ').trigger('change'); + done(); + }); + expect(element('.doc-example-live input:first').val()).toEqual('zyx'); + }); + +
    + diff --git a/docs/content/api/angular.markup.ngdoc b/docs/content/api/angular.markup.ngdoc new file mode 100644 index 00000000..a40385c8 --- /dev/null +++ b/docs/content/api/angular.markup.ngdoc @@ -0,0 +1,66 @@ +@workInProgress +@ngdoc overview +@name angular.markup + +@description +#Overview +Markups allow the angular compiler to transform content of DOM elements or portions of this content +into other text or DOM elements for further compilation. Markup extensions do not themselves produce +linking functions. Think of markup as a way to produce shorthand for a {@link angular.widget widget} + or a {@link angular.directive directive}. + +#`{{}}` (double curly) built-in markup +`{{}}` markup is a built-in markup, which translates the enclosed expression into an +{@link angular.directive.ng:bind ng:bind} directive. It simply transforms + +
    +{{expression}}
    +
    + +to: + +
    +
    +
    + +For example `{{1+2}}` is easier to write and understand than ``. The +expanded elements are then {@link guide.compiler compiled} normally. + +# Custom markup +Let's say you want to define this shorthand for a horizontal rule: `---` for `
    `. + +In other words, this HTML: +
    +header
    +---
    +footer
    +
    + +should translate to: +
    +header
    +
    +footer +
    + +Here's how the angular compiler could be extended to achieve this: +
    +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();
    +  }
    +});
    +
    + +Unlike {@link angular.widget widgets} and {@link angular.directive directives}, in which the +compiler matches the name of handler function to a DOM element or attribute name, for markup 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. diff --git a/docs/content/api/angular.ngdoc b/docs/content/api/angular.ngdoc new file mode 100644 index 00000000..3f342d1b --- /dev/null +++ b/docs/content/api/angular.ngdoc @@ -0,0 +1,4 @@ +@workInProgress +@ngdoc overview +@name angular +@namespace The exported angular namespace. diff --git a/docs/content/api/angular.service.ngdoc b/docs/content/api/angular.service.ngdoc new file mode 100644 index 00000000..0d3406e5 --- /dev/null +++ b/docs/content/api/angular.service.ngdoc @@ -0,0 +1,175 @@ +@workInProgress +@ngdoc overview +@name angular.service + +@description +# Overview +Services are substituable objects, which are wired together using dependency injection (DI). +Each service could have dependencies (other services), which are passed in constructor. +Because JS is dynamicaly typed language, dependency injection can not use static types +to identify these dependencies, so each service must explicitely define its dependencies. +This is done by `$inject` property. + + +# Built-in services +angular provides a set of services for common operations. These services can be overriden by custom +services if needed. + +Like other core angular variables and identifiers, the built-in services always start with `$`. + + * {@link angular.service.$browser $browser} + * {@link angular.service.$window $window} + * {@link angular.service.$document $document} + * {@link angular.service.$location $location} + * {@link angular.service.$log $log} + * {@link angular.service.$exceptionHandler $exceptionHandler} + * {@link angular.service.$hover $hover} + * {@link angular.service.$invalidWidgets $invalidWidgets} + * {@link angular.service.$route $route} + * {@link angular.service.$xhr $xhr} + * {@link angular.service.$xhr.error $xhr.error} + * {@link angular.service.$xhr.bulk $xhr.bulk} + * {@link angular.service.$xhr.cache $xhr.cache} + * {@link angular.service.$resource $resource} + * {@link angular.service.$cookies $cookies} + * {@link angular.service.$cookieStore $cookieStore} + +# Writing your own custom services +angular provides only set of basic services, so for any nontrivial application it will be necessary +to write one or more custom services. To do so, a factory function that creates a services needs to +be registered with angular's dependency injector. This factory function must return an object - the +service (it is not called with the `new` operator). + +**angular.service** accepts three parameters: + + - `{string} name` - Name of the service. + - `{function()} factory` - Factory function (called just once by DI). + - `{Object} config` - Configuration object with following properties: + - `$inject` - {Array.} - Array of service ids that this service depends on. These + services will be passed as arguments into the factory function in the same order as specified + in the `$inject` array. Defaults to `[]`. + - `$eager` - {boolean} - If true, the service factory will be called and thus, the service will + be instantiated when angular boots. If false, 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. + +angular enables services to participate in 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. + +Here is an example of very simple service. This service requires $window service (it's +passed as a parameter to factory function) and it's just a function. + +This service simple stores all notifications and after third one, it displays all of them by +window alert. +
    +       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']});
    +
    + +And here is a unit test for this service. We use Jasmine spy (mock) instead of real browser's alert. +
    +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"]);
    +});
    +
    + +# Injecting services into controllers +Using services as dependencies for controllers is very similar to using them as dependencies for +another service. + +JavaScript is dynamic language, so DI is not able to figure out which services to inject by +static types (like in static typed languages). Therefore you must specify the service name +by the `$inject` property - it's an array that contains strings with names of services to be +injected. The name must match the id that service has been registered as with angular. +The order of the services in the array matters, because this order 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. +
    +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'];
    +
    + +@example + + + + +
    +

    Let's try this simple notify service, injected into the controller...

    + + +
    +
    + + it('should test service', function(){ + expect(element(':input[name=message]').val()).toEqual('test'); + }); + +
    diff --git a/docs/content/api/angular.validator.ngdoc b/docs/content/api/angular.validator.ngdoc new file mode 100644 index 00000000..96b1e76a --- /dev/null +++ b/docs/content/api/angular.validator.ngdoc @@ -0,0 +1,77 @@ +@workInProgress +@ngdoc overview +@name angular.validator +@namespace Namespace for all filters. +@description +# Overview +Validators are a standard way to check the user input against a specific criteria. For +example, you might need to check that an input field contains a well-formed phone number. + +# Syntax +Attach a validator on user input widgets using the `ng:validate` attribute. + + + + Change me: + + + 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/); + }); + + + + +# Writing your own Validators +Writing your own validator is easy. To make a function available as a +validator, just define the JavaScript function on the `angular.validator` +object. passes in the input to validate as the first argument +to your function. Any additional validator arguments are passed in as +additional arguments to your function. + +You can use these variables in the function: + +* `this` — The current scope. +* `this.$element` — The DOM element containing the binding. This allows the filter to manipulate + the DOM in addition to transforming the input. + +In this example we have written a upsTrackingNo validator. +It marks the input text "valid" only when the user enters a well-formed +UPS tracking number. + +@css ng-validation-error + When validation fails, this css class is applied to the binding, making its borders red by + default. + +@example + + + + + + + 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/); + }); + + diff --git a/docs/content/api/angular.widget.ngdoc b/docs/content/api/angular.widget.ngdoc new file mode 100644 index 00000000..5fd7b259 --- /dev/null +++ b/docs/content/api/angular.widget.ngdoc @@ -0,0 +1,78 @@ +@workInProgress +@ngdoc overview +@name angular.widget +@namespace Namespace for all widgets. +@description +# Overview +Widgets allow you to create DOM elements that the browser doesn't +already understand. You create the widget in your namespace and +assign it behavior. You can only bind one widget per DOM element +(unlike directives, in which you can use any number per DOM +element). Widgets are expected to manipulate the DOM tree by +adding new elements whereas directives are expected to only modify +element properties. + +Widgets come in two flavors: element and attribute. + +# Element Widget +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. + +
    +<my:watch exp="name"/>
    +
    + +You can implement `my:watch` like this: +
    +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);
    +    });
    +  };
    +});
    +
    + +# Attribute Widget +Let's implement the same widget, but this time as an attribute +that can be added to any existing DOM element. +
    +<div my:watch="name">text</div>
    +
    +You can implement `my:watch` attribute like this: +
    +angular.widget('@my:watch', function(expression, compileElement) {
    +  var compiler = this;
    +  return function(linkElement) {
    +    var currentScope = this;
    +    currentScope.$watch(expression, function(value){
    +      alert(value);
    +    });
    +  };
    +});
    +
    + +@example + + + + + + + + diff --git a/docs/content/cookbook/buzz.ngdoc b/docs/content/cookbook/buzz.ngdoc new file mode 100644 index 00000000..2e82b2d1 --- /dev/null +++ b/docs/content/cookbook/buzz.ngdoc @@ -0,0 +1,63 @@ +@workInProgress +@ngdoc overview +@name Cookbook: Resources - Buzz +@description + +External resources are URLs that provide JSON data, which are then rendered with the help of +templates. angular has a resource factory that can be used to give names to the URLs and then +attach behavior to them. For example you can use the +{@link http://code.google.com/apis/buzz/v1/getting_started.html#background-operations| Google Buzz API} +to retrieve Buzz activity and comments. + + + + +
    + + +
    +
    +

    + + {{item.actor.name}} + + Expand replies: {{item.links.replies[0].count}} + +

    + {{item.object.content | html}} +
    + + {{reply.actor.name}}: + {{reply.content | html}} +
    +
    +
    +
    + + it('fetch buzz and expand', function(){ + element(':button:contains(fetch)').click(); + expect(repeater('div.buzz').count()).toBeGreaterThan(0); + element('.buzz a:contains(Expand replies):first').click(); + expect(repeater('div.reply').count()).toBeGreaterThan(0); + }); + +
    diff --git a/docs/content/cookbook/deeplinking.ngdoc b/docs/content/cookbook/deeplinking.ngdoc new file mode 100644 index 00000000..7d69ee84 --- /dev/null +++ b/docs/content/cookbook/deeplinking.ngdoc @@ -0,0 +1,114 @@ +@workInProgress +@ngdoc overview +@name Cookbook: Deep Linking +@description + +Deep linking allows you to encode the state of the application in the URL so that it can be +bookmarked and the application can be restored from the URL to the same state. + +While does not force you to deal with bookmarks in any particular way, it has services +which make the common case described here very easy to implement. + +# Assumptions + +Your application consists of a single HTML page which bootstraps the application. We will refer +to this page as the chrome. +Your application is divided into several screens (or views) which the user can visit. For example, +the home screen, settings screen, details screen, etc. For each of these screens, we would like to +assign a URL so that it can be bookmarked and later restored. Each of these screens will be +associated with a controller which define the screen's behavior. The most common case is that the +screen will be constructed from an HTML snippet, which we will refer to as the partial. Screens can +have multiple partials, but a single partial is the most common construct. This example makes the +partial boundary visible using a blue line. + +You can make a routing table which shows which URL maps to which partial view template and which +controller. + +# Example + +In this example we have a simple app which consist of two screens: + +* Welcome: url `#` Show the user contact information. +* Settings: url `#/settings` Show an edit screen for user contact information. + + +The two partials are defined in the following URLs: + +* {@link ./examples/settings.html} +* {@link ./examples/welcome.html} + + + + + +
    +

    Your App Chrome

    + [ Welcome | Settings ] +
    + + Partial: {{$route.current.template}} + + + Your app footer +
    +
    + + it('should navigate to URL', function(){ + element('a:contains(Welcome)').click(); + expect(element('ng\\:view').text()).toMatch(/Hello anonymous/); + element('a:contains(Settings)').click(); + input('form.name').enter('yourname'); + element(':button:contains(Save)').click(); + element('a:contains(Welcome)').click(); + expect(element('ng\\:view').text()).toMatch(/Hello yourname/); + }); + +
    + + + +# Things to notice + +* Routes are defined in the `AppCntl` class. The initialization of the controller causes the + initialization of the {@link angular.service.$route $route} service with the proper URL routes. +* The {@link angular.service.$route $route} service then watches the URL and instantiates the + appropriate controller when the URL changes. +* The {@link angular.widget.ng:view ng:view} widget loads the view when the URL changes. It also + sets the view scope to the newly instantiated controller. +* Changing the URL is sufficient to change the controller and view. It makes no difference whether + the URL is changed programatically or by the user. diff --git a/docs/content/cookbook/form.ngdoc b/docs/content/cookbook/form.ngdoc new file mode 100644 index 00000000..c9fd9e9a --- /dev/null +++ b/docs/content/cookbook/form.ngdoc @@ -0,0 +1,103 @@ +@workInProgress +@ngdoc overview +@name Cookbook: Form +@description + +A web application's main purpose is to present and gather data. For this reason angular strives +to make both of these operations trivial. This example shows off how you can build a simple form to +allow a user to enter data. + + + + + +
    + +
    +

    + +
    +
    + , + +

    + + + [ add ] +
    + + + [ X ] +
    +
    + Debug View: +
    user={{user}}
    +
    + +
    + + it('should show debug', function(){ + expect(binding('user')).toMatch(/John Smith/); + }); + it('should add contact', function(){ + using('.example').element('a:contains(add)').click(); + using('.example div:last').input('contact.value').enter('you@example.org'); + expect(binding('user')).toMatch(/\(234\) 555\-1212/); + expect(binding('user')).toMatch(/you@example.org/); + }); + + it('should remove contact', function(){ + using('.example').element('a:contains(X)').click(); + expect(binding('user')).not().toMatch(/\(234\) 555\-1212/); + }); + + it('should validate zip', function(){ + expect(using('.example').element(':input[name=user.address.zip]').attr('className')) + .not().toMatch(/ng-validation-error/); + + using('.example').input('user.address.zip').enter('abc'); + + expect(using('.example').element(':input[name=user.address.zip]').attr('className')) + .toMatch(/ng-validation-error/); + }); + + it('should validate state', function(){ + expect(using('.example').element(':input[name=user.address.state]').attr('className')) + .not().toMatch(/ng-validation-error/); + + using('.example').input('user.address.state').enter('XXX'); + + expect(using('.example').element(':input[name=user.address.state]').attr('className')) + .toMatch(/ng-validation-error/); + }); + +
    + + +# Things to notice + +* The user data model is initialized {@link angular.ng:controller controller} and is available in + the {@link angular.scope scope} with the initial data. +* For debugging purposes we have included a debug view of the model to better understand what + is going on. +* The {@link angular.widget.HTML input widgets} simply refer to the model and are auto bound. +* The inputs {@link angular.validator validate}. (Try leaving them blank or entering non digits + in the zip field) +* In your application you can simply read from or write to the model and the form will be updated. +* By clicking the 'add' link you are adding new items into the `user.contacts` array which are then + reflected in the view. diff --git a/docs/content/cookbook/formadvanced.ngdoc b/docs/content/cookbook/formadvanced.ngdoc new file mode 100644 index 00000000..181dd5e9 --- /dev/null +++ b/docs/content/cookbook/formadvanced.ngdoc @@ -0,0 +1,105 @@ +@workInProgress +@ngdoc overview +@name Cookbook: Advanced Form +@description + +Here we extend the basic form example to include common features such as reverting, dirty state +detection, and preventing invalid form submission. + + + + +
    + +
    +

    + +
    +
    + , + +

    + + + [ add ] +
    + + + [ X ] +
    + + + +
    + Debug View: +
    form={{form}}
    +    master={{master}}
    +
    +
    + + it('should enable save button', function(){ + expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); + input('form.name').enter(''); + expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); + input('form.name').enter('change'); + expect(element(':button:contains(Save)').attr('disabled')).toBeFalsy(); + element(':button:contains(Save)').click(); + expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); + }); + it('should enable cancel button', function(){ + expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy(); + input('form.name').enter('change'); + expect(element(':button:contains(Cancel)').attr('disabled')).toBeFalsy(); + element(':button:contains(Cancel)').click(); + expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy(); + expect(element(':input[name=form.name]').val()).toEqual('John Smith'); + }); + +
    + + +#Things to notice + +* Cancel & save buttons are only enabled if the form is dirty -- there is something to cancel or + save. +* Save button is only enabled if there are no validation errors on the form. +* Cancel reverts the form changes back to original state. +* Save updates the internal model of the form. +* Debug view shows the two models. One presented to the user form and the other being the pristine + copy master. diff --git a/docs/content/cookbook/helloworld.ngdoc b/docs/content/cookbook/helloworld.ngdoc new file mode 100644 index 00000000..ab4c337a --- /dev/null +++ b/docs/content/cookbook/helloworld.ngdoc @@ -0,0 +1,31 @@ +@workInProgress +@ngdoc overview +@name Cookbook: Hello World +@description + + + + Your name: +
    + Hello {{name}}! +
    + + it('should change the binding when user enters text', function(){ + expect(binding('name')).toEqual('World'); + input('name').enter('angular'); + expect(binding('name')).toEqual('angular'); + }); + +
    + +# Things to notice + +Take a look through the source and note: + +* The script tag that {@link guide.bootstrap bootstraps} the angular environment. +* The text {@link angular.widget.HTML input widget} which is bound to the greeting name text. +* No need for listener registration and event firing on change events. +* The implicit presence of the `name` variable which is in the root {@link angular.scope scope}. +* The double curly brace `{{markup}}`, which binds the name variable to the greeting text. +* The concept of {@link guide.data-binding data binding}, which reflects any changes to the + input field in the greeting text. diff --git a/docs/content/cookbook/index.ngdoc b/docs/content/cookbook/index.ngdoc new file mode 100644 index 00000000..7dc937c5 --- /dev/null +++ b/docs/content/cookbook/index.ngdoc @@ -0,0 +1,60 @@ +@workInProgress +@ngdoc overview +@name Cookbook +@description + +Welcome to the angular cookbook. Here we will show you typical uses of angular by example. + + +# Hello World + +{@link cookbook.helloworld Hello World}: The simplest possible application that demonstrates the +classic Hello World! + + +# Basic Form + +{@link cookbook.form Basic Form}: Displaying forms to the user for editing is the bread and butter +of web applications. Angular makes forms easy through bidirectional data binding. + + +# Advanced Form + +{@link cookbook.formadvanced Advanced Form}: Taking the form example to the next level and +providing advanced features such as dirty detection, form reverting and submit disabling if +validation errors exist. + + +# Model View Controller + +{@link cookbook.mvc MVC}: Tic-Tac-Toe: Model View Controller (MVC) is a time-tested design pattern +to separate the behavior (JavaScript controller) from the presentation (HTML view). This +separation aids in maintainability and testability of your project. + + +# Multi-page App and Deep Linking + +{@link cookbook.deeplinking Deep Linking}: An AJAX application never navigates away from the +first page it loads. Instead, it changes the DOM of its single page. Eliminating full-page reloads +is what makes AJAX apps responsive, but it creates a problem in that apps with a single URL +prevent you from emailing links to a particular screen within your application. + +Deep linking tries to solve this by changing the URL anchor without reloading a page, thus +allowing you to send links to specific screens in your app. + + +# Services + +{@link angular.service Services}: Services are long lived objects in your applications that are +available across controllers. A collection of useful services are pre-bundled with angular but you +will likely add your own. Services are initialized using dependency injection, which resolves the +order of initialization. This safeguards you from the perils of global state (a common way to +implement long lived objects). + + +# External Resources + +{@link cookbook.buzz Resources}: Web applications must be able to communicate with the external +services to get and update data. Resources are the abstractions of external URLs which are +specially tailored to angular data binding. + diff --git a/docs/content/cookbook/mvc.ngdoc b/docs/content/cookbook/mvc.ngdoc new file mode 100644 index 00000000..94688547 --- /dev/null +++ b/docs/content/cookbook/mvc.ngdoc @@ -0,0 +1,125 @@ +@workInProgress +@ngdoc overview +@name Cookbook: MVC +@description + +MVC allows for a clean an testable separation between the behavior (controller) and the view +(HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the +view. This makes it very easy for the controller and the view to share the model. + +The model is simply the controller's this. This makes it very easy to test the controller in +isolation since one can simply instantiate the controller and test without a view, because there is +no connection between the controller and the view. + + + + + +

    Tic-Tac-Toe

    +
    + Next Player: {{nextMove}} +
    Player {{winner}} has won!
    + + + + +
    {{cell}}
    + +
    +
    + + it('should play a game', function(){ + piece(1, 1); + expect(binding('nextMove')).toEqual('O'); + piece(3, 1); + expect(binding('nextMove')).toEqual('X'); + piece(1, 2); + piece(3, 2); + piece(1, 3); + expect(element('.winner').text()).toEqual('Player X has won!'); + }); + + function piece(row, col) { + element('.board tr:nth-child('+row+') td:nth-child('+col+')').click(); + } + +
    + + +# Things to notice + +* The controller is defined in JavaScript and has no reference to the rendering logic. +* The controller is instantiated by and injected into the view. +* The controller can be instantiated in isolation (without a view) and the code will still execute. + This makes it very testable. +* The HTML view is a projection of the model. In the above example, the model is stored in the + board variable. +* All of the controller's properties (such as board and nextMove) are available to the view. +* Changing the model changes the view. +* The view can call any controller function. +* In this example, the `setUrl()` and `readUrl()` functions copy the game state to/from the URL's + hash so the browser's back button will undo game steps. See deep-linking. This example calls + {@link angular.Scope.$watch $watch()} to set up a listener that invokes `readUrl()` when needed. 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: + + + + Hello {{'World'}}! + + + +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. + +
    +
    +
    + 
    + 
    + 
    +  Hello {{'World'}}!
    + 
    +
    +
    + +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. + +
    +
    +
    + + +# 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: + +
    +
    +
    + + +# 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 + + +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 + +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 + + + 1+2={{1+2}} + + + it('should calculate expression in binding', function(){ + expect(binding('1+2')).toEqual('3'); + }); + + + +You can try evaluating different expressions here: + + + +
    + Expression: + + +
      +
    • + [ X ] + {{expr}} => +
    • +
    +
    +
    + + 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"]); + }); + +
    + +# 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). + + + +
    + Name: + +
    +
    + + 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'); + }); + +
    + +## 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. + + + +
    + Search: + + + + + + +
    NamePhone
    {{friend.name}}{{friend.phone}}
    +
    + + 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); + + }); + +
    + +## 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 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 , which should display a greeting. + +If we want this HTML source: + +
    +
    + +
    +
    + +To produce this DOM: + +
    +
    + + Hello + World! + +
    +
    + +Write this widget definition (assuming you've already declared the my namespace in the page): + + +
    +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('');
    +    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);
    +    });
    +  };
    +});
    +
    + +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 element set to the salutation class + * Create a 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: + + >
    Error message
    + + + +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: + +
    +
    +
    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}. + +
    +// 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;
    +  }
    +});
    +
    + +At run-time we can access the `uniqueId` service by looking it up with the service locator like +this: + +
    +// 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);
    +
    + +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: + +
    +angular.service('gadgetFactory', function(uniqueId){
    +  return function(){
    +    return {gadgetId: uniqueId()};
    +  };
    +}, {$inject: ['uniqueId']});
    +
    + +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. + +
    +// crate a root scope
    +var rootScope = angular.scope();
    +// accesss the service locator
    +var myService = rootScope.$service('myService');
    +
    + + + +# 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: + +
    +function MyController($route){
    +  // configure the route service
    +  $route.when(...);
    +}
    +MyController.$inject = ['$route'];
    +
    + +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: + +
    +
    +
    + 
    + 
    +  ...
    + 
    +
    +
    + +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. + +
    +MyController.$inject = ['$route'];
    +
    + +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. + +
    +// 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');
    +
    + + +## Creating Controllers using Dependency Injection + +In a typical angular application the dependency injection is most commonly used when creating +controllers. +
    +// 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.
    +
    + + +## 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. + +
    +// 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');
    +
    + + + +# 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: + +
    +function myFn(a,b){}
    +expect(myFn.toString()).toEqual('function myFn(a,b){}');
    +
    + +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: + +
    +// 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'];
    +
    + +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 + + +* What Is Angular? +* The Angular Philosophy +* Anatomy Of An Angular App +* Why You Want Angular +* Angular's Ancestors +* Watch a Presentation About Angular + + + +# 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: + + + +

    Bigg Bike Shop

    +
    + Invoice: +
    +
    + + + + + + + +
    QuantityCost
    +
    + Total: {{qty * cost | currency}} +
    +
    + +
    + +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 + +This ensures angular runs nicely in all major browsers. + +In line __3__ we do two angular setup tasks inside a ` + +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: + 15 Cost: + +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." + + + +# 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): + +
    +Hello
    +
    + +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: + +
    +var label = new Label();
    +label.setText('Hello');
    +label.setClass('label');
    +parent.addChild(label);
    +
    + +That looks like, let's see, do some math, factor out the `
    `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.
    +
    +
    +
    +# 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:
    +
    +
    +
    +
    +
    +# 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.
    +
    +
    +
    +# 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.
    +`Thank You, TB-L!`.
    +
    +## 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.
    +
    +
    +
    +# 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.
    +
    +
    + 
    + 
    + 
    + 
    +
    +
    +{@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...
    diff --git a/docs/content/intro/contribute.ngdoc b/docs/content/intro/contribute.ngdoc
    new file mode 100644
    index 00000000..43d17283
    --- /dev/null
    +++ b/docs/content/intro/contribute.ngdoc
    @@ -0,0 +1,233 @@
    +@ngdoc overview
    +@name Contributing
    +@description
    +
    +
    +# Open Source
    +
    +`Angular` is an open source project licensed under the {@link
    +http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
    +always welcome. When working with `angular` source base, please follow the guidelines provided on
    +this page.
    +
    +* Contributing to Source Code
    +* Applying Code Standards
    +* Checking Out and Building `Angular`
    +* Submitting Your Changes
    +
    +
    +
    +
    +# Contributing to Source Code
    +
    +We'd love for you to contribute to our source code and to make `angular` even better than it is
    +today! Here are the guidelines we'd like you to use:
    +
    +* Major changes that you intend to contribute to the project must be discussed first on our {@link
    +https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
    +coordinate our efforts, prevent  duplication of work, and help you to craft the change so that it
    +is successfully accepted upstream.
    +* Small changes and bug fixes can be crafted and submitted to Github as a pull
    +request.
    +
    +
    +
    +
    +# Applying Code Standards
    +
    +To ensure consistency throughout the source code, keep these rules in mind as you are working:
    +
    +* All features or bug fixes must be tested by one or more specs.
    +* All public API methods must be documented with ngdoc, an extended version of jsdoc (we added
    +support for markdown and templating via `@ngdoc` tag). To see how we document our APIs, please
    +check out the existing ngdocs.
    +* With the exceptions listed below, we follow the rules contained in {@link
    +http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml Google's JavaScript Style
    +Guide}:
    +
    +  * Do not use namespaces: Instead, we wrap the entire `angular` code base in an anonymous closure
    +and export our API explicitly rather than implicitly.
    +  * Wrap all code at 100 characters.
    +  * Instead of complex inheritance hierarchies, we prefer simple objects. We use prototypical
    +inheritance only when absolutely necessary.
    +  * We love functions and closures and, whenever possible, prefer them over objects.
    +  * To write concise code that can be better minified, internally we use aliases that map to the
    +external API. See our existing code to see what we mean.
    +  * We don't go crazy with type annotations for private internal APIs unless it's an internal API
    +that is used throughout `angular`. The best guidance is to do what makes the most sense.
    +
    +
    +
    +# Checking Out and Building Angular
    +
    +The `angular` source code is hosted at {@link http://github.com Github}, which we also use to
    +accept code contributions. Several steps are needed to check out and build `angular`:
    +
    +
    +## Installation Dependencies
    +
    +Before you can build `angular`, you must install or configure the following dependencies on your
    +machine:
    +
    +* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
    +on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
    +Rake website.
    +
    +* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
    +development web server. Depending on your system, you can install Node either from source or as a
    +pre-packaged bundle.
    +
    +* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver
    +JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the
    +`angular` source base, which means there is no need to install or configure it separately.
    +* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
    +quite a good source for information on Git.
    +
    +
    +## Creating a Github Account and Forking Angular
    +
    +To create a Github account, follow the instructions {@link https://github.com/signup/free here}.
    +Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
    +https://github.com/angular/angular.js main angular repository}.
    +
    +
    +## Building `Angular`
    +
    +To build `angular`, you check out the source code and use Rake to generate the non-minified and
    +minified `angular` files:
    +
    +1. To clone your Github repository, run:
    +
    +        git clone git@github.com:/angular.js.git
    +
    +2. To go to the `angular` directory, run:
    +
    +        cd angular.js
    +
    +3. To add the main `angular` repository as an upstream remote to your repository, run:
    +
    +        git remote add upstream https://github.com/angular/angular.js.git
    +
    +4. To build `angular`, run:
    +
    +        rake package
    +
    +The build output can be located under the `build` directory. It consists of the following files and
    +directories:
    +
    +* `angular-x.y.z-.tgz` — This is the complete tarball, which  contains all of the release
    +build artifacts.
    +* `angular.js` — The non-minified `angular` script.
    +* `angular.min.js` —  The minified `angular` script.
    +* `angular-scenario.js` — The `angular` End2End test runner.
    +* `angular-ie-compat.js` —  The Internet Explorer compatibility patch file.
    +* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
    +* `docs/index.html` — The main page for the documentation.
    +* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
    +
    +
    +## Running a Local Development Web Server
    +
    +To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have
    +made available a local web server based on Node.js.
    +
    +1. To start the web server, run:
    +
    +        ./nodeserver.sh
    +
    +2. To access the local server, go to this website:
    +
    +        http://localhost:8000/
    +
    +   By default, it serves the contents of the `angular` project directory.
    +
    +
    +
    +## Running the Unit Test Suite
    +
    +Our unit and integration tests are written with Jasmine and executed with JsTestDriver.  To run the
    +tests:
    +
    +1. To start the JSTD server, run:
    +
    +        ./server.sh
    +
    +2. To capture one or more browsers, go to this website:
    +
    +        http://localhost:9876/
    +
    +3. To trigger a test execution, run:
    +
    +         ./test.sh
    +
    +4. To automatically run the test suite each time one or more of the files in the project directory
    +is changed, you can install `watchr` and then run:
    +
    +        watchr watchr.rb
    +
    +5. To view the output of each test run, you can tail this log file:
    +
    +        ./logs/jstd.log
    +
    +
    +## Running the End2End Test Suite
    +
    +To run the End2End test suite:
    +
    +1. Start the local web server.
    +2. In a browser, go to:
    +
    +        http://localhost:8000/build/docs/docs-scenario.html
    +
    +   The tests are executed automatically.
    +
    +
    +
    +
    +# Submitting Your Changes
    +
    +To create and submit a change:
    +
    +1. Create a new branch off the master for your changes:
    +
    +        git branch my-fix-branch
    +
    +2. Check out the branch:
    +
    +        git checkout my-fix-branch
    +
    +3. Create your patch, make sure to have plenty of tests (that pass).
    +
    +4. Commit your changes:
    +
    +        git commit -a
    +
    +5. Run JavaScript Lint and be sure to address all new warnings and errors:
    +
    +        rake lint
    +
    +6. Push your branch to Github:
    +
    +        git push origin my-fix-branch
    +
    +7. In Github, send a pull request to `angular:master`.
    +
    +8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
    +from the main (upstream) repository:
    +  * To delete the branch in Github, run:
    +
    +            git push origin :my-fix-branch
    +
    +  * To check out the master branch, run:
    +
    +            git checkout master
    +
    +  * To delete a local branch, run:
    +
    +            git branch -D my-fix-branch
    +
    +  * To update your master with the latest upstream version, run:
    +
    +            git pull --ff upstream master
    +
    +That's it! Thank you for your contribution!
    diff --git a/docs/content/intro/downloading.ngdoc b/docs/content/intro/downloading.ngdoc
    new file mode 100644
    index 00000000..a02b3367
    --- /dev/null
    +++ b/docs/content/intro/downloading.ngdoc
    @@ -0,0 +1,70 @@
    +@workInProgress
    +@ngdoc overview
    +@name Downloading
    +@description
    +
    +# Including angular scripts from code.angularjs.org
    +
    +To get started quickly you without worrying about downloading anything and maintaining a local copy,
    +you can point your html `script` tag directly to  urls.
    +
    +There are two kinds of urls you care about:
    +
    +* http://code.angularjs.org/angular-.js
    +* http://code.angularjs.org/angular-.min.js
    +
    +The first one is non-minified version, suitable for web development. The latter one is minified
    +version, which we strongly suggest you use in production.
    +
    +To point your code to let's say angular version 0.9.12, use the following template:
    +
    +
    +  
    +  
    +    
    +      My Angular App
    +      
    +    
    +    
    +    
    +  
    +
    + + +# Downloading and hosting the files on your own + +This options is for those who want to work with angular offline, or want to host the angular files +on their own servers. + +If you navigate to , you'll see a directory listing with all angular +versions since we started releasing versioned build artifacts (quite late in the project lifetime). + +Each directory contains all artifacts that we released for a particular version. Once you navigate +to one of these directories you'll see the following list of files: + +* `angular-.js` - This file is non-obfuscated, non-minified, and human-readable by opening +it it any editor or browser. In order to get better error messages during development, you should +always use this non-minified angular script. + +* `angular-.min.js` - This is a minified and obfuscated version of +`angular-.js` created with Closure compiler. Use this version for production in order to +minimize the size of the application that is downloaded by your user's browser. + +* `angular-.tgz` - This is a tarball archive which contains all the other files released +for this angular version. Use this file to get everything in a single download. + +* `angular-ie-compat-.js` - This is a special file that contains code and data specifically +tailored for getting Internet Explorer to work with angular. If you host your own copy of angular +files, make sure that this file is available for download and resides under the same parent path as +`angular-.js` or `angular-.min.js`. + +* `angular-mocks-.js` - This file contains implementation of mocks that we provide to you +to make testing angular apps even easier. Your unit/integration test harness should load this file +after `angular-.js` is loaded. + +* `angular-scenario-.js` - This file is a very nifty JavaScript file, which allows you to +write and execute end to end tests for angular applications. + +* `docs-` - this directory contains all the files that compose the + documentation app. These files are handy to see the older version of +our docs, or even more importantly, view the docs offline! diff --git a/docs/content/intro/faq.ngdoc b/docs/content/intro/faq.ngdoc new file mode 100644 index 00000000..dd06d961 --- /dev/null +++ b/docs/content/intro/faq.ngdoc @@ -0,0 +1,81 @@ +@workInProgress +@ngdoc overview +@name FAQ +@description + +#FAQ + +### Why is this project called "angular"? Why is the namespace called "ng"? + +Because HTML has angular brackets and "ng" sounds like "angular". + +### Is an HTML5 tag? + +No, is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two +together. + +### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}? + +No, angular is none of these. You don't call its functions, it does not call your functions, +it does not provide a way to manipulate DOM, but does provide primitives to create UI projections +of your data. There are lots of existing widget libraries which you can integrate with angular. +It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers. + +### Do I need to worry about security holes in angular? + +Like with any technology, angular is not impervious to attack. angular does, however, provide +built-in protection from basic security holes including cross-site scripting and HTML injection +attacks. angular does round-trip escaping on all strings for you. + +### Can I download the source, build, and host the angular environment locally? + +Yes. See instructions in {@link downloading downloading}. + +### Is angular a templating system? + +At the highest level, angular does look 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: bidirectional data binding. The template is compiled on the browser and +the compilation step produces a live view. This means you, the developer, don't need to write +code to constantly sync the view with the model and the model with the view as in other +templating systems. + +### What browsers does angular work with? + +Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and +above. Note that CSS only works on IE7 and above. + +### What's angular's performance like? + +angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your +app's performance will vary depending on how many bindings you use. + +### How big is the angular bootstrap JS file that I need to include? + +The size of the library itself is < 50KB compressed and obfuscated. + +### Can I use the open-source Closure Library with angular? + +Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library} +in angular. + +### Does angular use the jQuery library? + +Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library. +If jQuery is not present in your script path, angular falls back on its own implementation of +{@link angular.element jQuery lite}. If jQuery is present in the path, angular uses it to +manipulate the DOM. + +### What is testability like in angular? + +Very testable. It has an integrated dependency injection framework. See +{@link angular.service service} for details. + +### How can I learn more about angular? + +Watch the July 28, 2010 talk +"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building AJAX Apps}". + +### How is angular licensed? + +The MIT License. diff --git a/docs/content/intro/started.ngdoc b/docs/content/intro/started.ngdoc new file mode 100644 index 00000000..a505b471 --- /dev/null +++ b/docs/content/intro/started.ngdoc @@ -0,0 +1,146 @@ +@workInProgress +@ngdoc overview +@name Getting Started +@description + +# Hello World! + +A great way for you to get started with `angular` is to create the tradtional +"Hello World!" app: + +1. In your favorite text editor, create an HTML file + (for example, `helloworld.html`). +2. From the __Source__ box below, copy and paste the code into your HTML file. + (Double-click on the source to easily select all.) +3. Open the file in your web browser. + + + + Hello {{'World'}}! + + + +The resulting web page should look something like the following: + + + +Now let's take a closer look at that code, and see what is going on behind +the scenes. + +The first line of interest defines the `ng` namespace, which makes +`angular` work across all browsers (especially important for IE): + +
    +    
    +
    + +The next line downloads the `angular` script, and instructs `angular` to process +the entire HTML page when it is loaded: + +
    +    
    +
    + +(For details on what happens when `angular` processes an HTML page, +see {@link guide.bootstrap Bootstrap}.) + +Finally, this line in the `` of the page is the template that describes +how to display our greeting in the UI: + +
    +    Hello {{'World'}}!
    +
    + +Note the use of the double curly brace markup (`{{ }}`) to bind the expression to +the greeting text. Here the expression is the string literal 'World'. + +Next let's look at a more interesting example, that uses `angular` to +bind a dynamic expression to our greeting text. + +# Hello World! + +This example demonstrates `angular`'s two-way data binding: + +1. Edit the HTML file you created in the "Hello World!" example above. +2. Replace the contents of `` with the code from the __Source__ box below. +3. Refresh your browswer window. + + + + Your name: +
    + Hello {{yourname}}! +
    +
    + +After the refresh, the page should look something like this: + + + +These are some of the important points to note from this example: + +* The text input {@link angular.widget widget} called `yourname` is bound to a model variable called + `yourname`. +* The double curly braces notation binds the variable `yourname` to the + greeting text. + +* You did not need to explicitly register an event listener or define an event + handler for events! + +Now try typing your name into the input box, and notice the immediate change to +the displayed greeting. This demonstrates the concept of `angular`'s +{@link guide.data-binding bi-directional data binding}. Any changes to the input field are immediately +reflected in the model (one direction), and any changes to the model are +reflected in the greeting text (the other direction). + + +# Anatomy of an `angular` App + +This section describes the 3 parts of an `angular` app, and explains how they +map to the Model-View-Controller design pattern: + +## Templates + +Templates, which you write in HTML and CSS, serve as the View. You add elements, +attributes, and markup to HTML, which serve as instructions to the `angular` +compiler. The `angular` compiler is fully extensible, meaning that with angular +you can build your own declarative language on top of HTML! + +## Application Logic and Behavior + +Application Logic and Behavior, which you define in JavaScript, serve as the +Controller. With `angular` (unlike with standard AJAX applications) you don't +need to write additional listeners or DOM manipulators, because they are built-in. +This feature makes your application logic very easy to write, test, maintain, and +understand. + +## Scope + +The Model consists of one or more JavaScript objects, arrays, or primitive types. +These are referenced from the scope. There are no restrictions on what the Model +can be or what structure it should have. The only requirement is that it is +referenced by the scope. + +The following illustration shows the parts of an `angular` application and how they +work together: + + + +In addition, `angular` comes with a set of Services, which have the following +properties: + +* The services provided are very useful for building web applications. +* You can extend and add application-specific behavior to services. +* Services include Dependency-Injection, XHR, caching, URL routing, + and browser abstraction. + +# Where To Go Next + +* For additional hands-on examples of using `angular`, including more source + code that you can copy and paste into your own pages, take a look through + the `angular` {@link cookbook Cookbook}. + +* For explanations of the `angular` concepts presented in the examples on this + page, see the {@link guide Developer Guide}. diff --git a/docs/content/intro/testimonials.ngdoc b/docs/content/intro/testimonials.ngdoc new file mode 100644 index 00000000..2e333f4b --- /dev/null +++ b/docs/content/intro/testimonials.ngdoc @@ -0,0 +1,33 @@ +@ngdoc overview +@name Testimonials +@description + + +## John Hardy +> Also I want to pass on my compliments to Misko and Igor for this fantastic project. I'm currently +> rewriting a server-side web application to use this system. I am constantly astounded at how much +> simpler it is to do it this way and I still consider myself a learner. + +> This is without question the most productive approach to building webapps that I have seen. + +> The last time I had a coding epiphany was discovering the power and simplicity of JQuery. This is +> way better than that. + +> I'm interested in promoting this library as widely as possible. I understand that you are still +> developing it and I still have a long way to go before I really understand everything but I think +> you really have something here. + + +## Jerry Jeremiah +> angular is the best thing I have used in a long time. I am having so much fun, even thought it is +> probably obvious that dynamic web sites are new to me (my experience is more in the back end +> embedded world...) + + +## Dobrica Pavlinusic +> Thanks to great help I received at this list, I was basically able to accomplish my goal to write +> simple conference submission application within a week of first git clone of angular source from +> github. + +> I think it might be useful to summarize my experience here, especially for people who are still +> wondering if angular is worth a try. Executive summary is: **yes it is!** \ No newline at end of file diff --git a/docs/content/tutorial/index.ngdoc b/docs/content/tutorial/index.ngdoc new file mode 100644 index 00000000..b430b248 --- /dev/null +++ b/docs/content/tutorial/index.ngdoc @@ -0,0 +1,172 @@ +@workInProgress +@ngdoc overview +@name Tutorial +@description + +A great way to get introduced to angular is to work through the {@link tutorial.step_00 angular +tutorial}, which walks you through the construction of an angular web app. The app you will build +in the tutorial is loosely based on the {@link http://www.google.com/phone/ Google phone gallery +app}. The {@link http://angular.github.com/angular-phonecat/step-11/app/ end result of our effort} +is visually simpler, but demonstrates many of the angular features without distractions in the +form of CSS code. + +This tutorial app ends up like a Google phone gallery app, but is originally based on the {@link +https://github.com/angular/angular-seed angular-seed project}. The angular seed app isn't +necessary for building angular apps, but it helps you get started quickly and makes the +development and testing process much easier. Angular-seed includes a simple example, the latest +angular libraries, test libraries, and scripts. It provides all of these in an environment that +is pre-configured for developing a typical web app. + +Once you set up your tutorial environment, you should be able to get through the material in less +than a day and you'll have fun doing it. More experienced coders may be able to zip through the +exercises in an afternoon. In any case, we promise that your time will be well spent! + +When you finish the tutorial you will be able to: + +* Create a simple dynamic application that works in any browser +* Define the differences between angular and common JavaScript frameworks +* Understand angular expressions +* Understand how data binding works in angular +* Use the angular-seed project to quickly boot-strap your own projects +* Create and run tests +* Identify resources for learning more about angular + +You can work through the tutorial in any of the following ways: + +* Using Git. Use the Git versioning system to get the files for each step. +* Using Snapshots. Download snapshots (files for each step of the +tutorial) and tinker with them. +* Reading the Examples. Read through the examples, and inspect +results and code on our server. + +The first two ways (Git and snapshots) give you a fuller experience, in that you can run the unit +and end-to-end tests in addition to the tutorial app. They also give you the ability to play +around with the code and get instant feedback in your browser. The last way (reading through the +tutorial online) requires no setup on your machine, but you can't run the tests, and it won't be +as easy to play around with the code. + + +# Prerequisites for Git and Snapshots + +To run the tutorial app and tests on your machine (using Git or the snapshots) you will need the +following: + +* You need to be running on a Mac or Linux machine. +* An http server running on your system. If you don't already have one installed, you can install +`node.js` ({@link https://github.com/joyent/node/wiki/Installation node.js install}) or another +http sever (such as Apache, etc.). +* Java. This is required for running tests. Angular itself doesn't require Java. +* A modern browser (including IE8+). Needed for viewing and debugging code. +* A text editor of your choice. + + +# Using Git + +The following instructions are for developers who are comfortable with Git's versioning system: + +1. Check to be sure you have all of the prerequisites on your system. + +2. Clone the angular-phonecat repository located at {@link +https://github.com/angular/angular-phonecat angular-phonecat} by running the following command in +a terminal: + + git clone git://github.com/angular/angular-phonecat.git + + This will create a directory called `angular-phonecat`. + +3. In terminal, navigate to the `angular-phonecat` directory and run: + + git checkout step-0 + + (You can run `git checkout step-[0-11]` to go to any of the steps in the tutorial). + +4. To see the app running in a browser, do the following: + * __For node.js users:__ + 1. Run `./scripts/web-server.js` to start the app server. + 2. Open a browser window for the app and navigate to http://localhost:8000/app/index.html. + + * __For other http servers:__ + 1. Configure the server to serve the files in the `angular-phonecat` directory. + 2. Run `./scripts/web-server.js` to start the app server. + 3. Navigate in your browser to + http://localhost:[*port-number*]/[*context-path*]/app/index.html. + +5. To see tests running in a browser, do the following: + * __For node.js users:__ + 1. Run `./scripts/test-server.sh` to start the test web server. + 2. Open a browser window for the tests, navigate to http://localhost:9876, and choose + "strict mode". + * __For other http servers:__ + 1. Configure the server to serve the files in the `angular-phonecat` directory. + 1. Run `./scripts/test-server.sh` to start the test web server. + 3. Navigate in your browser to http://localhost:[*port-number*]/, and choose "strict mode". + + + + +# Using Snapshots + +Snapshots are the sets of files that reflect the state of the tutorial app at each step. These +files include the HTML, CSS, and JavaScript for the app, plus Jasmine JavaScript files and Java +libraries for the test stack. These will let you run the tutorial app and tests, without requiring +knowledge of Git. You can download and install the snapshot files as follows: + +1. Check to be sure you have all of the prerequisites on your system. + +2. Navigate to [*the angular server*], and download and unzip [*the snapshot file*] to an +[*install-dir*] of your choosing. + +3. Change directories to [*install-dir*]/sandbox. + +4. Run the following command: + * `./goto_step.sh 0` + + You have to start out at the beginning, which is Step 0. After you set up Step 0, you can skip + around between any steps. + +1. To see the app running in your browser, do the following: + * __For node.js users:__ + 1. Run `./scripts/web-server.js` to run the web server. + 2. Open a browser window for the app and navigate to http://localhost:8000/app/index.html. + 3. Open a browser window for the tests, navigate to http://localhost:9876, and choose + "strict mode". + + * __For other http servers:__ + 1. Configure servers to serve the app and test files in the [*install-dir*]/sandbox. + 2. Start the server. + 3. Navigate in your app browser to + http://localhost:[*port-number*]/[*context-path*]/app/index.html. + 4. Navigate in your test browser to http://localhost:[*port-number*] and choose "strict + mode". + +1. To view the tutorial app at different steps, run `./goto_step.sh [0-11]` and then refresh your +browser. For example, say you're on Step 5 of the tutorial, and you want to see the app in action: + + 1. Run `goto_step.sh 5` from the command line in the `sandbox` directory. + 1. Refresh your app browser. + + +# Reading the Examples + +If you don't want to set up anything on your local machine, you can read through the tutorial and +inspect the tutorial files on our servers; doing this will give you a good idea of what angular +does, but you won't be able to make any code changes and experiment on your own. + +To see the running app at each tutorial step, click the "Example" link at the top or bottom of +each tutorial page. + +To view the code differences between tutorial steps, click the Code Diff link at top or bottom of +each tutorial page. Additions are highlighted in green; deletions are highlighted in red. + + +# Relative URLs +Throughout the tutorial, we use relative URLs to refer to files hosted on our local http server. +The absolute URL depends on your configuration. For example, if you are using the node.js server, +`app/index.html` translates to: + + http://localhost:8000/app/index.html + +If you are using your own http server running on port 8080 and the tutorial files are hosted at +`/angular_tutorial`, `app/index.html` translates to: + + http://localhost:8080/angular_tutorial/app/index.html diff --git a/docs/content/tutorial/step_00.ngdoc b/docs/content/tutorial/step_00.ngdoc new file mode 100755 index 00000000..e506fcaf --- /dev/null +++ b/docs/content/tutorial/step_00.ngdoc @@ -0,0 +1,77 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 0 +@description + + + + + + + + + +
    {@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-0/app Example}{@link tutorial Tutorial Home}Code Diff{@link tutorial.step_01 Next}
    + +The following sample code is our starting point. It is a static HTML page that displays next to +nothing, but it has everything we need to proceed. You can think of this bit of code as our +prototype template, consisting of basic HTML tags with a pair of angular specific attributes. + +__`app/index.html`:__ +
    +
    +
    +
    +  
    +  my angular app
    +  
    +
    +
    +
    +  Nothing here yet!
    +
    +  
    +
    +
    +
    + +## Discussion: + +Although our app doesn't appear to do anything dynamic, note the following: + +* __... `xmlns:ng="http://angularjs.org"` ...__ This `xmlns` declaration for the `ng` namespace +must be specified if you use XHTML, or if you are targeting IE older than 9 (regardless of whether +you are using XHTML or HTML). + +* __` + + This will download the angular script from the angular server instead of from a local file. + +* To try this code out in your browser, you need to navigate to the step-0 page (you are currently +on Step 0 of the tutorial). If your http server is running, navigate to `app/index.html`. +Remember, this is a relative URL (see the Relative URL section in {@link tutorial Tutorial}). The +browser will display the same thing as you would see if you go to +http://angular.github.com/angular-phonecat/step-0/app (accessible from Example link at the bottom +of the page). + +Now we can move on and add some content to our developing web app. + + + + + + + + + +
    {@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-0/app Example}{@link tutorial Tutorial Home}Code Diff{@link tutorial.step_01 Next}
    diff --git a/docs/content/tutorial/step_01.ngdoc b/docs/content/tutorial/step_01.ngdoc new file mode 100755 index 00000000..e22adc20 --- /dev/null +++ b/docs/content/tutorial/step_01.ngdoc @@ -0,0 +1,88 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 1 +@description + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-1/app Example}{@link tutorial Tutorial Home} +{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}{@link tutorial.step_02 Next}
    + +Now that we have the basic ingredients in place, let's add some basic information about two cell +phones to our app. + +Note: We will usually include only the new code that we added for each step. In this and +subsequent examples, we will leave out code from the previous step that hasn't changed, for +example: + + ... + + ... + +Let's add the following code to `index.html`: + +__`app/index.html`:__ +
    +
    +...
    +  Google Phone Gallery
    +...
    +
    +...
    +  
      +
    • + Nexus S +

      + Fast just got faster with Nexus S. +

      +
    • +
    • + Motorola XOOM™ with Wi-Fi +

      + The Next, Next Generation tablet. +

      +
    • +
    +... +
    + +## Discussion: + +* It's a static web page! We displayed info about two phones! Yay. + +* For those of you playing along at home on your own web servers, did you switch to Step 1 and +refresh your browsers? + + * __{@link tutorial Using Git:}__ + + From your `angular-phonecat` directory, run this command: + + git checkout step-1 + + * __{@link tutorial Using Snapshots:}__ + + From `[install directory]/sandbox`, run this command: + + ./goto_step.sh 1 + +* Now would be a good time to open up `app/index.html` in your browser and see the current state +of our "application". It's not very exciting, but that's ok. + +When you're ready, let's move on and start using some angular features to turn this static page +into a dynamic web app. + + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-1/app Example}{@link tutorial Tutorial Home} +{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}{@link tutorial.step_02 Next}
    diff --git a/docs/content/tutorial/step_02.ngdoc b/docs/content/tutorial/step_02.ngdoc new file mode 100755 index 00000000..50fbd240 --- /dev/null +++ b/docs/content/tutorial/step_02.ngdoc @@ -0,0 +1,137 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 2 +@description + + + + + + + + +
    {@link tutorial.step_01 Previous}{@link http://angular.github.com/angular-phonecat/step-2/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code +Diff}{@link tutorial.step_03 Next}
    + +In the last step, we remembered what a basic, static web page looks like, and now we want to get +dynamic. There are many ways to do this, but an important feature of angular is the incorporation +of the principles behind {@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design +pattern} into client-side web apps. With that in mind, let's use a little angular and a little +JavaScript to add Model, View, and Controller components to our app, and change the static page +into one that is dynamically generated. + +Our __View__ component is constructed by angular from this template: + +__`app/index.html`:__ +
    +...
    +
    +
    +  
      +
    • + {{phone.name}} +

      {{phone.snippet}}

      +
    • +
    + + + + +... +
    + +Our data __Model__ (a short list of phones in object literal notation) is instantiated within our +__Controller__ function (`PhoneListCtrl`): + +__`app/js/controllers.js`:__ +
    +/* App Controllers */
    +
    +function PhoneListCtrl() {
    +  this.phones = [{"name": "Nexus S",
    +                  "snippet": "Fast just got faster with Nexus S."},
    +                 {"name": "Motorola XOOM™ with Wi-Fi",
    +                  "snippet": "The Next, Next Generation tablet."},
    +                 {"name": "MOTOROLA XOOM™",
    +                  "snippet": "The Next, Next Generation tablet."}];
    +}
    +
    + +The "Angular way" urges us to test as we develop: + +__`test/unit/controllersSpec.js`:__ +
    +/* jasmine specs for controllers go here */
    +describe('PhoneCat controllers', function() {
    +
    +  describe('PhoneListCtrl', function(){
    +
    +    it('should create "phones" model with 3 phones', function() {
    +      var ctrl = new PhoneListCtrl();
    +      expect(ctrl.phones.length).toBe(3);
    +    });
    +  });
    +});
    +
    + +## Discussion: + +So what were our changes from Step 1? + +* __View template:__ We replaced the hard-coded phone list with the {@link +angular.widget.@ng:repeat ng:repeat widget} and two {@link guide.expression angular expressions} +enclosed in curly braces: `{{phone.name}}` and `{{phone.snippet}}`: + + * The `ng:repeat="phone in phones"` statement in the `
  • ` tag is an angular repeater. It + tells angular to create a `
  • ` element for each phone in the phones list, using the first + `
  • ` tag as the template. + + * The curly braces around `phone.name` and `phone.snippet` are an example of {@link + angular.markup angular markup}. The curly braces are shorthand for the angular directive + {@link angular.directive.ng:bind ng:bind}. They indicate to angular that these are template + binding points. Binding points are locations in the template where angular creates + data-binding between the View and the Model. In angular, the View is a projection of the Model + through the HTML template. This means that whenever the model changes, angular refreshes the + appropriate binding points, which updates the view. + +* __Controller:__ At this point, it doesn't appear as if our controller is doing very much +controlling, but it is playing a crucial role: providing context for our data model so we can +establish data-binding between the model and the view. Note in the following how we connected the +dots between our presentation, data, and logic components: + + * The name of our controller function (in the JavaScript file `controllers.js`) matches the + {@link angular.directive.ng:controller ng:controller} directive in the `` tag + (`PhoneListCtrl`). + * We instantiated our data within the scope of our controller function, and our template + binding points are located within the block bounded by the ` + + {@link tutorial.step_01 Previous} + {@link http://angular.github.com/angular-phonecat/step-2/app Example} + {@link tutorial Tutorial Home} +{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code +Diff} + {@link tutorial.step_03 Next} + + diff --git a/docs/content/tutorial/step_03.ngdoc b/docs/content/tutorial/step_03.ngdoc new file mode 100755 index 00000000..4333636d --- /dev/null +++ b/docs/content/tutorial/step_03.ngdoc @@ -0,0 +1,108 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 3 +@description + + + + + + + + +
    {@link tutorial.step_02 Previous}{@link http://angular.github.com/angular-phonecat/step-3/app Example}{@link tutorial Tutorial Home}{@link + https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code + Diff}{@link tutorial.step_04 Next}
    + +We did a lot of work in laying the foundation of our app in the last step, so now we'll do +something simple, and add full text search. We will also write an end-to-end test, because a good +end-to-end test is a good friend. It stays with your app, keeps an eye on it, and quickly detects +regressions. + +__`app/index.html`:__ +
    +...
    +   Fulltext Search: 
    +
    +  
      +
    • + {{phone.name}} +

      {{phone.snippet}}

      +
    • +
    +... +
    +__`test/e2e/scenarios.js`:__ +
    +/* jasmine-like end2end tests go here */
    +describe('PhoneCat App', function() {
    +
    +  describe('Phone list view', function() {
    +
    +    beforeEach(function() {
    +      browser().navigateTo('../../app/index.html');
    +    });
    +
    +
    +    it('should filter the phone list as user types into the search box', function() {
    +      expect(repeater('.phones li').count()).toBe(3);
    +
    +      input('query').enter('nexus');
    +      expect(repeater('.phones li').count()).toBe(1);
    +
    +      input('query').enter('motorola');
    +      expect(repeater('.phones li').count()).toBe(2);
    +    });
    +  });
    +});
    +
    + +## Discussion: + +We continued using the same controller that we set up in Step 2, but we added the following +features to our app: + +* __Search Box:__ A standard HTML `` tag combined with angular's {@link +angular.Array.filter $filter} utility (added to the repeater) lets a user type in search criteria +and immediately see the effects of their search on the phone list. This new code demonstrates the +following: + + * Two way Data-binding. This is one of the core features in angular. When the page loads, + angular binds the name of the input box to a variable of the same name in the data model and + keeps the two in sync. + +In this example, the data that you type into the input box (named __`query`__) is immediately +available as a filter input in the list repeater (`phone in phones.$filter(`__`query`__`)`). +Whenever the data model changes and this change causes the input to the repeater to change, the +repeater will efficiently update the DOM to reflect the current state of the model. + + * Use of `$filter` in a template. The `$filter` function is one of several built-in {@link + angular.Array angular functions} that augment JavaScript arrays during their evaluation as + angular expressions. In {@link guide.expression angular expressions}, these array utilities are + available as array methods. (They are prefixed with a $ to avoid naming collisions.) + + * `ng:repeat` automatically shrinks and grows the number of phones in the View, via DOM + manipulation that is completely transparent to the developer. If you've written any DOM + manipulation code, this should make you happy. + +* __CSS:__ We added in some minimal CSS to the file we set up in Step 0: `./css/app.css`. + +* __Testing:__ To run the end to end test, open http://localhost:8000/test/e2e/runner.html in +your browser. This end-to-end test shows the following: + + * Proof that the search box and the repeater are correctly wired together. + + * How easy it is to write end-to-end tests. This is just a simple test, but the point here is + to show how easy it is to set up a functional, readable, end-to-end test. + + + + + + + + + +
    {@link tutorial.step_02 Previous}{@link http://angular.github.com/angular-phonecat/step-3/app Example}{@link tutorial Tutorial Home}{@link + https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code + Diff}{@link tutorial.step_04 Next}
    diff --git a/docs/content/tutorial/step_04.ngdoc b/docs/content/tutorial/step_04.ngdoc new file mode 100755 index 00000000..0589ba75 --- /dev/null +++ b/docs/content/tutorial/step_04.ngdoc @@ -0,0 +1,161 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 4 +@description + + + + + + + + +
    {@link tutorial.step_03 Previous}{@link http://angular.github.com/angular-phonecat/step-4/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-3...step-4 Code +Diff}{@link tutorial.step_05 Next}
    + +In this step, we add a feature that lets our users choose which way to order the phone list. + +__`app/index.html`:__ +
    +...
    +  
      +
    • + Search: +
    • +
    • + Sort by: + +
    • +
    + +
      +
    • + {{phone.name}} +

      {{phone.snippet}}

      +
    • +
    +... +
    + +__`app/js/controller.js`:__ +
    +/* App Controllers */
    +
    +function PhoneListCtrl() {
    +  this.phones = [{"name": "Nexus S",
    +                  "snippet": "Fast just got faster with Nexus S.",
    +                  "age": 0},
    +                 {"name": "Motorola XOOM™ with Wi-Fi",
    +                  "snippet": "The Next, Next Generation tablet.",
    +                  "age": 1},
    +                 {"name": "MOTOROLA XOOM™",
    +                  "snippet": "The Next, Next Generation tablet.",
    +                  "age": 2}];
    +
    +  this.orderProp = 'age';
    +}
    +
    + +__`test/unit/controllerSpec.js`:__ +
    +/* jasmine specs for controllers go here */
    +describe('PhoneCat controllers', function() {
    +
    +  describe('PhoneListCtrl', function(){
    +    var scope, $browser, ctrl;
    +
    +    beforeEach(function() {
    +      ctrl = new PhoneListCtrl();
    +    });
    +
    +
    +    it('should create "phones" model with 3 phones', function() {
    +      expect(ctrl.phones.length).toBe(3);
    +    });
    +
    +
    +    it('should set the default value of orderProp model', function() {
    +      expect(ctrl.orderProp).toBe('age');
    +    });
    +  });
    +});
    +
    + +__`test/e2e/scenarios.js`:__ +
    +/* jasmine-like end2end tests go here */
    +describe('PhoneCat App', function() {
    +
    +  describe('Phone list view', function() {
    +
    +    beforeEach(function() {
    +      browser().navigateTo('../../app/index.html');
    +    });
    +
    +
    +    it('should filter the phone list as user types into the search box', function() {
    +      expect(repeater('.phones li').count()).toBe(3);
    +
    +      input('query').enter('nexus');
    +      expect(repeater('.phones li').count()).toBe(1);
    +
    +      input('query').enter('motorola');
    +      expect(repeater('.phones li').count()).toBe(2);
    +    });
    +
    +
    +    it('should be possible to control phone order via the drop down select box', function() {
    +      input('query').enter('tablet'); //let's narrow the dataset to make the test assertions
    +      shorter
    +
    +      expect(repeater('.phones li', 'Phone List').column('a')).
    +          toEqual(["Motorola XOOM\u2122 with Wi-Fi",
    +                   "MOTOROLA XOOM\u2122"]);
    +
    +      select('orderProp').option('alphabetical');
    +
    +      expect(repeater('.phones li', 'Phone List').column('a')).
    +          toEqual(["MOTOROLA XOOM\u2122",
    +                   "Motorola XOOM\u2122 with Wi-Fi"]);
    +    });
    +  });
    +});
    +
    + +## Discussion: + +To provide dynamic ordering, we employ another one of angular's "array type augmenters" and let +the data binding do the rest of the work for us: + +* First, we provide a ` +
  • +
  • + Sort by: + +
  • + + + +... +
    + +__`app/js/controller.js`__ (Unchanged): +
    +/* App Controllers */
    +
    +function PhoneListCtrl($xhr) {
    +  var self = this;
    +
    +  $xhr('GET', 'phones/phones.json', function(code, response) {
    +    self.phones = response;
    +  });
    +
    +  self.orderProp = 'age';
    +}
    +
    +//PhoneListCtrl.$inject = ['$xhr'];
    +
    + +__`app/phones/phones.json`__ (sample snippet): +
    + [
    +  {
    +   "age": 4,
    +   ...
    +   "carrier": "T-Mobile",
    +   "id": "motorola-defy-with-motoblur",
    +   "imageUrl": "http://google.com/phone/image/small/640001",
    +   "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
    +   "snippet": "Are you ready for everything life throws your way?"
    +  },
    +  …
    + ]
    +
    + +__`test/e2e/scenarios.js`__: +
    +...
    +    it('should render phone specific links', function() {
    +      input('query').enter('nexus');
    +      element('.phones li a').click();
    +      expect(browser().location().hash()).toBe('/phones/nexus-s');
    +    });
    +...
    +
    + +## Discussion: + +* Note that we're using {@link guide.expression angular expressions} enclosed in the now-familiar +{@link angular.markup double-curly brace markup} in the href attribute values. These represent +attribute bindings, and work the same way as the bindings we saw in previous steps. + +* Note also the use of the {@link angular.directive.ng:src ng:src} directive in the `` tag. +That directive prevents the browser from treating the angular `{{ exppression }}` markup +literally, as it would do if we tried to use markup in a regular `src` attribute. Use `ng:src` to +keep the browser from eagerly making an extra http request to an invalid location. + +* We expanded our end-to-end test to verify that the app is generating correct links to the phone +views we will implement in the upcoming steps. + + + + + + + + + +
    {@link tutorial.step_05 Previous}{@link http://angular.github.com/angular-phonecat/step-6/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-5...step-6 Code +Diff}{@link tutorial.step_07 Next}
    diff --git a/docs/content/tutorial/step_07.ngdoc b/docs/content/tutorial/step_07.ngdoc new file mode 100755 index 00000000..802130c5 --- /dev/null +++ b/docs/content/tutorial/step_07.ngdoc @@ -0,0 +1,181 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 7 +@description + + + + + + + + +
    {@link tutorial.step_06 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code +Diff}{@link tutorial.step_08 Next}
    + +Our app is slowly growing and becoming more complex. Up until now, the app provided our users with +just one view (the list of all phones), and all of our template code was located in the +`index.html` file. The next step in building our app is the addition of a view that will show +detailed information about each of the devices in our list. + +To add the detailed view, we could expand the `index.html` file to contain template code for both +views, but that would get messy very quickly. Instead, we are going to turn the `index.html` +template into what we call a "layout template". This is a template that is common for all views in +our application. Other "partial templates" are then included into this layout template depending +on the current "route" — the view that is currently displayed to the user. + +Similarly as with templates, angular also allows for controllers and scopes managed by these +controllers to be nested. We are going to create a "root" controller called `PhoneCatCtrl`, which +will contain the declaration of routes for the application. + +Application routes in angular are declared via the {@link angular.service.$route $route} service. +This services makes it easy to wire together controllers, View templates, and the current URL +location in the browser. Using this feature we can implement {@link +http://en.wikipedia.org/wiki/Deep_linking deep linking}, which lets us utilize the browser's +History, and Back and Forward browser navigation. + +We'll use the $route service to declare that our application consists of two different views: one +view presents the phone listing, and the other view presents the details for a particular phone. +Each view will have the template stored in a separate file in the `app/partials/` directory. +Similarly each view will have a controller associated with it. These will be stored in the +existing `app/js/controllers.js` file. + +The `$route` service is usually used in conjunction with the {@link angular.widget.ng:view +ng:view} widget. The role of the `ng:view` widget is to include the view template for the current +route into the layout template, which makes it a perfect fit for our `index.html` template. + +For now we are going to get all the routing going, and move the phone listing template into a +separate file. We'll save the implementation of the phone details View for the next step. + +__`app/index.html`:__ +
    +...
    +
    +
    +  
    +
    +  
    +  
    +
    +
    +
    + +__`app/partials/phone-list.html`:__ +
    +
      +
    • + Search: +
    • +
    • + Sort by: + +
    • +
    + + +
    + +__`app/partials/phone-list.html`:__ +
    +TBD: detail view for {{params.phoneId}}
    +
    + +__`app/js/controller.js`:__ +
    +/* App Controllers */
    +
    +function PhoneCatCtrl($route) {
    +  var self = this;
    +
    +  $route.when('/phones',
    +              {template: 'partials/phone-list.html',   controller: PhoneListCtrl});
    +  $route.when('/phones/:phoneId',
    +              {template: 'partials/phone-detail.html', controller: PhoneDetailCtrl});
    +  $route.otherwise({redirectTo: '/phones'});
    +
    +  $route.onChange(function(){
    +    self.params = $route.current.params;
    +  });
    +
    +  $route.parent(this);
    +}
    +
    +//PhoneCatCtrl.$inject = ['$route'];
    +
    +
    +function PhoneListCtrl($xhr) {
    +  var self = this;
    +
    +  $xhr('GET', 'phones/phones.json', function(code, response) {
    +    self.phones = response;
    +  });
    +
    +  self.orderProp = 'age';
    +}
    +
    +//PhoneListCtrl.$inject = ['$xhr'];
    +
    +
    +function PhoneDetailCtrl() {}
    +
    + +## Discussion: + +* __The View.__ Our View template in `index.html` has been reduced down to this: +``. As described above, it is now a "layout template". We added the following +two new View templates: + + * `app/partials/phone-list.html` for the phone list. The phone-list view was formerly our + main view. We simply moved the code from `index.html` to here. + + * `app/partials/phone-detail.html` for the phone details (just a placeholder template for now). + +* __The Controller(s).__ We now have a new root controller (`PhoneCatCtrl`) and two +sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`). These inherit the model properties and +behavior from the root controller. + + * __`$route.`__ The root controller's job now is to set up the `$route` configuration: + + * When the fragment part of the URL in the browser ends in "/phones", `$route` service + grabs the `phone-list.html` template, compiles it, and links it with a new scope that is + controlled by our `PhoneListCtrl` controller. + + * When the URL ends in "/phones/:phoneId", `$route` compiles and links the + `phone-detail.html` template as it did with `phone-list.html`. But note the use of the + `:phoneId` parameter declaration in the `path` argument of `$route.when()`: `$route` + services provides all the values for variables defined in this way as + `$route.current.params` map. In our route, `$route.current.params.phoneId` always holds + the current contents of the `:phoneId` portion of the URL. We will use the `phoneId` + parameter when we fetch the phone details in Step 8. + + * Any other URL fragment gets redirected to `/phones`. + + * __Controller/Scope inheritance.__ In the function passed into `$route`'s `onChange()` + method, we copied url parameters extracted from the current route to the `params` property in + the root scope. This property is inherited by child scopes created for our view controllers + and accessible by these controllers. + + * __Tests.__ To automatically verify that everything is wired properly, we write end to end + tests that navigate to various URLs and verify that the correct view was rendered. + + + + + + + + + +
    {@link tutorial.step_06 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code +Diff}{@link tutorial.step_08 Next}
    diff --git a/docs/content/tutorial/step_08.ngdoc b/docs/content/tutorial/step_08.ngdoc new file mode 100755 index 00000000..65ce6883 --- /dev/null +++ b/docs/content/tutorial/step_08.ngdoc @@ -0,0 +1,148 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 8 +@description + + + + + + + + +
    {@link tutorial.step_07 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code +Diff}{@link tutorial.step_09 Next}
    + +In this step, we implement the Phone Details View template. Once again we will use {@link +angular.services.$xhr $xhr} to fetch our data, and we'll flesh out the `phone-details.html` View +template. + +__`app/partials/phone-details.html`:__ +
    +
    +
    +

    {{phone.name}}

    + +

    {{phone.description}}

    + +
      +
    • + +
    • +
    + +
      +
    • + Availability and Networks +
      +
      Availability
      +
      {{availability}}
      +
      +
    • + ... + + Additional Features +
      {{phone.additionalFeatures}}
      + +
    +
    + +__`app/js/controller.js`:__ +
    +function PhoneCatCtrl($route) (same as Step 7)
    +
    +function PhoneListCtrl($xhr) (same as Step 7)
    +
    +function PhoneDetailCtrl($xhr) {
    +  var self = this;
    +
    +  $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
    +    self.phone = response;
    +  });
    +}
    +
    +//PhoneDetailCtrl.$inject = ['$xhr'];
    +
    + +__`app/phones/nexus-s.json`:__ (sample snippet) +
    +{
    +  "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope,
    +  Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)",
    +  "android": {
    +      "os": "Android 2.3",
    +      "ui": "Android"
    +  },
    +  ...
    +  "images": [
    +      "img/phones/nexus-s.0.jpg",
    +      "img/phones/nexus-s.1.jpg",
    +      "img/phones/nexus-s.2.jpg",
    +      "img/phones/nexus-s.3.jpg"
    +  ],
    +  "storage": {
    +      "flash": "16384MB",
    +      "ram": "512MB"
    +  }
    +}
    +
    + +__`test/unit/controllerSpec.js`:__ +
    +...
    +    it('should fetch phone detail', function(){
    +      scope.params = {phoneId:'xyz'};
    +      $browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
    +      ctrl = scope.$new(PhoneDetailCtrl);
    +
    +      expect(ctrl.phone).toBeUndefined();
    +      $browser.xhr.flush();
    +
    +      expect(ctrl.phone).toEqual({name:'phone xyz'});
    +    });
    +...
    +
    + +__`test/e2e/scenarios.js`:__ +
    +...
    +  describe('Phone detail view', function() {
    +
    +    beforeEach(function() {
    +      browser().navigateTo('../../app/index.html#/phones/nexus-s');
    +    });
    +
    +
    +    it('should display nexus-s page', function() {
    +      expect(binding('phone.name')).toBe('Nexus S');
    +    });
    +  });
    +...
    +
    + +## Discussion: + +* Phone Details View Template. There is nothing fancy or new here, just note where we use the +angular `{{ expression }}` markup and directives to project phone data from our model into the +view. + +* Note how we used the `$route` `params` object from the scope managed by the root controller +(`PhoneCatCtrl`), to construct the path for the phone details xhr request. The rest of this step +is simply applying the previously learned concepts and angular APIs to create a large template +that displays a lot of data about a phone. + +* Tests. We updated the existing end to end test and wrote a new unit test that is similar in +spirit to the one we wrote for the `PhoneListCtrl` controller. + + + + + + + + + +
    {@link tutorial.step_07 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code +Diff}{@link tutorial.step_09 Next}
    diff --git a/docs/content/tutorial/step_09.ngdoc b/docs/content/tutorial/step_09.ngdoc new file mode 100755 index 00000000..2d6ed925 --- /dev/null +++ b/docs/content/tutorial/step_09.ngdoc @@ -0,0 +1,108 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 9 +@description + + + + + + + + +
    {@link tutorial.step_08 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code +Diff}{@link tutorial.step_10 Next}
    + +In this step, we have determined that the built-in angular display filters ({@link +angular.filter.number number}, {@link angular.filter.currency currency}, {@link +angular.filter.date date}, etc.) don't handle what we want to do, so we get to create our own +custom {@link angular.filter filter}. + +In the previous step, the details page displayed either "true" or "false" to indicate whether +certain phone features were present or not. Our custom "checkmark" filter replaces those text +strings with glyphs: ✓ for "true", and ✘ for "false". + +Our filter code lives in `app/js/filters.js`: + +__`app/index.html`:__ +
    +...
    + 
    + 
    + 
    +...
    +
    + +In the phone details template, we employ our filter for angular expressions whose values are +"true" or "false"; `{{ [phone_feature] | checkmark }}`: + +__`app/partials/phone-detail.html`:__ +
    +
    +

    {{phone.name}}

    +

    {{phone.description}}

    +... +
      + ... +
    • + Connectivity +
      +
      Network Support
      +
      {{phone.connectivity.cell}}
      +
      WiFi
      +
      {{phone.connectivity.wifi}}
      +
      Bluetooth
      +
      {{phone.connectivity.bluetooth}}
      +
      Infrared
      +
      {{phone.connectivity.infrared | checkmark}}
      +
      GPS
      +
      {{phone.connectivity.gps | checkmark}}
      +
      +
    • +... +
    +
    + +__`app/js/filters.js`:__ (New) +
    +angular.filter('checkmark', function(input) {
    +  return input ? '\u2713' : '\u2718';
    +});
    +
    + +__`test/unit/filtersSpec.js`:__ (New) +
    +describe('checkmark filter', function() {
    +
    +  it('should convert boolean values to unicode checkmark or cross', function() {
    +    expect(angular.filter.checkmark(true)).toBe('\u2713');
    +    expect(angular.filter.checkmark(false)).toBe('\u2718');
    +  });
    +})
    +
    + +## Discussion: + +* This example shows how easy it is to roll your own filters for displaying data. As explained in +the "Writing your own Filters" section of the {@link angular.filter angular.filter} page, you +simply register your custom filter function on to the `angular.filter` function. + +* In this example, our filter name is "checkmark"; our input is either "true" or "false", and we +return one of two unicode characters we have chosen to represent true or false (`\u2713` and +`\u2718`). + +* We created a new unit test to verify that our custom filter converts boolean values to unicode +characters. + + + + + + + + + +
    {@link tutorial.step_08 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code +Diff}{@link tutorial.step_10 Next}
    diff --git a/docs/content/tutorial/step_10.ngdoc b/docs/content/tutorial/step_10.ngdoc new file mode 100644 index 00000000..130b4023 --- /dev/null +++ b/docs/content/tutorial/step_10.ngdoc @@ -0,0 +1,110 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 10 +@description + + + + + + + + +
    {@link tutorial.step_09 Previous}{@link http://angular.github.com/angular-phonecat/step-10/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-9...step-10 +Code Diff}{@link tutorial.step_11 Next}
    + +The phone details view displays one large image of the current phone and several smaller thumbnail +images. It would be great if we could replace the large image with any of the thumbnails just by +clicking on the desired thumbnail image. Let's have a look how we can do this with angular. + +__`app/partials/phone-detail.html`:__ +
    +
    +
    +

    {{phone.name}}

    + +

    {{phone.description}}

    + +
      +
    • + +
    • +
    +... +
    + +__`app/js/controllers.js`:__ +
    +...
    +function PhoneDetailCtrl($xhr) {
    +  var self = this;
    +
    +  $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
    +    self.phone = response;
    +    self.mainImageUrl = response.images[0];
    +  });
    +
    +  self.setImage = function(imageUrl) {
    +    self.mainImageUrl = imageUrl;
    +  }
    +}
    +
    +//PhoneDetailCtrl.$inject = ['$xhr'];
    +
    + +__`test/e2e/scenarios.js`:__ +
    +/* jasmine-like end2end tests go here */
    +...
    +  describe('Phone detail view', function() {
    +
    +    beforeEach(function() {
    +      browser().navigateTo('../../app/index.html#/phones/nexus-s');
    +    });
    +
    +
    +    it('should display nexus-s page', function() {
    +      expect(binding('phone.name')).toBe('Nexus S');
    +    });
    +
    +    it('should display the first phone image as the main phone image', function() {
    +       expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
    +    });
    +
    +
    +    it('should swap main image if a thumbnail image is clicked on', function() {
    +      element('.phone-thumbs li:nth-child(3) img').click();
    +      expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.2.jpg');
    +
    +      element('.phone-thumbs li:nth-child(1) img').click();
    +      expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
    +    });
    +  });
    +});
    +
    + +## Discussion: + +Adding the phone image swapping feature is fairly straightforward: + +* We defined the `mainImageUrl` model property in the details controller (`PhoneDetailCtrl`) and +set the default value of `mainImageUrl` to the first image in the array of images. +* We created a `setImage` controller method to change `mainImageUrl` to the image clicked on by +the user. +* We registered an `{@link angular.directive.ng:click ng:click}` handler for thumb images to use +the `setImage` controller method. +* We expanded the end-to-end test to verify that our new feature is swapping images correctly. + + + + + + + + + + +
    {@link tutorial.step_09 Previous}{@link http://angular.github.com/angular-phonecat/step-10/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-9...step-10 +Code Diff}{@link tutorial.step_11 Next}
    diff --git a/docs/content/tutorial/step_11.ngdoc b/docs/content/tutorial/step_11.ngdoc new file mode 100644 index 00000000..e383f406 --- /dev/null +++ b/docs/content/tutorial/step_11.ngdoc @@ -0,0 +1,178 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 11 +@description + + + + + + + + +
    {@link tutorial.step_10 Previous}{@link http://angular.github.com/angular-phonecat/step-11/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-10...step-11 +Code Diff}Next
    + +And so we arrive at the last step of this tutorial. Here we define a custom service that +represents a {@link http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. +Using this client we can make xhr requests for data in an easier way, without having to deal with +the lower-level {@link angular.service.$xhr $xhr} APIs, HTTP methods and URLs. + +__`app/index.html`.__ +
    +...
    +  
    +...
    +
    + + +__`app/js/services.js`.__ (New) +
    + angular.service('Phone', function($resource){
    +  return $resource('phones/:phoneId.json', {}, {
    +    query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
    +  });
    + });
    +
    + +__`app/js/controllers.js`.__ +
    +...
    +
    +function PhoneListCtrl(Phone_) {
    +  this.orderProp = 'age';
    +  this.phones = Phone_.query();
    +}
    +//PhoneListCtrl.$inject = ['Phone'];
    +
    +
    +function PhoneDetailCtrl(Phone_) {
    +  this.phone = Phone_.get({phoneId:this.params.phoneId});
    +}
    +//PhoneDetailCtrl.$inject = ['Phone'];
    +
    + +__`test/unit/controllersSpec.js`:__ +
    +/* jasmine specs for controllers go here */
    +describe('PhoneCat controllers', function() {
    +
    +  beforeEach(function(){
    +    this.addMatchers({
    +      toEqualData: function(expected) {
    +        return angular.equals(this.actual, expected);
    +      }
    +    });
    +  });
    +
    +  describe('PhoneListCtrl', function(){
    +    var scope, $browser, ctrl;
    +
    +    beforeEach(function() {
    +      scope = angular.scope();
    +      $browser = scope.$service('$browser');
    +
    +      $browser.xhr.expectGET('phones/phones.json').respond([{name: 'Nexus S'},
    +                                                            {name: 'Motorola DROID'}]);
    +      ctrl = scope.$new(PhoneListCtrl);
    +    });
    +
    +    it('should create "phones" model with 2 phones fetched from xhr', function() {
    +      expect(ctrl.phones).toEqual([]);
    +      $browser.xhr.flush();
    +
    +      expect(ctrl.phones).toEqualData([{name: 'Nexus S'},
    +                                       {name: 'Motorola DROID'}]);
    +    });
    +
    +    it('should set the default value of orderProp model', function() {
    +      expect(ctrl.orderProp).toBe('age');
    +    });
    +  });
    +
    +
    +  describe('PhoneDetailCtrl', function(){
    +    var scope, $browser, ctrl;
    +
    +    beforeEach(function() {
    +      scope = angular.scope();
    +      $browser = scope.$service('$browser');
    +    });
    +
    +    beforeEach(function() {
    +      scope = angular.scope();
    +      $browser = scope.$service('$browser');
    +    });
    +
    +    it('should fetch phone detail', function(){
    +      scope.params = {phoneId:'xyz'};
    +      $browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
    +      ctrl = scope.$new(PhoneDetailCtrl);
    +
    +      expect(ctrl.phone).toEqualData({});
    +      $browser.xhr.flush();
    +
    +      expect(ctrl.phone).toEqualData({name:'phone xyz'});
    +    });
    +  });
    +});
    +
    + + +## Discussion: + +* We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the +lower-level `$xhr` service, replacing it with a new service called `Phone`. Angular's {@link +angular.service.$resource `$resource`} service is easier to use than `$xhr` for interacting with +data sources exposed as RESTful resources. It is also easier now to understand what the code in +our controllers is doing. + + An important thing to notice in our controller code is that we don't pass any callback + functions when invoking methods of our Phone services. It looks as if the result were returned + synchronously. That is not the case at all. What is returned synchronously is a "future" — an + object, which will be filled with data when the xhr response returns. Because of the + data-binding in angular, we can use this future and bind it to our template. Then, when the + data arrives, the view will automatically update. See? Angular tries hard to make simple + stuff simple. + +* Once again we make use of `$route's` params, this time to construct the URL passed as a +parameter to `$resource` in our `services.js` script. + +* Last, but certainly not least, we expanded and modified our unit test to verify that our new +service is returning data as we expect it to. + + In our assertions we use a newly-defined `toEqualData` {@link + http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html Jasmine matcher}, which + compares only object properties and ignores methods. This is necessary, because the `$resource` + client will augment the response object with handy methods for updating and deleting the + resource (we don't use these in our tutorial though). + +There you have it! We have created a web app in a relatively short amount of time. + +## Closing Notes: + +* For more details and examples of the angular concepts we touched on in this tutorial, see the +{@link guide Developer Guide}. + +* For several more examples of sample code, see the {@link cookbook Cookbook}. + +* When you are ready to start developing a project using angular, be sure to begin with the {@link +https://github.com/angular/angular-seed angular seed app}. + +* We hope this tutorial was useful to you, and that you learned enough about angular to make you +want to learn more. Of course, we especially hope you are inspired to go out and develop angular +web apps of your own, and perhaps you might even be interested in {@link contribute contributing} +to angular. + + + + + + + + + +
    {@link tutorial.step_10 Previous}{@link http://angular.github.com/angular-phonecat/step-11/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-10...step-11 +Code Diff}Next
    diff --git a/docs/contribute.ngdoc b/docs/contribute.ngdoc deleted file mode 100644 index 43d17283..00000000 --- a/docs/contribute.ngdoc +++ /dev/null @@ -1,233 +0,0 @@ -@ngdoc overview -@name Contributing -@description - - -# Open Source - -`Angular` is an open source project licensed under the {@link -http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are -always welcome. When working with `angular` source base, please follow the guidelines provided on -this page. - -* Contributing to Source Code -* Applying Code Standards -* Checking Out and Building `Angular` -* Submitting Your Changes - - - - -# Contributing to Source Code - -We'd love for you to contribute to our source code and to make `angular` even better than it is -today! Here are the guidelines we'd like you to use: - -* Major changes that you intend to contribute to the project must be discussed first on our {@link -https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better -coordinate our efforts, prevent duplication of work, and help you to craft the change so that it -is successfully accepted upstream. -* Small changes and bug fixes can be crafted and submitted to Github as a pull -request. - - - - -# Applying Code Standards - -To ensure consistency throughout the source code, keep these rules in mind as you are working: - -* All features or bug fixes must be tested by one or more specs. -* All public API methods must be documented with ngdoc, an extended version of jsdoc (we added -support for markdown and templating via `@ngdoc` tag). To see how we document our APIs, please -check out the existing ngdocs. -* With the exceptions listed below, we follow the rules contained in {@link -http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml Google's JavaScript Style -Guide}: - - * Do not use namespaces: Instead, we wrap the entire `angular` code base in an anonymous closure -and export our API explicitly rather than implicitly. - * Wrap all code at 100 characters. - * Instead of complex inheritance hierarchies, we prefer simple objects. We use prototypical -inheritance only when absolutely necessary. - * We love functions and closures and, whenever possible, prefer them over objects. - * To write concise code that can be better minified, internally we use aliases that map to the -external API. See our existing code to see what we mean. - * We don't go crazy with type annotations for private internal APIs unless it's an internal API -that is used throughout `angular`. The best guidance is to do what makes the most sense. - - - -# Checking Out and Building Angular - -The `angular` source code is hosted at {@link http://github.com Github}, which we also use to -accept code contributions. Several steps are needed to check out and build `angular`: - - -## Installation Dependencies - -Before you can build `angular`, you must install or configure the following dependencies on your -machine: - -* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed -on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the -Rake website. - -* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a -development web server. Depending on your system, you can install Node either from source or as a -pre-packaged bundle. - -* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver -JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the -`angular` source base, which means there is no need to install or configure it separately. -* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is -quite a good source for information on Git. - - -## Creating a Github Account and Forking Angular - -To create a Github account, follow the instructions {@link https://github.com/signup/free here}. -Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link -https://github.com/angular/angular.js main angular repository}. - - -## Building `Angular` - -To build `angular`, you check out the source code and use Rake to generate the non-minified and -minified `angular` files: - -1. To clone your Github repository, run: - - git clone git@github.com:/angular.js.git - -2. To go to the `angular` directory, run: - - cd angular.js - -3. To add the main `angular` repository as an upstream remote to your repository, run: - - git remote add upstream https://github.com/angular/angular.js.git - -4. To build `angular`, run: - - rake package - -The build output can be located under the `build` directory. It consists of the following files and -directories: - -* `angular-x.y.z-.tgz` — This is the complete tarball, which contains all of the release -build artifacts. -* `angular.js` — The non-minified `angular` script. -* `angular.min.js` — The minified `angular` script. -* `angular-scenario.js` — The `angular` End2End test runner. -* `angular-ie-compat.js` — The Internet Explorer compatibility patch file. -* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`. -* `docs/index.html` — The main page for the documentation. -* `docs/docs-scenario.html` — The End2End test runner for the documentation application. - - -## Running a Local Development Web Server - -To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have -made available a local web server based on Node.js. - -1. To start the web server, run: - - ./nodeserver.sh - -2. To access the local server, go to this website: - - http://localhost:8000/ - - By default, it serves the contents of the `angular` project directory. - - - -## Running the Unit Test Suite - -Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the -tests: - -1. To start the JSTD server, run: - - ./server.sh - -2. To capture one or more browsers, go to this website: - - http://localhost:9876/ - -3. To trigger a test execution, run: - - ./test.sh - -4. To automatically run the test suite each time one or more of the files in the project directory -is changed, you can install `watchr` and then run: - - watchr watchr.rb - -5. To view the output of each test run, you can tail this log file: - - ./logs/jstd.log - - -## Running the End2End Test Suite - -To run the End2End test suite: - -1. Start the local web server. -2. In a browser, go to: - - http://localhost:8000/build/docs/docs-scenario.html - - The tests are executed automatically. - - - - -# Submitting Your Changes - -To create and submit a change: - -1. Create a new branch off the master for your changes: - - git branch my-fix-branch - -2. Check out the branch: - - git checkout my-fix-branch - -3. Create your patch, make sure to have plenty of tests (that pass). - -4. Commit your changes: - - git commit -a - -5. Run JavaScript Lint and be sure to address all new warnings and errors: - - rake lint - -6. Push your branch to Github: - - git push origin my-fix-branch - -7. In Github, send a pull request to `angular:master`. - -8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes -from the main (upstream) repository: - * To delete the branch in Github, run: - - git push origin :my-fix-branch - - * To check out the master branch, run: - - git checkout master - - * To delete a local branch, run: - - git branch -D my-fix-branch - - * To update your master with the latest upstream version, run: - - git pull --ff upstream master - -That's it! Thank you for your contribution! diff --git a/docs/cookbook.buzz.ngdoc b/docs/cookbook.buzz.ngdoc deleted file mode 100644 index 2e82b2d1..00000000 --- a/docs/cookbook.buzz.ngdoc +++ /dev/null @@ -1,63 +0,0 @@ -@workInProgress -@ngdoc overview -@name Cookbook: Resources - Buzz -@description - -External resources are URLs that provide JSON data, which are then rendered with the help of -templates. angular has a resource factory that can be used to give names to the URLs and then -attach behavior to them. For example you can use the -{@link http://code.google.com/apis/buzz/v1/getting_started.html#background-operations| Google Buzz API} -to retrieve Buzz activity and comments. - - - - -
    - - -
    -
    -

    - - {{item.actor.name}} - - Expand replies: {{item.links.replies[0].count}} - -

    - {{item.object.content | html}} -
    - - {{reply.actor.name}}: - {{reply.content | html}} -
    -
    -
    -
    - - it('fetch buzz and expand', function(){ - element(':button:contains(fetch)').click(); - expect(repeater('div.buzz').count()).toBeGreaterThan(0); - element('.buzz a:contains(Expand replies):first').click(); - expect(repeater('div.reply').count()).toBeGreaterThan(0); - }); - -
    diff --git a/docs/cookbook.deeplinking.ngdoc b/docs/cookbook.deeplinking.ngdoc deleted file mode 100644 index 7d69ee84..00000000 --- a/docs/cookbook.deeplinking.ngdoc +++ /dev/null @@ -1,114 +0,0 @@ -@workInProgress -@ngdoc overview -@name Cookbook: Deep Linking -@description - -Deep linking allows you to encode the state of the application in the URL so that it can be -bookmarked and the application can be restored from the URL to the same state. - -While does not force you to deal with bookmarks in any particular way, it has services -which make the common case described here very easy to implement. - -# Assumptions - -Your application consists of a single HTML page which bootstraps the application. We will refer -to this page as the chrome. -Your application is divided into several screens (or views) which the user can visit. For example, -the home screen, settings screen, details screen, etc. For each of these screens, we would like to -assign a URL so that it can be bookmarked and later restored. Each of these screens will be -associated with a controller which define the screen's behavior. The most common case is that the -screen will be constructed from an HTML snippet, which we will refer to as the partial. Screens can -have multiple partials, but a single partial is the most common construct. This example makes the -partial boundary visible using a blue line. - -You can make a routing table which shows which URL maps to which partial view template and which -controller. - -# Example - -In this example we have a simple app which consist of two screens: - -* Welcome: url `#` Show the user contact information. -* Settings: url `#/settings` Show an edit screen for user contact information. - - -The two partials are defined in the following URLs: - -* {@link ./examples/settings.html} -* {@link ./examples/welcome.html} - - - - - -
    -

    Your App Chrome

    - [ Welcome | Settings ] -
    - - Partial: {{$route.current.template}} - - - Your app footer -
    -
    - - it('should navigate to URL', function(){ - element('a:contains(Welcome)').click(); - expect(element('ng\\:view').text()).toMatch(/Hello anonymous/); - element('a:contains(Settings)').click(); - input('form.name').enter('yourname'); - element(':button:contains(Save)').click(); - element('a:contains(Welcome)').click(); - expect(element('ng\\:view').text()).toMatch(/Hello yourname/); - }); - -
    - - - -# Things to notice - -* Routes are defined in the `AppCntl` class. The initialization of the controller causes the - initialization of the {@link angular.service.$route $route} service with the proper URL routes. -* The {@link angular.service.$route $route} service then watches the URL and instantiates the - appropriate controller when the URL changes. -* The {@link angular.widget.ng:view ng:view} widget loads the view when the URL changes. It also - sets the view scope to the newly instantiated controller. -* Changing the URL is sufficient to change the controller and view. It makes no difference whether - the URL is changed programatically or by the user. diff --git a/docs/cookbook.form.ngdoc b/docs/cookbook.form.ngdoc deleted file mode 100644 index c9fd9e9a..00000000 --- a/docs/cookbook.form.ngdoc +++ /dev/null @@ -1,103 +0,0 @@ -@workInProgress -@ngdoc overview -@name Cookbook: Form -@description - -A web application's main purpose is to present and gather data. For this reason angular strives -to make both of these operations trivial. This example shows off how you can build a simple form to -allow a user to enter data. - - - - - -
    - -
    -

    - -
    -
    - , - -

    - - - [ add ] -
    - - - [ X ] -
    -
    - Debug View: -
    user={{user}}
    -
    - -
    - - it('should show debug', function(){ - expect(binding('user')).toMatch(/John Smith/); - }); - it('should add contact', function(){ - using('.example').element('a:contains(add)').click(); - using('.example div:last').input('contact.value').enter('you@example.org'); - expect(binding('user')).toMatch(/\(234\) 555\-1212/); - expect(binding('user')).toMatch(/you@example.org/); - }); - - it('should remove contact', function(){ - using('.example').element('a:contains(X)').click(); - expect(binding('user')).not().toMatch(/\(234\) 555\-1212/); - }); - - it('should validate zip', function(){ - expect(using('.example').element(':input[name=user.address.zip]').attr('className')) - .not().toMatch(/ng-validation-error/); - - using('.example').input('user.address.zip').enter('abc'); - - expect(using('.example').element(':input[name=user.address.zip]').attr('className')) - .toMatch(/ng-validation-error/); - }); - - it('should validate state', function(){ - expect(using('.example').element(':input[name=user.address.state]').attr('className')) - .not().toMatch(/ng-validation-error/); - - using('.example').input('user.address.state').enter('XXX'); - - expect(using('.example').element(':input[name=user.address.state]').attr('className')) - .toMatch(/ng-validation-error/); - }); - -
    - - -# Things to notice - -* The user data model is initialized {@link angular.ng:controller controller} and is available in - the {@link angular.scope scope} with the initial data. -* For debugging purposes we have included a debug view of the model to better understand what - is going on. -* The {@link angular.widget.HTML input widgets} simply refer to the model and are auto bound. -* The inputs {@link angular.validator validate}. (Try leaving them blank or entering non digits - in the zip field) -* In your application you can simply read from or write to the model and the form will be updated. -* By clicking the 'add' link you are adding new items into the `user.contacts` array which are then - reflected in the view. diff --git a/docs/cookbook.formadvanced.ngdoc b/docs/cookbook.formadvanced.ngdoc deleted file mode 100644 index 181dd5e9..00000000 --- a/docs/cookbook.formadvanced.ngdoc +++ /dev/null @@ -1,105 +0,0 @@ -@workInProgress -@ngdoc overview -@name Cookbook: Advanced Form -@description - -Here we extend the basic form example to include common features such as reverting, dirty state -detection, and preventing invalid form submission. - - - - -
    - -
    -

    - -
    -
    - , - -

    - - - [ add ] -
    - - - [ X ] -
    - - - -
    - Debug View: -
    form={{form}}
    -    master={{master}}
    -
    -
    - - it('should enable save button', function(){ - expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); - input('form.name').enter(''); - expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); - input('form.name').enter('change'); - expect(element(':button:contains(Save)').attr('disabled')).toBeFalsy(); - element(':button:contains(Save)').click(); - expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); - }); - it('should enable cancel button', function(){ - expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy(); - input('form.name').enter('change'); - expect(element(':button:contains(Cancel)').attr('disabled')).toBeFalsy(); - element(':button:contains(Cancel)').click(); - expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy(); - expect(element(':input[name=form.name]').val()).toEqual('John Smith'); - }); - -
    - - -#Things to notice - -* Cancel & save buttons are only enabled if the form is dirty -- there is something to cancel or - save. -* Save button is only enabled if there are no validation errors on the form. -* Cancel reverts the form changes back to original state. -* Save updates the internal model of the form. -* Debug view shows the two models. One presented to the user form and the other being the pristine - copy master. diff --git a/docs/cookbook.helloworld.ngdoc b/docs/cookbook.helloworld.ngdoc deleted file mode 100644 index ab4c337a..00000000 --- a/docs/cookbook.helloworld.ngdoc +++ /dev/null @@ -1,31 +0,0 @@ -@workInProgress -@ngdoc overview -@name Cookbook: Hello World -@description - - - - Your name: -
    - Hello {{name}}! -
    - - it('should change the binding when user enters text', function(){ - expect(binding('name')).toEqual('World'); - input('name').enter('angular'); - expect(binding('name')).toEqual('angular'); - }); - -
    - -# Things to notice - -Take a look through the source and note: - -* The script tag that {@link guide.bootstrap bootstraps} the angular environment. -* The text {@link angular.widget.HTML input widget} which is bound to the greeting name text. -* No need for listener registration and event firing on change events. -* The implicit presence of the `name` variable which is in the root {@link angular.scope scope}. -* The double curly brace `{{markup}}`, which binds the name variable to the greeting text. -* The concept of {@link guide.data-binding data binding}, which reflects any changes to the - input field in the greeting text. diff --git a/docs/cookbook.mvc.ngdoc b/docs/cookbook.mvc.ngdoc deleted file mode 100644 index 94688547..00000000 --- a/docs/cookbook.mvc.ngdoc +++ /dev/null @@ -1,125 +0,0 @@ -@workInProgress -@ngdoc overview -@name Cookbook: MVC -@description - -MVC allows for a clean an testable separation between the behavior (controller) and the view -(HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the -view. This makes it very easy for the controller and the view to share the model. - -The model is simply the controller's this. This makes it very easy to test the controller in -isolation since one can simply instantiate the controller and test without a view, because there is -no connection between the controller and the view. - - - - - -

    Tic-Tac-Toe

    -
    - Next Player: {{nextMove}} -
    Player {{winner}} has won!
    - - - - -
    {{cell}}
    - -
    -
    - - it('should play a game', function(){ - piece(1, 1); - expect(binding('nextMove')).toEqual('O'); - piece(3, 1); - expect(binding('nextMove')).toEqual('X'); - piece(1, 2); - piece(3, 2); - piece(1, 3); - expect(element('.winner').text()).toEqual('Player X has won!'); - }); - - function piece(row, col) { - element('.board tr:nth-child('+row+') td:nth-child('+col+')').click(); - } - -
    - - -# Things to notice - -* The controller is defined in JavaScript and has no reference to the rendering logic. -* The controller is instantiated by and injected into the view. -* The controller can be instantiated in isolation (without a view) and the code will still execute. - This makes it very testable. -* The HTML view is a projection of the model. In the above example, the model is stored in the - board variable. -* All of the controller's properties (such as board and nextMove) are available to the view. -* Changing the model changes the view. -* The view can call any controller function. -* In this example, the `setUrl()` and `readUrl()` functions copy the game state to/from the URL's - hash so the browser's back button will undo game steps. See deep-linking. This example calls - {@link angular.Scope.$watch $watch()} to set up a listener that invokes `readUrl()` when needed. diff --git a/docs/cookbook.ngdoc b/docs/cookbook.ngdoc deleted file mode 100644 index 7dc937c5..00000000 --- a/docs/cookbook.ngdoc +++ /dev/null @@ -1,60 +0,0 @@ -@workInProgress -@ngdoc overview -@name Cookbook -@description - -Welcome to the angular cookbook. Here we will show you typical uses of angular by example. - - -# Hello World - -{@link cookbook.helloworld Hello World}: The simplest possible application that demonstrates the -classic Hello World! - - -# Basic Form - -{@link cookbook.form Basic Form}: Displaying forms to the user for editing is the bread and butter -of web applications. Angular makes forms easy through bidirectional data binding. - - -# Advanced Form - -{@link cookbook.formadvanced Advanced Form}: Taking the form example to the next level and -providing advanced features such as dirty detection, form reverting and submit disabling if -validation errors exist. - - -# Model View Controller - -{@link cookbook.mvc MVC}: Tic-Tac-Toe: Model View Controller (MVC) is a time-tested design pattern -to separate the behavior (JavaScript controller) from the presentation (HTML view). This -separation aids in maintainability and testability of your project. - - -# Multi-page App and Deep Linking - -{@link cookbook.deeplinking Deep Linking}: An AJAX application never navigates away from the -first page it loads. Instead, it changes the DOM of its single page. Eliminating full-page reloads -is what makes AJAX apps responsive, but it creates a problem in that apps with a single URL -prevent you from emailing links to a particular screen within your application. - -Deep linking tries to solve this by changing the URL anchor without reloading a page, thus -allowing you to send links to specific screens in your app. - - -# Services - -{@link angular.service Services}: Services are long lived objects in your applications that are -available across controllers. A collection of useful services are pre-bundled with angular but you -will likely add your own. Services are initialized using dependency injection, which resolves the -order of initialization. This safeguards you from the perils of global state (a common way to -implement long lived objects). - - -# External Resources - -{@link cookbook.buzz Resources}: Web applications must be able to communicate with the external -services to get and update data. Resources are the abstractions of external URLs which are -specially tailored to angular data binding. - diff --git a/docs/downloading.ngdoc b/docs/downloading.ngdoc deleted file mode 100644 index a02b3367..00000000 --- a/docs/downloading.ngdoc +++ /dev/null @@ -1,70 +0,0 @@ -@workInProgress -@ngdoc overview -@name Downloading -@description - -# Including angular scripts from code.angularjs.org - -To get started quickly you without worrying about downloading anything and maintaining a local copy, -you can point your html `script` tag directly to urls. - -There are two kinds of urls you care about: - -* http://code.angularjs.org/angular-.js -* http://code.angularjs.org/angular-.min.js - -The first one is non-minified version, suitable for web development. The latter one is minified -version, which we strongly suggest you use in production. - -To point your code to let's say angular version 0.9.12, use the following template: - -
    -  
    -  
    -    
    -      My Angular App
    -      
    -    
    -    
    -    
    -  
    -
    - - -# Downloading and hosting the files on your own - -This options is for those who want to work with angular offline, or want to host the angular files -on their own servers. - -If you navigate to , you'll see a directory listing with all angular -versions since we started releasing versioned build artifacts (quite late in the project lifetime). - -Each directory contains all artifacts that we released for a particular version. Once you navigate -to one of these directories you'll see the following list of files: - -* `angular-.js` - This file is non-obfuscated, non-minified, and human-readable by opening -it it any editor or browser. In order to get better error messages during development, you should -always use this non-minified angular script. - -* `angular-.min.js` - This is a minified and obfuscated version of -`angular-.js` created with Closure compiler. Use this version for production in order to -minimize the size of the application that is downloaded by your user's browser. - -* `angular-.tgz` - This is a tarball archive which contains all the other files released -for this angular version. Use this file to get everything in a single download. - -* `angular-ie-compat-.js` - This is a special file that contains code and data specifically -tailored for getting Internet Explorer to work with angular. If you host your own copy of angular -files, make sure that this file is available for download and resides under the same parent path as -`angular-.js` or `angular-.min.js`. - -* `angular-mocks-.js` - This file contains implementation of mocks that we provide to you -to make testing angular apps even easier. Your unit/integration test harness should load this file -after `angular-.js` is loaded. - -* `angular-scenario-.js` - This file is a very nifty JavaScript file, which allows you to -write and execute end to end tests for angular applications. - -* `docs-` - this directory contains all the files that compose the - documentation app. These files are handy to see the older version of -our docs, or even more importantly, view the docs offline! diff --git a/docs/faq.ngdoc b/docs/faq.ngdoc deleted file mode 100644 index dd06d961..00000000 --- a/docs/faq.ngdoc +++ /dev/null @@ -1,81 +0,0 @@ -@workInProgress -@ngdoc overview -@name FAQ -@description - -#FAQ - -### Why is this project called "angular"? Why is the namespace called "ng"? - -Because HTML has angular brackets and "ng" sounds like "angular". - -### Is an HTML5 tag? - -No, is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two -together. - -### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}? - -No, angular is none of these. You don't call its functions, it does not call your functions, -it does not provide a way to manipulate DOM, but does provide primitives to create UI projections -of your data. There are lots of existing widget libraries which you can integrate with angular. -It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers. - -### Do I need to worry about security holes in angular? - -Like with any technology, angular is not impervious to attack. angular does, however, provide -built-in protection from basic security holes including cross-site scripting and HTML injection -attacks. angular does round-trip escaping on all strings for you. - -### Can I download the source, build, and host the angular environment locally? - -Yes. See instructions in {@link downloading downloading}. - -### Is angular a templating system? - -At the highest level, angular does look 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: bidirectional data binding. The template is compiled on the browser and -the compilation step produces a live view. This means you, the developer, don't need to write -code to constantly sync the view with the model and the model with the view as in other -templating systems. - -### What browsers does angular work with? - -Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and -above. Note that CSS only works on IE7 and above. - -### What's angular's performance like? - -angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your -app's performance will vary depending on how many bindings you use. - -### How big is the angular bootstrap JS file that I need to include? - -The size of the library itself is < 50KB compressed and obfuscated. - -### Can I use the open-source Closure Library with angular? - -Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library} -in angular. - -### Does angular use the jQuery library? - -Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library. -If jQuery is not present in your script path, angular falls back on its own implementation of -{@link angular.element jQuery lite}. If jQuery is present in the path, angular uses it to -manipulate the DOM. - -### What is testability like in angular? - -Very testable. It has an integrated dependency injection framework. See -{@link angular.service service} for details. - -### How can I learn more about angular? - -Watch the July 28, 2010 talk -"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building AJAX Apps}". - -### How is angular licensed? - -The MIT License. diff --git a/docs/guide.bootstrap.ngdoc b/docs/guide.bootstrap.ngdoc deleted file mode 100644 index 12028796..00000000 --- a/docs/guide.bootstrap.ngdoc +++ /dev/null @@ -1,97 +0,0 @@ -@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: - - - - Hello {{'World'}}! - - - -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. - -
    -
    -
    - 
    - 
    - 
    -  Hello {{'World'}}!
    - 
    -
    -
    - -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. - -
    -
    -
    - - -# 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: - -
    -
    -
    - - -# 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/guide.compiler.ngdoc b/docs/guide.compiler.ngdoc deleted file mode 100644 index 8896db43..00000000 --- a/docs/guide.compiler.ngdoc +++ /dev/null @@ -1,163 +0,0 @@ -@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 , which should display a greeting. - -If we want this HTML source: - -
    -
    - -
    -
    - -To produce this DOM: - -
    -
    - - Hello - World! - -
    -
    - -Write this widget definition (assuming you've already declared the my namespace in the page): - - -
    -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('');
    -    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);
    -    });
    -  };
    -});
    -
    - -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 element set to the salutation class - * Create a 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/guide.css.ngdoc b/docs/guide.css.ngdoc deleted file mode 100644 index 6e028f30..00000000 --- a/docs/guide.css.ngdoc +++ /dev/null @@ -1,46 +0,0 @@ -@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: - - >
    Error message
    - - - -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: - -
    -
    -
    diff --git a/docs/guide.data-binding.ngdoc b/docs/guide.data-binding.ngdoc deleted file mode 100644 index 12a926bd..00000000 --- a/docs/guide.data-binding.ngdoc +++ /dev/null @@ -1,41 +0,0 @@ -@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 - - -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 - -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/guide.di.ngdoc b/docs/guide.di.ngdoc deleted file mode 100644 index 2d1f92eb..00000000 --- a/docs/guide.di.ngdoc +++ /dev/null @@ -1,304 +0,0 @@ -@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}. - -
    -// 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;
    -  }
    -});
    -
    - -At run-time we can access the `uniqueId` service by looking it up with the service locator like -this: - -
    -// 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);
    -
    - -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: - -
    -angular.service('gadgetFactory', function(uniqueId){
    -  return function(){
    -    return {gadgetId: uniqueId()};
    -  };
    -}, {$inject: ['uniqueId']});
    -
    - -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. - -
    -// crate a root scope
    -var rootScope = angular.scope();
    -// accesss the service locator
    -var myService = rootScope.$service('myService');
    -
    - - - -# 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: - -
    -function MyController($route){
    -  // configure the route service
    -  $route.when(...);
    -}
    -MyController.$inject = ['$route'];
    -
    - -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: - -
    -
    -
    - 
    - 
    -  ...
    - 
    -
    -
    - -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. - -
    -MyController.$inject = ['$route'];
    -
    - -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. - -
    -// 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');
    -
    - - -## Creating Controllers using Dependency Injection - -In a typical angular application the dependency injection is most commonly used when creating -controllers. -
    -// 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.
    -
    - - -## 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. - -
    -// 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');
    -
    - - - -# 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: - -
    -function myFn(a,b){}
    -expect(myFn.toString()).toEqual('function myFn(a,b){}');
    -
    - -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: - -
    -// 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'];
    -
    - -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/guide.expression.ngdoc b/docs/guide.expression.ngdoc deleted file mode 100644 index 421dd9c7..00000000 --- a/docs/guide.expression.ngdoc +++ /dev/null @@ -1,207 +0,0 @@ -@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 - - - 1+2={{1+2}} - - - it('should calculate expression in binding', function(){ - expect(binding('1+2')).toEqual('3'); - }); - - - -You can try evaluating different expressions here: - - - -
    - Expression: - - -
      -
    • - [ X ] - {{expr}} => -
    • -
    -
    -
    - - 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"]); - }); - -
    - -# 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). - - - -
    - Name: - -
    -
    - - 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'); - }); - -
    - -## 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. - - - -
    - Search: - - - - - - -
    NamePhone
    {{friend.name}}{{friend.phone}}
    -
    - - 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); - - }); - -
    - -## 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 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/guide.ngdoc b/docs/guide.ngdoc deleted file mode 100644 index 2798210d..00000000 --- a/docs/guide.ngdoc +++ /dev/null @@ -1,37 +0,0 @@ -@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/guide.overview.ngdoc b/docs/guide.overview.ngdoc deleted file mode 100644 index 61c58435..00000000 --- a/docs/guide.overview.ngdoc +++ /dev/null @@ -1,337 +0,0 @@ -@ngdoc overview -@name Developer Guide: Overview -@description - - -* What Is Angular? -* The Angular Philosophy -* Anatomy Of An Angular App -* Why You Want Angular -* Angular's Ancestors -* Watch a Presentation About Angular - - - -# 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: - - - -

    Bigg Bike Shop

    -
    - Invoice: -
    -
    - - - - - - - -
    QuantityCost
    -
    - Total: {{qty * cost | currency}} -
    -
    - -
    - -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 - -This ensures angular runs nicely in all major browsers. - -In line __3__ we do two angular setup tasks inside a ` - -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: - 15 Cost: - -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." - - - -# 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): - -
    -Hello
    -
    - -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: - -
    -var label = new Label();
    -label.setText('Hello');
    -label.setClass('label');
    -parent.addChild(label);
    -
    - -That looks like, let's see, do some math, factor out the `
    `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.
    -
    -
    -
    -# 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:
    -
    -
    -
    -
    -
    -# 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.
    -
    -
    -
    -# 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.
    -`Thank You, TB-L!`.
    -
    -## 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.
    -
    -
    -
    -# 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.
    -
    -
    - 
    - 
    - 
    - 
    -
    -
    -{@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/guide.template.ngdoc b/docs/guide.template.ngdoc
    deleted file mode 100644
    index ae9bba92..00000000
    --- a/docs/guide.template.ngdoc
    +++ /dev/null
    @@ -1,22 +0,0 @@
    -@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/guide.testing.ngdoc b/docs/guide.testing.ngdoc
    deleted file mode 100644
    index bb3a1441..00000000
    --- a/docs/guide.testing.ngdoc
    +++ /dev/null
    @@ -1,8 +0,0 @@
    -@workInProgress
    -@ngdoc overview
    -@name Developer Guide: Testing
    -@description
    -
    -# Testing Angular Applications
    -
    -to be written...
    diff --git a/docs/service.template b/docs/service.template
    deleted file mode 100644
    index 639990ed..00000000
    --- a/docs/service.template
    +++ /dev/null
    @@ -1,57 +0,0 @@
    -

    {{name}}

    - -{{#workInProgress}} -
    - Work In Progress - This page is currently being revised. It might be incomplete or contain inaccuracies. - {{{workInProgress.description}}} -
    -{{/workInProgress}} - -{{#deprecated}} -
    - Deprecated API - {{deprecated}} -
    -{{/deprecated}} - -

    Description

    -{{{description}}} - -

    Dependencies

    -
      - {{#requires}} -
    • {{name}}
    • - {{/requires}} -
    - -{{#method.length}} -

    Methods

    -
      - {{#method}} -
    • {{shortName}}(): {{{description}}}
    • - {{/method}} -
    -{{/method.length}} - -{{#property.length}} -

    Properties

    -
      - {{#property}} -
    • {{name}}:{{#type}}{{type}}{{/type}}{{#description}}: {{{description}}}{{/description}}
    • - {{/property}} -
    -{{/property.length}} - -{{#example}} -

    Example

    -{{{exampleDescription}}} - - -{{/example}} - {{{example}}} -{{#example}} - - {{#scenario}}{{{scenario}}}{{/scenario}} - -{{/example}} diff --git a/docs/src/gen-docs.js b/docs/src/gen-docs.js index 464916b1..9edfaceb 100644 --- a/docs/src/gen-docs.js +++ b/docs/src/gen-docs.js @@ -20,7 +20,7 @@ var work = callback.chain(function(){ var writes = callback.chain(function(){ ngdoc.merge(docs); docs.forEach(function(doc){ - writer.output(doc.id + '.html', doc.html(), writes.waitFor()); + writer.output(doc.section + '/' + doc.id + '.html', doc.html(), writes.waitFor()); }); var metadata = ngdoc.metadata(docs); writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'], writes.waitFor()); diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js index 57202809..869fe4c5 100644 --- a/docs/src/ngdoc.js +++ b/docs/src/ngdoc.js @@ -36,7 +36,6 @@ Doc.METADATA_IGNORE = (function(){ })(); - Doc.prototype = { keywords: function keywords(){ var keywords = {}; @@ -57,6 +56,38 @@ Doc.prototype = { return words.join(' '); }, + + /* + * This function is here to act as a huristic based translator from the old style urls to + * the new style which use sections. + */ + sectionHuristic: function (url){ + // if we are new styl URL with section/id then just return; + if (url.match(/\//)) return url; + var match = url.match(/(\w+)(\.(.*))?/); + var section = match[1]; + var id = match[3] || 'index'; + switch(section) { + case 'angular': + section = 'api'; + id = 'angular.' + id; + break; + case 'api': + case 'cookbook': + case 'guide': + case 'intro': + case 'tutorial': + break; + default: + id = section + '.' + id; + section = 'intro'; + } + var newUrl = section + '/' + (id || 'index'); + console.log('WARNING:', 'found old style url', url, 'at', this.file, this.line, + 'converting to', newUrl); + return newUrl; + }, + markdown: function (text) { var self = this; var IS_URL = /^(https?:\/\/|ftps?:\/\/|mailto:|\.|\/)/; @@ -70,7 +101,7 @@ Doc.prototype = { parts.forEach(function(text, i){ if (text.match(/^
    /)) {
             text = text.replace(/^
    ([\s\S]*)<\/pre>/mi, function(_, content){
    -          var clazz = 'brush: js;'
    +          var clazz = 'brush: js;';
               if (content.match(/\<\w/)) {
                 // we are HTML
                 clazz += ' html-script: true;';
    @@ -93,7 +124,8 @@ Doc.prototype = {
             text = text.replace(//gm, '<angular/>');
             text = text.replace(/{@link\s+([^\s}]+)\s*([^}]*?)\s*}/g,
               function(_all, url, title){
    -            return ''
    +            var isFullUrl = url.match(IS_URL);
    +            return ''
                   + (url.match(IS_ANGULAR) ? '' : '')
                   + (title || url).replace(/\n/g, ' ')
                   + (url.match(IS_ANGULAR) ? '' : '')
    @@ -525,6 +557,7 @@ function metadata(docs){
         var depth = path.length - 1;
         var shortName = path.pop();
         words.push({
    +      section: doc.section,
           id: doc.id,
           name: doc.name,
           depth: depth,
    @@ -538,7 +571,7 @@ function metadata(docs){
     }
     
     var KEYWORD_PRIORITY = {
    -  '.started': 1,
    +  '.index': 1,
       '.guide': 2,
       '.guide.overview': 1,
       '.angular': 7,
    @@ -562,7 +595,7 @@ function keywordSort(a, b){
           mangled.push(KEYWORD_PRIORITY[partialName] || 5);
           mangled.push(name);
         });
    -    return mangled.join('.');
    +    return doc.section + '/' + mangled.join('.');
       }
       var nameA = mangleName(a);
       var nameB = mangleName(b);
    diff --git a/docs/src/reader.js b/docs/src/reader.js
    index 300b17f0..f20bc06e 100644
    --- a/docs/src/reader.js
    +++ b/docs/src/reader.js
    @@ -9,15 +9,13 @@ var fs       = require('fs'),
     var NEW_LINE = /\n\r?/;
     
     function collect(callback){
    -/*
        findJsFiles('src', callback.waitMany(function(file) {
    -     //console.log('reading', file, '...');
    +     console.log('reading', file, '...');
          findNgDocInJsFile(file, callback.waitMany(function(doc, line) {
    -       callback(doc, file, line);
    +       callback('@section api\n' + doc, file, line);
         }));
       }));
    -*/
    -  findNgDocInDir('docs/', callback.waitMany(callback));
    +  findNgDocInDir('docs/content', callback.waitMany(callback));
       callback.done();
     }
     
    @@ -42,11 +40,18 @@ function findNgDocInDir(directory, docNotify) {
       fs.readdir(directory, docNotify.waitFor(function(err, files){
         if (err) return this.error(err);
         files.forEach(function(file){
    -      //console.log('reading', directory + file, '...');
    -      if (!file.match(/tutorial.*\.ngdoc$/)) return;
    -      fs.readFile(directory + file, docNotify.waitFor(function(err, content){
    +      fs.stat(directory + '/' + file, docNotify.waitFor(function(err, stats){
             if (err) return this.error(err);
    -        docNotify(content.toString(), directory + file, 1);
    +        if (stats.isFile()) {
    +          console.log('reading', directory + '/' + file, '...');
    +          fs.readFile(directory + '/' + file, docNotify.waitFor(function(err, content){
    +            if (err) return this.error(err);
    +            var section = '@section ' + directory.split('/').pop() + '\n';
    +            docNotify(section + content.toString(), directory + '/' +file, 1);
    +          }));
    +        } else if(stats.isDirectory()) {
    +          findNgDocInDir(directory + '/' + file, docNotify.waitFor(docNotify));
    +        }
           }));
         });
         docNotify.done();
    diff --git a/docs/src/templates/docs.css b/docs/src/templates/docs.css
    index f5b9275b..4f47367d 100644
    --- a/docs/src/templates/docs.css
    +++ b/docs/src/templates/docs.css
    @@ -18,6 +18,24 @@ a {
       height: 3.5em;
     }
     
    +#header .navigation {
    +  position: absolute;
    +  text-align: center;
    +  top: 0;
    +  right: 0;
    +  left: 0;
    +  margin: 0;
    +  padding: 0;
    +}
    +#header .navigation > li {
    +  display: inline;
    +  padding: 0 .5em;
    +}
    +
    +#header .navigation > li.selected {
    +  font-weight: bold;
    +}
    +
     #sidebar,
     #main {
       position: absolute;
    @@ -191,12 +209,8 @@ a {
       margin-top: 0;
     }
     
    -#sidebar ul li.level-1.level-angular {
    +#sidebar ul li.monospace{
       font-family: monospace;
    -  font-weight: normal;
    -  font-size: 1em;
    -  margin-top: 0;
    -  margin-bottom: 0;
     }
     
     #sidebar ul li.level-1 {
    @@ -208,17 +222,14 @@ a {
     
     #sidebar ul li.level-2 {
       margin-left: 2em;
    -  font-family: monospace;
     }
     
     #sidebar ul li.level-3 {
       margin-left: 3em;
    -  font-family: monospace;
     }
     
     #sidebar ul li.level-4 {
       margin-left: 4em;
    -  font-family: monospace;
     }
     
     
    diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js
    index 9483496e..47bb87a6 100644
    --- a/docs/src/templates/docs.js
    +++ b/docs/src/templates/docs.js
    @@ -1,8 +1,8 @@
     var HAS_HASH = /#/;
     DocsController.$inject = ['$location', '$browser', '$window'];
     function DocsController($location, $browser, $window) {
    -  this.pages = NG_PAGES;
       window.$root = this.$root;
    +  var self = this;
       this.$location = $location;
     
       if (!HAS_HASH.test($location.href)) {
    @@ -11,28 +11,36 @@ function DocsController($location, $browser, $window) {
     
       this.$watch('$location.hashPath', function(hashPath) {
         if (hashPath.match(/^!/)) {
    -      this.partialId = hashPath.substring(1);
    -      this.partialTitle = (angular.Array.filter(NG_PAGES, {id:this.partialId})[0]||{}).name;
    +      var parts = hashPath.substring(1).split('/');
    +      self.sectionId = parts[0];
    +      self.partialId = parts[1] || 'index';
    +      self.pages = angular.Array.filter(NG_PAGES, {section:self.sectionId});
    +      self.partialTitle = (angular.Array.filter(self.pages, function(doc){return doc.id == self.partialId;})[0]||{}).name;
         }
       });
     
       this.getUrl = function(page){
    -    return '#!' + page.id;
    +    return '#!' + page.section + '/' + page.id;
       };
     
       this.getCurrentPartial = function(){
    -    return './' + this.partialId + '.html';
    +    return './' + this.sectionId + '/' + this.partialId + '.html';
       };
     
       this.getClass = function(page) {
         var depth = page.depth,
             cssClass = 'level-' + depth + (page.name == this.partialId ? ' selected' : '');
     
    -    if (depth == 1 && page.type !== 'overview') cssClass += ' level-angular';
    +    if (page.section == 'api')
    +      cssClass += ' monospace';
     
         return cssClass;
       };
     
    +  this.selectedSection = function(section) {
    +    return section == self.sectionId ? 'selected' : null;
    +  };
    +
       this.afterPartialLoaded = function() {
         SyntaxHighlighter.highlight();
       };
    diff --git a/docs/src/templates/index.html b/docs/src/templates/index.html
    index 63e8d871..1c3dd3a6 100644
    --- a/docs/src/templates/index.html
    +++ b/docs/src/templates/index.html
    @@ -4,23 +4,36 @@
           ng:controller="DocsController">
     
       <angular/>
    -
       
    -
       
       
       
       
    -
    -  
    -  
    -  
    -  
    -
    -  
    -  
    -  
    -  
    +  
     
     
       
       
    - -__`app/js/controller.js`__ (Unchanged): -
    -/* App Controllers */
    -
    -function PhoneListCtrl($xhr) {
    -  var self = this;
    -
    -  $xhr('GET', 'phones/phones.json', function(code, response) {
    -    self.phones = response;
    -  });
    -
    -  self.orderProp = 'age';
    -}
    -
    -//PhoneListCtrl.$inject = ['$xhr'];
    -
    - -__`app/phones/phones.json`__ (sample snippet): -
    - [
    -  {
    -   "age": 4, 
    -   ...
    -   "carrier": "T-Mobile", 
    -   "id": "motorola-defy-with-motoblur", 
    -   "imageUrl": "http://google.com/phone/image/small/640001", 
    -   "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", 
    -   "snippet": "Are you ready for everything life throws your way?"
    -  }, 
    -  …
    - ]
    -
    - -__`test/e2e/scenarios.js`__: -
    -...
    -    it('should render phone specific links', function() {
    -      input('query').enter('nexus');
    -      element('.phones li a').click();
    -      expect(browser().location().hash()).toBe('/phones/nexus-s');
    -    });
    -...
    -
    - -## Discussion: - -* Note that we're using {@link guide.expression angular expressions} enclosed in the now-familiar -{@link angular.markup double-curly brace markup} in the href attribute values. These represent -attribute bindings, and work the same way as the bindings we saw in previous steps. - -* Note also the use of the {@link angular.directive.ng:src ng:src} directive in the `` tag. -That directive prevents the browser from treating the angular `{{ exppression }}` markup -literally, as it would do if we tried to use markup in a regular `src` attribute. Use `ng:src` to -keep the browser from eagerly making an extra http request to an invalid location. - -* We expanded our end-to-end test to verify that the app is generating correct links to the phone -views we will implement in the upcoming steps. - - - - - - - - - -
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-6/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-5...step-6 Code -Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_07.ngdoc b/docs/tutorial.step_07.ngdoc deleted file mode 100755 index 3c715a79..00000000 --- a/docs/tutorial.step_07.ngdoc +++ /dev/null @@ -1,181 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 7 -@description - - - - - - - - -
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code -Diff}{@link tutorial.step_00 Next}
    - -Our app is slowly growing and becoming more complex. Up until now, the app provided our users with -just one view (the list of all phones), and all of our template code was located in the -`index.html` file. The next step in building our app is the addition of a view that will show -detailed information about each of the devices in our list. - -To add the detailed view, we could expand the `index.html` file to contain template code for both -views, but that would get messy very quickly. Instead, we are going to turn the `index.html` -template into what we call a "layout template". This is a template that is common for all views in -our application. Other "partial templates" are then included into this layout template depending -on the current "route" — the view that is currently displayed to the user. - -Similarly as with templates, angular also allows for controllers and scopes managed by these -controllers to be nested. We are going to create a "root" controller called `PhoneCatCtrl`, which -will contain the declaration of routes for the application. - -Application routes in angular are declared via the {@link angular.service.$route $route} service. -This services makes it easy to wire together controllers, View templates, and the current URL -location in the browser. Using this feature we can implement {@link -http://en.wikipedia.org/wiki/Deep_linking deep linking}, which lets us utilize the browser's -History, and Back and Forward browser navigation. - -We'll use the $route service to declare that our application consists of two different views: one -view presents the phone listing, and the other view presents the details for a particular phone. -Each view will have the template stored in a separate file in the `app/partials/` directory. -Similarly each view will have a controller associated with it. These will be stored in the -existing `app/js/controllers.js` file. - -The `$route` service is usually used in conjunction with the {@link angular.widget.ng:view -ng:view} widget. The role of the `ng:view` widget is to include the view template for the current -route into the layout template, which makes it a perfect fit for our `index.html` template. - -For now we are going to get all the routing going, and move the phone listing template into a -separate file. We'll save the implementation of the phone details View for the next step. - -__`app/index.html`:__ -
    -...
    -
    -
    -  
    -
    -  
    -  
    -
    -
    -
    - -__`app/partials/phone-list.html`:__ -
    -
      -
    • - Search: -
    • -
    • - Sort by: - -
    • -
    - - -
    - -__`app/partials/phone-list.html`:__ -
    -TBD: detail view for {{params.phoneId}}
    -
    - -__`app/js/controller.js`:__ -
    -/* App Controllers */
    -
    -function PhoneCatCtrl($route) {
    -  var self = this;
    -
    -  $route.when('/phones',
    -              {template: 'partials/phone-list.html',   controller: PhoneListCtrl});
    -  $route.when('/phones/:phoneId',
    -              {template: 'partials/phone-detail.html', controller: PhoneDetailCtrl});
    -  $route.otherwise({redirectTo: '/phones'});
    -
    -  $route.onChange(function(){
    -    self.params = $route.current.params;
    -  });
    -
    -  $route.parent(this);
    -}
    -
    -//PhoneCatCtrl.$inject = ['$route'];
    -
    -
    -function PhoneListCtrl($xhr) {
    -  var self = this;
    -
    -  $xhr('GET', 'phones/phones.json', function(code, response) {
    -    self.phones = response;
    -  });
    -
    -  self.orderProp = 'age';
    -}
    -
    -//PhoneListCtrl.$inject = ['$xhr'];
    -
    -
    -function PhoneDetailCtrl() {}
    -
    - -## Discussion: - -* __The View.__ Our View template in `index.html` has been reduced down to this: -``. As described above, it is now a "layout template". We added the following -two new View templates: - - * `app/partials/phone-list.html` for the phone list. The phone-list view was formerly our - main view. We simply moved the code from `index.html` to here. - - * `app/partials/phone-detail.html` for the phone details (just a placeholder template for now). - -* __The Controller(s).__ We now have a new root controller (`PhoneCatCtrl`) and two -sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`). These inherit the model properties and -behavior from the root controller. - - * __`$route.`__ The root controller's job now is to set up the `$route` configuration: - - * When the fragment part of the URL in the browser ends in "/phones", `$route` service - grabs the `phone-list.html` template, compiles it, and links it with a new scope that is - controlled by our `PhoneListCtrl` controller. - - * When the URL ends in "/phones/:phoneId", `$route` compiles and links the - `phone-detail.html` template as it did with `phone-list.html`. But note the use of the - `:phoneId` parameter declaration in the `path` argument of `$route.when()`: `$route` - services provides all the values for variables defined in this way as - `$route.current.params` map. In our route, `$route.current.params.phoneId` always holds - the current contents of the `:phoneId` portion of the URL. We will use the `phoneId` - parameter when we fetch the phone details in Step 8. - - * Any other URL fragment gets redirected to `/phones`. - - * __Controller/Scope inheritance.__ In the function passed into `$route`'s `onChange()` - method, we copied url parameters extracted from the current route to the `params` property in - the root scope. This property is inherited by child scopes created for our view controllers - and accessible by these controllers. - - * __Tests.__ To automatically verify that everything is wired properly, we write end to end - tests that navigate to various URLs and verify that the correct view was rendered. - - - - - - - - - -
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code -Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_08.ngdoc b/docs/tutorial.step_08.ngdoc deleted file mode 100755 index bd220f5a..00000000 --- a/docs/tutorial.step_08.ngdoc +++ /dev/null @@ -1,148 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 8 -@description - - - - - - - - -
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code -Diff}{@link tutorial.step_00 Next}
    - -In this step, we implement the Phone Details View template. Once again we will use {@link -angular.services.$xhr $xhr} to fetch our data, and we'll flesh out the `phone-details.html` View -template. - -__`app/partials/phone-details.html`:__ -
    -
    -
    -

    {{phone.name}}

    - -

    {{phone.description}}

    - -
      -
    • - -
    • -
    - -
      -
    • - Availability and Networks -
      -
      Availability
      -
      {{availability}}
      -
      -
    • - ... - - Additional Features -
      {{phone.additionalFeatures}}
      - -
    -
    - -__`app/js/controller.js`:__ -
    -function PhoneCatCtrl($route) (same as Step 7)
    -
    -function PhoneListCtrl($xhr) (same as Step 7)
    -
    -function PhoneDetailCtrl($xhr) {
    -  var self = this;
    -
    -  $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
    -    self.phone = response;
    -  });
    -}
    -
    -//PhoneDetailCtrl.$inject = ['$xhr'];
    -
    - -__`app/phones/nexus-s.json`:__ (sample snippet) -
    -{
    -  "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope,
    -  Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)", 
    -  "android": {
    -      "os": "Android 2.3", 
    -      "ui": "Android"
    -  }, 
    -  ...
    -  "images": [
    -      "img/phones/nexus-s.0.jpg", 
    -      "img/phones/nexus-s.1.jpg", 
    -      "img/phones/nexus-s.2.jpg", 
    -      "img/phones/nexus-s.3.jpg"
    -  ], 
    -  "storage": {
    -      "flash": "16384MB", 
    -      "ram": "512MB"
    -  }
    -}
    -
    - -__`test/unit/controllerSpec.js`:__ -
    -...
    -    it('should fetch phone detail', function(){
    -      scope.params = {phoneId:'xyz'};
    -      $browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
    -      ctrl = scope.$new(PhoneDetailCtrl);
    -
    -      expect(ctrl.phone).toBeUndefined();
    -      $browser.xhr.flush();
    -
    -      expect(ctrl.phone).toEqual({name:'phone xyz'});
    -    });
    -...
    -
    - -__`test/e2e/scenarios.js`:__ -
    -...
    -  describe('Phone detail view', function() {
    -
    -    beforeEach(function() {
    -      browser().navigateTo('../../app/index.html#/phones/nexus-s');
    -    });
    -
    -
    -    it('should display nexus-s page', function() {
    -      expect(binding('phone.name')).toBe('Nexus S');
    -    });
    -  });
    -...
    -
    - -## Discussion: - -* Phone Details View Template. There is nothing fancy or new here, just note where we use the -angular `{{ expression }}` markup and directives to project phone data from our model into the -view. - -* Note how we used the `$route` `params` object from the scope managed by the root controller -(`PhoneCatCtrl`), to construct the path for the phone details xhr request. The rest of this step -is simply applying the previously learned concepts and angular APIs to create a large template -that displays a lot of data about a phone. - -* Tests. We updated the existing end to end test and wrote a new unit test that is similar in -spirit to the one we wrote for the `PhoneListCtrl` controller. - - - - - - - - - -
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code -Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_09.ngdoc b/docs/tutorial.step_09.ngdoc deleted file mode 100755 index 9d952514..00000000 --- a/docs/tutorial.step_09.ngdoc +++ /dev/null @@ -1,108 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 9 -@description - - - - - - - - -
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code -Diff}{@link tutorial.step_00 Next}
    - -In this step, we have determined that the built-in angular display filters ({@link -angular.filter.number number}, {@link angular.filter.currency currency}, {@link -angular.filter.date date}, etc.) don't handle what we want to do, so we get to create our own -custom {@link angular.filter filter}. - -In the previous step, the details page displayed either "true" or "false" to indicate whether -certain phone features were present or not. Our custom "checkmark" filter replaces those text -strings with glyphs: ✓ for "true", and ✘ for "false". - -Our filter code lives in `app/js/filters.js`: - -__`app/index.html`:__ -
    -...
    - 
    - 
    - 
    -...
    -
    - -In the phone details template, we employ our filter for angular expressions whose values are -"true" or "false"; `{{ [phone_feature] | checkmark }}`: - -__`app/partials/phone-detail.html`:__ -
    -
    -

    {{phone.name}}

    -

    {{phone.description}}

    -... -
      - ... -
    • - Connectivity -
      -
      Network Support
      -
      {{phone.connectivity.cell}}
      -
      WiFi
      -
      {{phone.connectivity.wifi}}
      -
      Bluetooth
      -
      {{phone.connectivity.bluetooth}}
      -
      Infrared
      -
      {{phone.connectivity.infrared | checkmark}}
      -
      GPS
      -
      {{phone.connectivity.gps | checkmark}}
      -
      -
    • -... -
    -
    - -__`app/js/filters.js`:__ (New) -
    -angular.filter('checkmark', function(input) {
    -  return input ? '\u2713' : '\u2718';
    -});
    -
    - -__`test/unit/filtersSpec.js`:__ (New) -
    -describe('checkmark filter', function() {
    -
    -  it('should convert boolean values to unicode checkmark or cross', function() {
    -    expect(angular.filter.checkmark(true)).toBe('\u2713');
    -    expect(angular.filter.checkmark(false)).toBe('\u2718');
    -  });
    -})
    -
    - -## Discussion: - -* This example shows how easy it is to roll your own filters for displaying data. As explained in -the "Writing your own Filters" section of the {@link angular.filter angular.filter} page, you -simply register your custom filter function on to the `angular.filter` function. - -* In this example, our filter name is "checkmark"; our input is either "true" or "false", and we -return one of two unicode characters we have chosen to represent true or false (`\u2713` and -`\u2718`). - -* We created a new unit test to verify that our custom filter converts boolean values to unicode -characters. - - - - - - - - - -
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code -Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_10.ngdoc b/docs/tutorial.step_10.ngdoc deleted file mode 100644 index 130b4023..00000000 --- a/docs/tutorial.step_10.ngdoc +++ /dev/null @@ -1,110 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 10 -@description - - - - - - - - -
    {@link tutorial.step_09 Previous}{@link http://angular.github.com/angular-phonecat/step-10/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-9...step-10 -Code Diff}{@link tutorial.step_11 Next}
    - -The phone details view displays one large image of the current phone and several smaller thumbnail -images. It would be great if we could replace the large image with any of the thumbnails just by -clicking on the desired thumbnail image. Let's have a look how we can do this with angular. - -__`app/partials/phone-detail.html`:__ -
    -
    -
    -

    {{phone.name}}

    - -

    {{phone.description}}

    - -
      -
    • - -
    • -
    -... -
    - -__`app/js/controllers.js`:__ -
    -...
    -function PhoneDetailCtrl($xhr) {
    -  var self = this;
    -
    -  $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
    -    self.phone = response;
    -    self.mainImageUrl = response.images[0];
    -  });
    -
    -  self.setImage = function(imageUrl) {
    -    self.mainImageUrl = imageUrl;
    -  }
    -}
    -
    -//PhoneDetailCtrl.$inject = ['$xhr'];
    -
    - -__`test/e2e/scenarios.js`:__ -
    -/* jasmine-like end2end tests go here */
    -...
    -  describe('Phone detail view', function() {
    -
    -    beforeEach(function() {
    -      browser().navigateTo('../../app/index.html#/phones/nexus-s');
    -    });
    -
    -
    -    it('should display nexus-s page', function() {
    -      expect(binding('phone.name')).toBe('Nexus S');
    -    });
    -
    -    it('should display the first phone image as the main phone image', function() {
    -       expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
    -    });
    -
    -
    -    it('should swap main image if a thumbnail image is clicked on', function() {
    -      element('.phone-thumbs li:nth-child(3) img').click();
    -      expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.2.jpg');
    -
    -      element('.phone-thumbs li:nth-child(1) img').click();
    -      expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
    -    });
    -  });
    -});
    -
    - -## Discussion: - -Adding the phone image swapping feature is fairly straightforward: - -* We defined the `mainImageUrl` model property in the details controller (`PhoneDetailCtrl`) and -set the default value of `mainImageUrl` to the first image in the array of images. -* We created a `setImage` controller method to change `mainImageUrl` to the image clicked on by -the user. -* We registered an `{@link angular.directive.ng:click ng:click}` handler for thumb images to use -the `setImage` controller method. -* We expanded the end-to-end test to verify that our new feature is swapping images correctly. - - - - - - - - - - -
    {@link tutorial.step_09 Previous}{@link http://angular.github.com/angular-phonecat/step-10/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-9...step-10 -Code Diff}{@link tutorial.step_11 Next}
    diff --git a/docs/tutorial.step_11.ngdoc b/docs/tutorial.step_11.ngdoc deleted file mode 100644 index 34ba7b02..00000000 --- a/docs/tutorial.step_11.ngdoc +++ /dev/null @@ -1,178 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 11 -@description - - - - - - - - -
    {@link tutorial.step_10 Previous}{@link http://angular.github.com/angular-phonecat/step-11/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-10...step-11 -Code Diff}Next
    - -And so we arrive at the last step of this tutorial. Here we define a custom service that -represents a {@link http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. -Using this client we can make xhr requests for data in an easier way, without having to deal with -the lower-level {@link angular.service.$xhr $xhr} APIs, HTTP methods and URLs. - -__`app/index.html`.__ -
    -...
    -  
    -...
    -
    - - -__`app/js/services.js`.__ (New) -
    - angular.service('Phone', function($resource){
    -  return $resource('phones/:phoneId.json', {}, {
    -    query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
    -  });
    - });
    -
    - -__`app/js/controllers.js`.__ -
    -...
    -
    -function PhoneListCtrl(Phone_) {
    -  this.orderProp = 'age';
    -  this.phones = Phone_.query();
    -}
    -//PhoneListCtrl.$inject = ['Phone'];
    -
    -
    -function PhoneDetailCtrl(Phone_) {
    -  this.phone = Phone_.get({phoneId:this.params.phoneId});
    -}
    -//PhoneDetailCtrl.$inject = ['Phone'];
    -
    - -__`test/unit/controllersSpec.js`:__ -
    -/* jasmine specs for controllers go here */
    -describe('PhoneCat controllers', function() {
    -
    -  beforeEach(function(){
    -    this.addMatchers({
    -      toEqualData: function(expected) {
    -        return angular.equals(this.actual, expected);
    -      }
    -    });
    -  });
    -
    -  describe('PhoneListCtrl', function(){
    -    var scope, $browser, ctrl;
    -
    -    beforeEach(function() {
    -      scope = angular.scope();
    -      $browser = scope.$service('$browser');
    -
    -      $browser.xhr.expectGET('phones/phones.json').respond([{name: 'Nexus S'},
    -                                                            {name: 'Motorola DROID'}]);
    -      ctrl = scope.$new(PhoneListCtrl);
    -    });
    -
    -    it('should create "phones" model with 2 phones fetched from xhr', function() {
    -      expect(ctrl.phones).toEqual([]);
    -      $browser.xhr.flush();
    -
    -      expect(ctrl.phones).toEqualData([{name: 'Nexus S'},
    -                                       {name: 'Motorola DROID'}]);
    -    });
    -
    -    it('should set the default value of orderProp model', function() {
    -      expect(ctrl.orderProp).toBe('age');
    -    });
    -  });
    -
    -
    -  describe('PhoneDetailCtrl', function(){
    -    var scope, $browser, ctrl;
    -
    -    beforeEach(function() {
    -      scope = angular.scope();
    -      $browser = scope.$service('$browser');
    -    });
    -
    -    beforeEach(function() {
    -      scope = angular.scope();
    -      $browser = scope.$service('$browser');
    -    });
    -
    -    it('should fetch phone detail', function(){
    -      scope.params = {phoneId:'xyz'};
    -      $browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
    -      ctrl = scope.$new(PhoneDetailCtrl);
    -
    -      expect(ctrl.phone).toEqualData({});
    -      $browser.xhr.flush();
    -
    -      expect(ctrl.phone).toEqualData({name:'phone xyz'});
    -    });
    -  });
    -});
    -
    - - -## Discussion: - -* We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the -lower-level `$xhr` service, replacing it with a new service called `Phone`. Angular's {@link -angular.service.$resource `$resource`} service is easier to use than `$xhr` for interacting with -data sources exposed as RESTful resources. It is also easier now to understand what the code in -our controllers is doing. - - An important thing to notice in our controller code is that we don't pass any callback - functions when invoking methods of our Phone services. It looks as if the result were returned - synchronously. That is not the case at all. What is returned synchronously is a "future" — an - object, which will be filled with data when the xhr response returns. Because of the - data-binding in angular, we can use this future and bind it to our template. Then, when the - data arrives, the view will automatically update. See? Angular tries hard to make simple - stuff simple. - -* Once again we make use of `$route's` params, this time to construct the URL passed as a -parameter to `$resource` in our `services.js` script. - -* Last, but certainly not least, we expanded and modified our unit test to verify that our new -service is returning data as we expect it to. - - In our assertions we use a newly-defined `toEqualData` {@link - http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html Jasmine matcher}, which - compares only object properties and ignores methods. This is necessary, because the `$resource` - client will augment the response object with handy methods for updating and deleting the - resource (we don't use these in our tutorial though). - -There you have it! We have created a web app in a relatively short amount of time. - -## Closing Notes: - -* For more details and examples of the angular concepts we touched on in this tutorial, see the -{@link guide Developer Guide}. - -* For several more examples of sample code, see the {@link cookbook Cookbook}. - -* When you are ready to start developing a project using angular, be sure to begin with the {@link -https://github.com/angular/angular-seed angular seed app}. - -* We hope this tutorial was useful to you, and that you learned enough about angular to make you -want to learn more. Of course, we especially hope you are inspired to go out and develop angular -web apps of your own, and perhaps you might even be interested in {@link contribute contributing} -to angular. - - - - - - - - - -
    {@link tutorial.step_10 Previous}{@link http://angular.github.com/angular-phonecat/step-11/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-10...step-11 -Code Diff}Next
    -- cgit v1.2.3