Upgrade to angularjs 1.2.0 rc1
This commit is contained in:
parent
d223dfd662
commit
d6b021bfaf
674 changed files with 79667 additions and 62269 deletions
69
lib/angular/docs/partials/tutorial/index.html
Normal file → Executable file
69
lib/angular/docs/partials/tutorial/index.html
Normal file → Executable file
|
@ -1,16 +1,14 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/index.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/index.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><p>A great way to get introduced to AngularJS is to work through this tutorial, which walks you through
|
||||
<div><div class="tutorial-page tutorial-index-page"><p>A great way to get introduced to AngularJS is to work through this tutorial, which walks you through
|
||||
the construction of an AngularJS web app. The app you will build is a catalog that displays a list
|
||||
of Android devices, lets you filter the list to see only devices that interest you, and then view
|
||||
details for any device.</p>
|
||||
|
||||
<p><img class="diagram" src="img/tutorial/catalog_screen.png" width="488" height="413"></p>
|
||||
|
||||
<p>Work through the tutorial to see how Angular makes browsers smarter — without the use of extensions
|
||||
or plug-ins. As you work through the tutorial, you will:</p>
|
||||
|
||||
<ul>
|
||||
<li>See examples of how to use client-side data binding and dependency injection to build dynamic
|
||||
views of data that change immediately in response to user actions.</li>
|
||||
|
@ -19,11 +17,8 @@ views of data that change immediately in response to user actions.</li>
|
|||
<li>Learn how to use Angular services to make common web tasks, such as getting data into your app,
|
||||
easier.</li>
|
||||
</ul>
|
||||
|
||||
<p>And all of this works in any browser without modification to the browser!</p>
|
||||
|
||||
<p>When you finish the tutorial you will be able to:</p>
|
||||
|
||||
<ul>
|
||||
<li>Create a dynamic application that works in any browser.</li>
|
||||
<li>Define the differences between Angular and common JavaScript frameworks.</li>
|
||||
|
@ -32,81 +27,77 @@ easier.</li>
|
|||
<li>Create and run tests.</li>
|
||||
<li>Identify resources for learning more about AngularJS.</li>
|
||||
</ul>
|
||||
|
||||
<p>The tutorial guides you through the entire process of building a simple application, including
|
||||
writing and running unit and end-to-end tests. Experiments at the end of each step provide
|
||||
suggestions for you to learn more about AngularJS and the application you are building.</p>
|
||||
|
||||
<p>You can go through the whole tutorial in a couple of hours or you may want to spend a pleasant day
|
||||
really digging into it. If you're looking for a shorter introduction to AngularJS, check out the
|
||||
really digging into it. If you're looking for a shorter introduction to AngularJS, check out the
|
||||
<a href="misc/started">Getting Started</a> document.</p>
|
||||
|
||||
<h2>Working with the code</h2>
|
||||
|
||||
<p>You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
|
||||
environment. The tutorial relies on the use of Git versioning system for source code management.
|
||||
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
|
||||
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
|
||||
and follow the instructions for setting up your computer.</p>
|
||||
|
||||
<div class="tabbable" show="true">
|
||||
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
|
||||
<ol>
|
||||
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre class="prettyprint linenums">node --version</pre>
|
||||
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||
don't have it already:</p>
|
||||
<pre class="prettyprint linenums">npm install -g testacular</pre>
|
||||
<li><p>You'll also need Git, which you can get from
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
|
||||
don't have it already:</p>
|
||||
<pre class="prettyprint linenums">npm install -g karma</pre>
|
||||
<li><p>You'll also need Git, which you can get from
|
||||
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
|
||||
<li><p>Clone the angular-phonecat repository located at <a
|
||||
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<li><p>Clone the angular-phonecat repository located at <a href="a
|
||||
href="https://github.com/angular/angular-phonecat"">a
|
||||
href="https://github.com/angular/angular-phonecat"</a>Github</a> by running the following command:</p>
|
||||
<pre class="prettyprint linenums">git clone git://github.com/angular/angular-phonecat.git</pre>
|
||||
<p>This command creates the <code>angular-phonecat</code> directory in your current
|
||||
directory.</p></li>
|
||||
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
|
||||
<pre class="prettyprint linenums">cd angular-phonecat</pre>
|
||||
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
|
||||
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
|
||||
directory.</p></li>
|
||||
<li><p>You will need an http server running on your system. Mac and Linux machines typically
|
||||
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
|
||||
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
|
||||
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<p><div class="tab-pane well" id="git-win" title="Git on Windows">
|
||||
<div class="tab-pane well" id="git-win" title="Git on Windows">
|
||||
<ol>
|
||||
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre class="prettyprint linenums">node --version</pre>
|
||||
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||
don't have it already:</p>
|
||||
<pre class="prettyprint linenums">npm install -g testacular</pre>
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
|
||||
don't have it already:</p>
|
||||
<pre class="prettyprint linenums">npm install -g karma</pre>
|
||||
</li>
|
||||
<li><p>You'll also need Git, which you can get from
|
||||
<li><p>You'll also need Git, which you can get from
|
||||
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
|
||||
<li><p>Clone the angular-phonecat repository located at <a
|
||||
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<pre class="prettyprint linenums">git clone git://github.com/angular/angular-phonecat.git</pre>
|
||||
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
|
||||
<li><p>Change your current directory to angular-phonecat.</p>
|
||||
<p>This command creates the <code>angular-phonecat</code> directory in your current directory.</p></li>
|
||||
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
|
||||
<pre class="prettyprint linenums">cd angular-phonecat</pre>
|
||||
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
|
||||
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
|
||||
directory.</p>
|
||||
<p>You should run all <code>git</code> commands from Git bash.</p>
|
||||
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
|
||||
executed from the Windows command line.</li>
|
||||
<li><p>You need an http server running on your system, but if you don't already have one
|
||||
<li><p>You need an http server running on your system, but if you don't already have one
|
||||
already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
|
||||
bundled http server.</p></li>
|
||||
</ol>
|
||||
</div></p>
|
||||
</div>
|
||||
|
||||
<p>The last thing to do is to make sure your computer has a web browser and a good text editor
|
||||
installed. Now, let's get some cool stuff done!</p>
|
||||
|
||||
<p><a href="tutorial/step_00"><span class="btn btn-primary">Get Started!</span></a></p></div>
|
||||
installed. Now, let's get some cool stuff done!</p>
|
||||
<p><a href="tutorial/step_00"><span class="btn btn-primary">Get Started!</span></a></p>
|
||||
</div></div>
|
||||
|
|
121
lib/angular/docs/partials/tutorial/step_00.html
Normal file → Executable file
121
lib/angular/docs/partials/tutorial/step_00.html
Normal file → Executable file
|
@ -1,16 +1,17 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_00.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_00.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="0"></ul>
|
||||
<div><div class="tutorial-page tutorial-0-bootstrapping-page"><ul doc-tutorial-nav="0"></ul>
|
||||
|
||||
|
||||
<p>You are now ready to build the AngularJS phonecat app. In this step, you will become familiar
|
||||
with the most important source code files, learn how to start the development servers bundled with
|
||||
angular-seed, and run the application in the browser.</p>
|
||||
|
||||
<div class="tabbable" show="true" ng-model="$cookies.platformPreference">
|
||||
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux" value="gitUnix">
|
||||
<ol>
|
||||
<li><p>In angular-phonecat directory, run this command:</p>
|
||||
<li><p>In <code>angular-phonecat</code> directory, run this command:</p>
|
||||
<pre class="prettyprint linenums">git checkout -f step-0</pre>
|
||||
<p>This resets your workspace to step 0 of the tutorial app.</p>
|
||||
<p>You must repeat this for every future step in the tutorial and change the number to
|
||||
|
@ -22,9 +23,10 @@ angular-seed, and run the application in the browser.</p>
|
|||
<li><b>For node.js users:</b>
|
||||
<ol>
|
||||
<li>In a <i>separate</i> terminal tab or window, run
|
||||
<code>./scripts/web-server.js</code> to start the web server.</li>
|
||||
<li>Open a browser window for the app and navigate to <a
|
||||
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
|
||||
<code>node ./scripts/web-server.js</code> to start the web server.</li>
|
||||
<li>Open a browser window for the app and navigate to <a href="a
|
||||
href="http://localhost:8000/app/index.html"">a
|
||||
href="http://localhost:8000/app/index.html"</a><a href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><b>For other http servers:</b>
|
||||
|
@ -32,7 +34,7 @@ href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html
|
|||
<li>Configure the server to serve the files in the <code>angular-phonecat</code>
|
||||
directory.</li>
|
||||
<li>Navigate in your browser to
|
||||
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
|
||||
<code><a href="http://localhost:[port-number]/[context-path]/app/index.html">http://localhost:[port-number]/[context-path]/app/index.html</a></code>.</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -43,7 +45,7 @@ directory.</li>
|
|||
|
||||
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
|
||||
<ol>
|
||||
<li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
|
||||
<li><p>Open Git bash and run this command (in <code>angular-phonecat</code> directory):</p>
|
||||
<pre class="prettyprint linenums">git checkout -f step-0</pre>
|
||||
<p>This resets your workspace to step 0 of the tutorial app.</p>
|
||||
<p>You must repeat this for every future step in the tutorial and change the number to
|
||||
|
@ -55,8 +57,9 @@ directory.</li>
|
|||
<ol>
|
||||
<li>In a <i>separate</i> terminal tab or window, run <code>node
|
||||
scripts\web-server.js</code> to start the web server.</li>
|
||||
<li>Open a browser window for the app and navigate to <a
|
||||
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
|
||||
<li>Open a browser window for the app and navigate to <a href="a
|
||||
href="http://localhost:8000/app/index.html"">a
|
||||
href="http://localhost:8000/app/index.html"</a><a href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><b>For other http servers:</b>
|
||||
|
@ -64,7 +67,7 @@ href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html
|
|||
<li>Configure the server to serve the files in the <code>angular-phonecat</code>
|
||||
directory.</li>
|
||||
<li>Navigate in your browser to
|
||||
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
|
||||
<code><a href="http://localhost:[port-number]/[context-path]/app/index.html">http://localhost:[port-number]/[context-path]/app/index.html</a></code>.</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -73,11 +76,10 @@ directory.</li>
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<p>You can now see the page in your browser. It's not very exciting, but that's OK.</p>
|
||||
|
||||
<p>The HTML page that displays "Nothing here yet!" was constructed with the HTML code shown below.
|
||||
<p>You can now see the page in your browser. It's not very exciting, but that's OK.</p>
|
||||
<p>The HTML page that displays "Nothing here yet!" was constructed with the HTML code shown below.
|
||||
The code contains some key Angular elements that we will need going forward.</p>
|
||||
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<!doctype html>
|
||||
|
@ -96,111 +98,86 @@ The code contains some key Angular elements that we will need going forward.</p>
|
|||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
<h3>What is the code doing?</h3>
|
||||
|
||||
<h3>What is the code doing?</h2>
|
||||
<ul>
|
||||
<li><p><code>ng-app</code> directive:</p>
|
||||
|
||||
<pre><code> <html ng-app>
|
||||
</code></pre>
|
||||
|
||||
<pre><code> <html ng-app></code></pre>
|
||||
<p>The <code>ng-app</code> attribute represents an Angular directive (named <code>ngApp</code>; Angular uses
|
||||
<code>name-with-dashes</code> for attribute names and <code>camelCase</code> for the corresponding directive name)
|
||||
used to flag an element which Angular should consider to be the root element of our application.
|
||||
This gives application developers the freedom to tell Angular if the entire html page or only a
|
||||
portion of it should be treated as the Angular application.</p></li>
|
||||
portion of it should be treated as the Angular application.</p>
|
||||
</li>
|
||||
<li><p>AngularJS script tag:</p>
|
||||
|
||||
<pre><code> <script src="lib/angular/angular.js">
|
||||
</code></pre>
|
||||
|
||||
<pre><code> <script src="lib/angular/angular.js"></code></pre>
|
||||
<p>This code downloads the <code>angular.js</code> script and registers a callback that will be executed by the
|
||||
browser when the containing HTML page is fully downloaded. When the callback is executed, Angular
|
||||
looks for the <a href="api/ng.directive:ngApp"><code>ngApp</code></a> directive. If
|
||||
Angular finds the directive, it will bootstrap the application with the root of the application DOM
|
||||
being the element on which the <code>ngApp</code> directive was defined.</p></li>
|
||||
being the element on which the <code>ngApp</code> directive was defined.</p>
|
||||
</li>
|
||||
<li><p>Double-curly binding with an expression:</p>
|
||||
|
||||
<pre><code> Nothing here {{'yet' + '!'}}
|
||||
</code></pre>
|
||||
|
||||
<p>This line demonstrates the core feature of Angular's templating capabilities – a binding, denoted
|
||||
by double-curlies <code>{{ }}</code> as well as a simple expression <code>'yet' + '!'</code> used in this binding.</p>
|
||||
|
||||
<pre><code> Nothing here {{'yet' + '!'}}</code></pre>
|
||||
<p>This line demonstrates the core feature of Angular's templating capabilities – a binding, denoted
|
||||
by double-curlies <code>{{ }}</code> as well as a simple expression <code>'yet' + '!'</code> used in this binding.</p>
|
||||
<p>The binding tells Angular that it should evaluate an expression and insert the result into the
|
||||
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
|
||||
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
|
||||
binding will result in efficient continuous updates whenever the result of the expression
|
||||
evaluation changes.</p>
|
||||
|
||||
<p><a href="guide/expression">Angular expression</a> is a JavaScript-like code snippet that is
|
||||
evaluated by Angular in the context of the current model scope, rather than within the scope of
|
||||
the global context (<code>window</code>).</p>
|
||||
|
||||
<p>As expected, once this template is processed by Angular, the html page contains the text:
|
||||
"Nothing here yet!".</p></li>
|
||||
"Nothing here yet!".</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Bootstrapping AngularJS apps</h3>
|
||||
|
||||
<h2>Bootstrapping AngularJS apps</h2>
|
||||
<p>Bootstrapping AngularJS apps automatically using the <code>ngApp</code> directive is very easy and suitable
|
||||
for most cases. In advanced cases, such as when using script loaders, you can use
|
||||
<a href="guide/bootstrap">imperative / manual way</a> to bootstrap the app.</p>
|
||||
|
||||
<p>There are 3 important things that happen during the app bootstrap:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>The <a href="api/AUTO.$injector"><code>injector</code></a> that will be used for dependency injection
|
||||
within this app is created.</p></li>
|
||||
within this app is created.</p>
|
||||
</li>
|
||||
<li><p>The injector will then create the <a href="api/ng.$rootScope"><code>root scope</code></a> that will
|
||||
become the context for the model of our application.</p></li>
|
||||
<li><p>Angular will then "compile" the DOM starting at the <code>ngApp</code> root element, processing any
|
||||
directives and bindings found along the way.</p></li>
|
||||
become the context for the model of our application.</p>
|
||||
</li>
|
||||
<li><p>Angular will then "compile" the DOM starting at the <code>ngApp</code> root element, processing any
|
||||
directives and bindings found along the way.</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>Once an application is bootstrapped, it will then wait for incoming browser events (such as mouse
|
||||
click, key press or incoming HTTP response) that might change the model. Once such an event occurs,
|
||||
Angular detects if it caused any model changes and if changes are found, Angular will reflect them
|
||||
in the view by updating all of the affected bindings.</p>
|
||||
|
||||
<p>The structure of our application is currently very simple. The template contains just one directive
|
||||
and one static binding, and our model is empty. That will soon change!</p>
|
||||
|
||||
<p><img class="diagram" src="img/tutorial/tutorial_00.png"></p>
|
||||
|
||||
<h3>What are all these files in my working directory?</h3>
|
||||
|
||||
<h2>What are all these files in my working directory?</h3>
|
||||
<p>Most of the files in your working directory come from the <a href="https://github.com/angular/angular-seed">angular-seed project</a> which is typically used to bootstrap
|
||||
new Angular projects. The seed project includes the latest Angular libraries, test libraries,
|
||||
scripts and a simple example app, all pre-configured for developing a typical web app.</p>
|
||||
|
||||
<p>For the purposes of this tutorial, we modified the angular-seed with the following changes:</p>
|
||||
|
||||
<ul>
|
||||
<li>Removed the example app</li>
|
||||
<li>Added phone images to <code>app/img/phones/</code></li>
|
||||
<li>Added phone data files (JSON) to <code>app/phones/</code></li>
|
||||
<li>Added <a href="http://twitter.github.com/bootstrap/">Bootstrap</a> files to <code>app/css/</code> and <code>app/img/</code></li>
|
||||
</ul>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>Try adding a new expression to the <code>index.html</code> that will do some math:</p>
|
||||
|
||||
<pre><code> <p>1 + 2 = {{ 1 + 2 }}</p>
|
||||
</code></pre></li>
|
||||
<pre><code> <p>1 + 2 = {{ 1 + 2 }}</p></code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<p>Now let's go to <a href="tutorial/step_01">step 1</a> and add some content to the web app.</p>
|
||||
|
||||
<h1>Summary</h2>
|
||||
<p>Now let's go to <a href="tutorial/step_01">step 1</a> and add some content to the web app.</p>
|
||||
<ul doc-tutorial-nav="0"></ul>
|
||||
|
||||
<div style="display: none">
|
||||
Note: During the bootstrap the injector and the root scope will then be associated with the
|
||||
element on which the `ngApp` directive was declared, so when debugging the app you can retrieve
|
||||
them from browser console via `angular.element(rootElement).scope()` and
|
||||
`angular.element(rootElement).injector()`.
|
||||
</div></div>
|
||||
element on which the <code>ngApp</code> directive was declared, so when debugging the app you can retrieve
|
||||
them from browser console via <code>angular.element(rootElement).scope()</code> and
|
||||
<code>angular.element(rootElement).injector()</code>.
|
||||
</div></div></div>
|
||||
|
|
31
lib/angular/docs/partials/tutorial/step_01.html
Normal file → Executable file
31
lib/angular/docs/partials/tutorial/step_01.html
Normal file → Executable file
|
@ -1,21 +1,20 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_01.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_01.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="1"></ul>
|
||||
<div><div class="tutorial-page tutorial-1-static-template-page"><ul doc-tutorial-nav="1"></ul>
|
||||
|
||||
|
||||
<p>In order to illustrate how Angular enhances standard HTML, you will create a purely <em>static</em> HTML
|
||||
page and then examine how we can turn this HTML code into a template that Angular will use to
|
||||
dynamically display the same result with any set of data.</p>
|
||||
|
||||
<p>In this step you will add some basic information about two cell phones to an HTML page.</p>
|
||||
|
||||
<div doc-tutorial-reset="1">
|
||||
</div>
|
||||
|
||||
|
||||
<p>The page now contains a list with information about two phones.</p>
|
||||
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-0...step-1">GitHub</a>:</p>
|
||||
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<ul>
|
||||
|
@ -33,18 +32,12 @@ dynamically display the same result with any set of data.</p>
|
|||
</li>
|
||||
</ul>
|
||||
</pre>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>Try adding more static HTML to <code>index.html</code>. For example:</p>
|
||||
|
||||
<pre><code> <p>Total number of phones: 2</p>
|
||||
</code></pre></li>
|
||||
<pre><code> <p>Total number of phones: 2</p></code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<p>This addition to your app uses static HTML to display the list. Now, let's go to <a href="tutorial/step_02">step 2</a> to learn how to use AngularJS to dynamically generate the same list.</p>
|
||||
|
||||
<ul doc-tutorial-nav="1"></ul></div>
|
||||
<h1>Summary</h2>
|
||||
<p>This addition to your app uses static HTML to display the list. Now, let's go to <a href="tutorial/step_02">step 2</a> to learn how to use AngularJS to dynamically generate the same list.</p>
|
||||
<ul doc-tutorial-nav="1"></ul></div></div>
|
||||
|
|
154
lib/angular/docs/partials/tutorial/step_02.html
Normal file → Executable file
154
lib/angular/docs/partials/tutorial/step_02.html
Normal file → Executable file
|
@ -1,30 +1,26 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_02.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_02.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="2"></ul>
|
||||
<div><div class="tutorial-page tutorial-2-angular-templates-page"><ul doc-tutorial-nav="2"></ul>
|
||||
|
||||
<p>Now it's time to make the web page dynamic — with AngularJS. We'll also add a test that verifies the
|
||||
|
||||
<p>Now it's time to make the web page dynamic — with AngularJS. We'll also add a test that verifies the
|
||||
code for the controller we are going to add.</p>
|
||||
|
||||
<p>There are many ways to structure the code for an application. For Angular apps, we encourage the
|
||||
use of <a href="http://en.wikipedia.org/wiki/Model–View–Controller">the Model-View-Controller (MVC) design pattern</a> to decouple the code and to separate concerns. With that in mind, let's use a
|
||||
use of <a href="http://en.wikipedia.org/wiki/Model–View–Controller">the Model-View-Controller (MVC) design pattern</a> to decouple the code and to separate concerns. With that in mind, let's use a
|
||||
little Angular and JavaScript to add model, view, and controller components to our app.</p>
|
||||
|
||||
<div doc-tutorial-reset="2">
|
||||
</div>
|
||||
|
||||
|
||||
<p>The app now contains a list with three phones.</p>
|
||||
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-1...step-2">GitHub</a>:</p>
|
||||
|
||||
<h3>View and Template</h3>
|
||||
|
||||
<h3>View and Template</h2>
|
||||
<p>In Angular, the <strong>view</strong> is a projection of the model through the HTML <strong>template</strong>. This means that
|
||||
whenever the model changes, Angular refreshes the appropriate binding points, which updates the
|
||||
view.</p>
|
||||
|
||||
<p>The view component is constructed by Angular from this template:</p>
|
||||
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<html ng-app>
|
||||
|
@ -44,28 +40,24 @@ view.</p>
|
|||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
<p>We replaced the hard-coded phone list with the
|
||||
<a href="api/ng.directive:ngRepeat"><code>ngRepeat directive</code></a> and two
|
||||
<a href="guide/expression">Angular expressions</a> enclosed in curly braces:
|
||||
<code>{{phone.name}}</code> and <code>{{phone.snippet}}</code>:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>The <code>ng-repeat="phone in phones"</code> statement in the <code><li></code> tag is an Angular repeater. The
|
||||
<li><p>The <code>ng-repeat="phone in phones"</code> statement in the <code><li></code> tag is an Angular repeater. The
|
||||
repeater tells Angular to create a <code><li></code> element for each phone in the list using the first <code><li></code>
|
||||
tag as the template.</p></li>
|
||||
<li><p>As we've learned in step 0, the curly braces around <code>phone.name</code> and <code>phone.snippet</code> denote
|
||||
tag as the template.</p>
|
||||
</li>
|
||||
<li><p>As we've learned in step 0, the curly braces around <code>phone.name</code> and <code>phone.snippet</code> denote
|
||||
bindings. As opposed to evaluating constants, these expressions are referring to our application
|
||||
model, which was set up in our <code>PhoneListCtrl</code> controller.</p>
|
||||
|
||||
<p><img class="diagram" src="img/tutorial/tutorial_02.png"></p></li>
|
||||
<pre><code><img class="diagram" src="img/tutorial/tutorial_02.png"></code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Model and Controller</h3>
|
||||
|
||||
<h2>Model and Controller</h2>
|
||||
<p>The data <strong>model</strong> (a simple array of phones in object literal notation) is instantiated within
|
||||
the <code>PhoneListCtrl</code> <strong>controller</strong>:</p>
|
||||
|
||||
<p><strong><code>app/js/controllers.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
function PhoneListCtrl($scope) {
|
||||
|
@ -79,36 +71,31 @@ function PhoneListCtrl($scope) {
|
|||
];
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Although the controller is not yet doing very much controlling, it is playing a crucial role. By
|
||||
providing context for our data model, the controller allows us to establish data-binding between
|
||||
the model and the view. We connected the dots between the presentation, data, and logic components
|
||||
as follows:</p>
|
||||
|
||||
<ul>
|
||||
<li><p><code>PhoneListCtrl</code> — the name of our controller function (located in the JavaScript file
|
||||
<code>controllers.js</code>), matches the value of the
|
||||
<a href="api/ng.directive:ngController"><code>ngController</code></a> directive located
|
||||
on the <code><body></code> tag.</p></li>
|
||||
on the <code><body></code> tag.</p>
|
||||
</li>
|
||||
<li><p>The phone data is then attached to the <em>scope</em> (<code>$scope</code>) that was injected into our controller
|
||||
function. The controller scope is a prototypical descendant of the root scope that was created
|
||||
when the application bootstrapped. This controller scope is available to all bindings located within
|
||||
the <code><body ng-controller="PhoneListCtrl"></code> tag.</p>
|
||||
|
||||
the <code><body ng-controller="PhoneListCtrl"></code> tag.</p>
|
||||
<p>The concept of a scope in Angular is crucial; a scope can be seen as the glue which allows the
|
||||
template, model and controller to work together. Angular uses scopes, along with the information
|
||||
contained in the template, data model, and controller, to keep models and views separate, but in
|
||||
sync. Any changes made to the model are reflected in the view; any changes that occur in the view
|
||||
are reflected in the model.</p>
|
||||
|
||||
<p>To learn more about Angular scopes, see the <a href="api/ng.$rootScope.Scope"><code>angular scope documentation</code></a>.</p></li>
|
||||
<p>To learn more about Angular scopes, see the <a href="api/ng.$rootScope.Scope"><code>angular scope documentation</code></a>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Tests</h3>
|
||||
|
||||
<p>The "Angular way" makes it easy to test code as it is being developed. Take a look at the following
|
||||
<h2>Tests</h3>
|
||||
<p>The "Angular way" makes it easy to test code as it is being developed. Take a look at the following
|
||||
unit test for your newly created controller:</p>
|
||||
|
||||
<p><strong><code>test/unit/controllersSpec.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
describe('PhoneCat controllers', function() {
|
||||
|
@ -124,71 +111,58 @@ describe('PhoneCat controllers', function() {
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>The test verifies that we have three records in the phones array and the example demonstrates how
|
||||
easy it is to create a unit test for code in Angular. Since testing is such a critical part of
|
||||
software development, we make it easy to create tests in Angular so that developers are encouraged
|
||||
to write them.</p>
|
||||
|
||||
<p>Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
||||
<p>The test instantiates our PhoneListCtrl and verifies that its phones array property contains three
|
||||
records. This example demonstrates how easy it is to create a unit test for code in Angular. Since
|
||||
testing is such a critical part of software development, we make it easy to create tests in Angular
|
||||
so that developers are encouraged to write them.</p>
|
||||
<p>Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
||||
writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in
|
||||
this tutorial in Jasmine. You can learn about Jasmine on the <a href="http://pivotal.github.com/jasmine/">Jasmine home page</a> and on the <a href="https://github.com/pivotal/jasmine/wiki">Jasmine wiki</a>.</p>
|
||||
|
||||
<p>The angular-seed project is pre-configured to run all unit tests using <a href="http://vojtajina.github.com/testacular/">Testacular</a>. To run the test, do the following:</p>
|
||||
|
||||
<p>The angular-seed project is pre-configured to run all unit tests using <a href="http://karma-runner.github.io/">Karma</a>. To run the test, do the following:</p>
|
||||
<ol>
|
||||
<li><p>In a <em>separate</em> terminal window or tab, go to the <code>angular-phonecat</code> directory and run
|
||||
<code>./scripts/test.sh</code> to start the Testacular server.</p></li>
|
||||
<li><p>Testacular will start a new instance of Chrome browser automatically. Just ignore it and let it run in
|
||||
the background. Testacular will use this browser for test execution.</p></li>
|
||||
<code>./scripts/test.sh</code> to start the Karma server (the config file necessary to start the server
|
||||
is located at <code>./config/karma.conf.js</code>).</p>
|
||||
</li>
|
||||
<li><p>Karma will start a new instance of Chrome browser automatically. Just ignore it and let it run in
|
||||
the background. Karma will use this browser for test execution.</p>
|
||||
</li>
|
||||
<li><p>You should see the following or similar output in the terminal:</p>
|
||||
|
||||
<pre><code> info: Testacular server started at http://localhost:9876/
|
||||
info (launcher): Starting browser "Chrome"
|
||||
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
|
||||
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
|
||||
</code></pre>
|
||||
|
||||
<p>Yay! The test passed! Or not...</p></li>
|
||||
<li><p>To rerun the tests, just change any of the source or test files. Testacular will notice the change
|
||||
and will rerun the tests for you. Now isn't that sweet?</p></li>
|
||||
<pre><code> info: Karma server started at http://localhost:9876/
|
||||
info (launcher): Starting browser "Chrome"
|
||||
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
|
||||
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)</code></pre>
|
||||
<p>Yay! The test passed! Or not...</p>
|
||||
</li>
|
||||
<li><p>To rerun the tests, just change any of the source or test files. Karma will notice the change
|
||||
and will rerun the tests for you. Now isn't that sweet?</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>Add another binding to <code>index.html</code>. For example:</p>
|
||||
|
||||
<pre><code> <p>Total number of phones: {{phones.length}}</p>
|
||||
</code></pre></li>
|
||||
<pre><code> <p>Total number of phones: {{phones.length}}</p></code></pre>
|
||||
</li>
|
||||
<li><p>Create a new model property in the controller and bind to it from the template. For example:</p>
|
||||
|
||||
<pre><code> $scope.hello = "Hello, World!"
|
||||
</code></pre>
|
||||
|
||||
<p>Refresh your browser to make sure it says, "Hello, World!"</p></li>
|
||||
<pre><code> $scope.hello = "Hello, World!"</code></pre>
|
||||
<p>Refresh your browser to make sure it says, "Hello, World!"</p>
|
||||
</li>
|
||||
<li><p>Create a repeater that constructs a simple table:</p>
|
||||
|
||||
<pre><code> <table>
|
||||
<tr><th>row number</th></tr>
|
||||
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i}}</td></tr>
|
||||
</table>
|
||||
</code></pre>
|
||||
|
||||
<pre><code> <table>
|
||||
<tr><th>row number</th></tr>
|
||||
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i}}</td></tr>
|
||||
</table></code></pre>
|
||||
<p>Now, make the list 1-based by incrementing <code>i</code> by one in the binding:</p>
|
||||
|
||||
<pre><code> <table>
|
||||
<tr><th>row number</th></tr>
|
||||
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
|
||||
</table>
|
||||
</code></pre></li>
|
||||
<li><p>Make the unit test fail by changing the <code>toBe(3)</code> statement to <code>toBe(4)</code>.</p></li>
|
||||
<pre><code> <table>
|
||||
<tr><th>row number</th></tr>
|
||||
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
|
||||
</table></code></pre>
|
||||
</li>
|
||||
<li><p>Make the unit test fail by changing the <code>toBe(3)</code> statement to <code>toBe(4)</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<h1>Summary</h2>
|
||||
<p>You now have a dynamic app that features separate model, view, and controller components, and you
|
||||
are testing as you go. Now, let's go to <a href="tutorial/step_03">step 3</a> to learn how to add full text search
|
||||
are testing as you go. Now, let's go to <a href="tutorial/step_03">step 3</a> to learn how to add full text search
|
||||
to the app.</p>
|
||||
|
||||
<ul doc-tutorial-nav="2"></ul></div>
|
||||
<ul doc-tutorial-nav="2"></ul></div></div>
|
||||
|
|
124
lib/angular/docs/partials/tutorial/step_03.html
Normal file → Executable file
124
lib/angular/docs/partials/tutorial/step_03.html
Normal file → Executable file
|
@ -1,28 +1,25 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_03.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_03.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="3"></ul>
|
||||
<div><div class="tutorial-page tutorial-3-filtering-repeaters-page"><ul doc-tutorial-nav="3"></ul>
|
||||
|
||||
<p>We did a lot of work in laying a foundation for the app in the last step, so now we'll do something
|
||||
|
||||
<p>We did a lot of work in laying a foundation for the app in the last step, so now we'll do something
|
||||
simple; we will add full text search (yes, it will be simple!). 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.</p>
|
||||
|
||||
<div doc-tutorial-reset="3">
|
||||
</div>
|
||||
|
||||
|
||||
<p>The app now has a search box. Notice that the phone list on the page changes depending on what a
|
||||
user types into the search box.</p>
|
||||
|
||||
<p>The most important differences between Steps 2 and 3 are listed below. You can see the full diff on
|
||||
<a href="https://github.com/angular/angular-phonecat/compare/step-2...step-3">GitHub</a>:</p>
|
||||
|
||||
<h3>Controller</h3>
|
||||
|
||||
<h3>Controller</h2>
|
||||
<p>We made no changes to the controller.</p>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h2>Template</h2>
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<div class="container-fluid">
|
||||
|
@ -47,41 +44,33 @@ user types into the search box.</p>
|
|||
</div>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<p>We added a standard HTML <code><input></code> tag and used Angular's
|
||||
<p>We added a standard HTML <code><input></code> tag and used Angular's
|
||||
<a href="api/ng.filter:filter"><code>$filter</code></a> function to process the input for the
|
||||
<a href="api/ng.directive:ngRepeat"><code>ngRepeat</code></a> directive.</p>
|
||||
|
||||
<p>This lets a user enter search criteria and immediately see the effects of their search on the phone
|
||||
list. This new code demonstrates the following:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>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.</p>
|
||||
|
||||
<p>In this code, the data that a user types into the input box (named <strong><code>query</code></strong>) is immediately
|
||||
available as a filter input in the list repeater (<code>phone in phones | filter:</code><strong><code>query</code></strong>). When
|
||||
changes to the data model cause the repeater's input to change, the repeater efficiently updates
|
||||
changes to the data model cause the repeater's input to change, the repeater efficiently updates
|
||||
the DOM to reflect the current state of the model.</p>
|
||||
|
||||
<p><img class="diagram" src="img/tutorial/tutorial_03.png"></p></li>
|
||||
<pre><code><img class="diagram" src="img/tutorial/tutorial_03.png"></code></pre>
|
||||
</li>
|
||||
<li><p>Use of the <code>filter</code> filter: The <a href="api/ng.filter:filter"><code>filter</code></a> function uses the
|
||||
<code>query</code> value to create a new array that contains only those records that match the <code>query</code>.</p>
|
||||
|
||||
<p><code>ngRepeat</code> automatically updates the view in response to the changing number of phones returned
|
||||
by the <code>filter</code> filter. The process is completely transparent to the developer.</p></li>
|
||||
by the <code>filter</code> filter. The process is completely transparent to the developer.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<h2>Test</h3>
|
||||
<p>In Step 2, we learned how to write and run unit tests. Unit tests are perfect for testing
|
||||
controllers and other components of our application written in JavaScript, but they can't easily
|
||||
controllers and other components of our application written in JavaScript, but they can't easily
|
||||
test DOM manipulation or the wiring of our application. For these, an end-to-end test is a much
|
||||
better choice.</p>
|
||||
|
||||
<p>The search feature was fully implemented via templates and data-binding, so we'll write our first
|
||||
<p>The search feature was fully implemented via templates and data-binding, so we'll write our first
|
||||
end-to-end test, to verify that the feature works.</p>
|
||||
|
||||
<p><strong><code>test/e2e/scenarios.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
describe('PhoneCat App', function() {
|
||||
|
@ -105,63 +94,44 @@ describe('PhoneCat App', function() {
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>Even though the syntax of this test looks very much like our controller unit test written with
|
||||
Jasmine, the end-to-end test uses APIs of <a href="guide/dev_guide.e2e-testing">Angular's end-to-end test runner</a>.</p>
|
||||
|
||||
Jasmine, the end-to-end test uses APIs of <a href="guide/dev_guide.e2e-testing">Angular's end-to-end test runner</a>.</p>
|
||||
<p>To run the end-to-end test, open one of the following in a new browser tab:</p>
|
||||
|
||||
<ul>
|
||||
<li>node.js users: <a href="http://localhost:8000/test/e2e/runner.html">http://localhost:8000/test/e2e/runner.html</a></li>
|
||||
<li>node.js users: <a href="http://localhost:8000/test/e2e/runner.html"><a href="http://localhost:8000/test/e2e/runner.html">http://localhost:8000/test/e2e/runner.html</a></a></li>
|
||||
<li>users with other http servers:
|
||||
<code>http://localhost:[port-number]/[context-path]/test/e2e/runner.html</code></li>
|
||||
<li>casual reader: <a href="http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html">http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html</a></li>
|
||||
<li>casual reader: <a href="http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html"><a href="http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html">http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html</a></a></li>
|
||||
</ul>
|
||||
|
||||
<p>Previously we've seen how Testacular can be used to execute unit tests. Well, it can also run the
|
||||
<p>Previously we've seen how Karma can be used to execute unit tests. Well, it can also run the
|
||||
end-to-end tests! Use <code>./scripts/e2e-test.sh</code> script for that. End-to-end tests are slow, so unlike
|
||||
with unit tests, Testacular will exit after the test run and will not automatically rerun the test
|
||||
with unit tests, Karma will exit after the test run and will not automatically rerun the test
|
||||
suite on every file change. To rerun the test suite, execute the <code>e2e-test.sh</code> script again.</p>
|
||||
|
||||
<p>This test verifies that the search box and the repeater are correctly wired together. Notice how
|
||||
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
|
||||
really is that easy to set up any functional, readable, end-to-end test.</p>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>Display the current value of the <code>query</code> model by adding a <code>{{query}}</code> binding into the
|
||||
<code>index.html</code> template, and see how it changes when you type in the input box.</p></li>
|
||||
<li><p>Let's see how we can get the current value of the <code>query</code> model to appear in the HTML page title.</p>
|
||||
|
||||
<p>You might think you could just add the {{query}} to the title tag element as follows:</p>
|
||||
|
||||
<pre><code> <title>Google Phone Gallery: {{query}}</title>
|
||||
</code></pre>
|
||||
|
||||
<p>However, when you reload the page, you won't see the expected result. This is because the "query"
|
||||
model lives in the scope defined by the body element:</p>
|
||||
|
||||
<pre><code> <body ng-controller="PhoneListCtrl">
|
||||
</code></pre>
|
||||
|
||||
<code>index.html</code> template, and see how it changes when you type in the input box.</p>
|
||||
</li>
|
||||
<li><p>Let's see how we can get the current value of the <code>query</code> model to appear in the HTML page title.</p>
|
||||
<p>You might think you could just add the <code>{{query}}</code> to the title tag element as follows:</p>
|
||||
<pre><code> <title>Google Phone Gallery: {{query}}</title></code></pre>
|
||||
<p>However, when you reload the page, you won't see the expected result. This is because the "query"
|
||||
model lives in the scope, defined by the <code>ng-controller="PhoneListCtrl"</code> directive, on the body element:</p>
|
||||
<pre><code> <body ng-controller="PhoneListCtrl"></code></pre>
|
||||
<p>If you want to bind to the query model from the <code><title></code> element, you must <strong>move</strong> the
|
||||
<code>ngController</code> declaration to the HTML element because it is the common parent of both the body
|
||||
and title elements:</p>
|
||||
|
||||
<pre><code> <html ng-app ng-controller="PhoneListCtrl">
|
||||
</code></pre>
|
||||
|
||||
<pre><code> <html ng-app ng-controller="PhoneListCtrl"></code></pre>
|
||||
<p>Be sure to <strong>remove</strong> the <code>ng-controller</code> declaration from the body element.</p>
|
||||
|
||||
<p>While using double curlies works fine within the title element, you might have noticed that
|
||||
for a split second they are actually displayed to the user while the page is loading. A better
|
||||
solution would be to use the <a href="api/ng.directive:ngBind"><code>ngBind</code></a> or <a href="api/ng.directive:ngBindTemplate"><code>ngBindTemplate</code></a> directives, which are invisible to the user while the page is loading:</p>
|
||||
|
||||
<pre><code> <title ng-bind-template="Google Phone Gallery: {{query}}">Google Phone Gallery</title>
|
||||
</code></pre></li>
|
||||
<pre><code> <title ng-bind-template="Google Phone Gallery: {{query}}">Google Phone Gallery</title></code></pre>
|
||||
</li>
|
||||
<li><p>Add the following end-to-end test into the <code>describe</code> block within <code>test/e2e/scenarios.js</code>:</p>
|
||||
|
||||
<pre class="prettyprint linenums">
|
||||
it('should display the current filter value within an element with id "status"',
|
||||
function() {
|
||||
|
@ -175,22 +145,18 @@ solution would be to use the <a href="api/ng.directive:ngBind"><code>ngBind</cod
|
|||
using('#status').expect(binding('query')).toBe('nexus');
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test
|
||||
pass, edit the <code>index.html</code> template to add a <code>div</code> or <code>p</code> element with <code>id</code> <code>"status"</code> and content
|
||||
with the <code>query</code> binding, prefixed by "Current filter:". For instance:</p>
|
||||
|
||||
<pre><code> <div id="status">Current filter: {{query}}</div>
|
||||
</code></pre></li>
|
||||
<li><p>Add a <code>pause()</code> statement inside of an end-to-end test and rerun it. You'll see the runner pause;
|
||||
pass, edit the <code>index.html</code> template to add a <code>div</code> or <code>p</code> element with <code>id</code> <code>"status"</code> and content
|
||||
with the <code>query</code> binding, prefixed by "Current filter:". For instance:</p>
|
||||
<pre><code> <div id="status">Current filter: {{query}}</div></code></pre>
|
||||
</li>
|
||||
<li><p>Add a <code>pause()</code> statement inside of an end-to-end test and rerun it. You'll see the runner pause;
|
||||
this gives you the opportunity to explore the state of your application while it is displayed in
|
||||
the browser. The app is live! You can change the search query to prove it. Notice how useful this
|
||||
is for troubleshooting end-to-end tests.</p></li>
|
||||
is for troubleshooting end-to-end tests.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<p>We have now added full text search and included a test to verify that search works! Now let's go on
|
||||
<h1>Summary</h2>
|
||||
<p>We have now added full text search and included a test to verify that search works! Now let's go on
|
||||
to <a href="tutorial/step_04">step 4</a> to learn how to add sorting capability to the phone app.</p>
|
||||
|
||||
<ul doc-tutorial-nav="3"></ul></div>
|
||||
<ul doc-tutorial-nav="3"></ul></div></div>
|
||||
|
|
91
lib/angular/docs/partials/tutorial/step_04.html
Normal file → Executable file
91
lib/angular/docs/partials/tutorial/step_04.html
Normal file → Executable file
|
@ -1,23 +1,22 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_04.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_04.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="4"></ul>
|
||||
<div><div class="tutorial-page tutorial-4-two-way-data-binding-page"><ul doc-tutorial-nav="4"></ul>
|
||||
|
||||
|
||||
<p>In this step, you will add a feature to let your users control the order of the items in the phone
|
||||
list. The dynamic ordering is implemented by creating a new model property, wiring it together with
|
||||
the repeater, and letting the data binding magic do the rest of the work.</p>
|
||||
|
||||
<div doc-tutorial-reset="4">
|
||||
</div>
|
||||
|
||||
|
||||
<p>You should see that in addition to the search box, the app displays a drop down menu that allows
|
||||
users to control the order in which the phones are listed.</p>
|
||||
|
||||
<p>The most important differences between Steps 3 and 4 are listed below. You can see the full diff on
|
||||
<a href="https://github.com/angular/angular-phonecat/compare/step-3...step-4">GitHub</a>:</p>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h3>Template</h2>
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
Search: <input ng-model="query">
|
||||
|
@ -35,29 +34,24 @@ users to control the order in which the phones are listed.</p>
|
|||
</li>
|
||||
</ul>
|
||||
</pre>
|
||||
|
||||
<p>We made the following changes to the <code>index.html</code> template:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>First, we added a <code><select></code> html element named <code>orderProp</code>, so that our users can pick from the
|
||||
two provided sorting options.</p>
|
||||
|
||||
<p><img class="diagram" src="img/tutorial/tutorial_04.png"></p></li>
|
||||
<pre><code><img class="diagram" src="img/tutorial/tutorial_04.png"></code></pre>
|
||||
</li>
|
||||
<li><p>We then chained the <code>filter</code> filter with <a href="api/ng.filter:orderBy"><code><code>orderBy</code></code></a>
|
||||
filter to further process the input into the repeater. <code>orderBy</code> is a filter that takes an input
|
||||
array, copies it and reorders the copy which is then returned.</p></li>
|
||||
array, copies it and reorders the copy which is then returned.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Angular creates a two way data-binding between the select element and the <code>orderProp</code> model.
|
||||
<code>orderProp</code> is then used as the input for the <code>orderBy</code> filter.</p>
|
||||
|
||||
<p>As we discussed in the section about data-binding and the repeater in step 3, whenever the model
|
||||
changes (for example because a user changes the order with the select drop down menu), Angular's
|
||||
changes (for example because a user changes the order with the select drop down menu), Angular's
|
||||
data-binding will cause the view to automatically update. No bloated DOM manipulation code is
|
||||
necessary!</p>
|
||||
|
||||
<h3>Controller</h3>
|
||||
|
||||
<h2>Controller</h2>
|
||||
<p><strong><code>app/js/controllers.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
function PhoneListCtrl($scope) {
|
||||
|
@ -76,27 +70,24 @@ function PhoneListCtrl($scope) {
|
|||
$scope.orderProp = 'age';
|
||||
}
|
||||
</pre>
|
||||
|
||||
<ul>
|
||||
<li><p>We modified the <code>phones</code> model - the array of phones - and added an <code>age</code> property to each phone
|
||||
record. This property is used to order phones by age.</p></li>
|
||||
record. This property is used to order phones by age.</p>
|
||||
</li>
|
||||
<li><p>We added a line to the controller that sets the default value of <code>orderProp</code> to <code>age</code>. If we had
|
||||
not set the default value here, the model would stay uninitialized until our user would pick an
|
||||
option from the drop down menu.</p>
|
||||
|
||||
<p>This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
|
||||
browser, "Newest" is selected in the drop down menu. This is because we set <code>orderProp</code> to <code>'age'</code>
|
||||
browser, "Newest" is selected in the drop down menu. This is because we set <code>orderProp</code> to <code>'age'</code>
|
||||
in the controller. So the binding works in the direction from our model to the UI. Now if you
|
||||
select "Alphabetically" in the drop down menu, the model will be updated as well and the phones
|
||||
select "Alphabetically" in the drop down menu, the model will be updated as well and the phones
|
||||
will be reordered. That is the data-binding doing its job in the opposite direction — from the UI
|
||||
to the model.</p></li>
|
||||
to the model.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<p>The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
||||
<h2>Test</h3>
|
||||
<p>The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
||||
the unit test first.</p>
|
||||
|
||||
<p><strong><code>test/unit/controllersSpec.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
describe('PhoneCat controllers', function() {
|
||||
|
@ -121,19 +112,12 @@ describe('PhoneCat controllers', function() {
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>The unit test now verifies that the default ordering property is set.</p>
|
||||
|
||||
<p>We used Jasmine's API to extract the controller construction into a <code>beforeEach</code> block, which is
|
||||
<p>We used Jasmine's API to extract the controller construction into a <code>beforeEach</code> block, which is
|
||||
shared by all tests in the parent <code>describe</code> block.</p>
|
||||
|
||||
<p>You should now see the following output in the Testacular tab:</p>
|
||||
|
||||
<pre><code> Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
|
||||
</code></pre>
|
||||
|
||||
<p>Let's turn our attention to the end-to-end test.</p>
|
||||
|
||||
<p>You should now see the following output in the Karma tab:</p>
|
||||
<pre><code> Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)</code></pre>
|
||||
<p>Let's turn our attention to the end-to-end test.</p>
|
||||
<p><strong><code>test/e2e/scenarios.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -154,25 +138,22 @@ shared by all tests in the parent <code>describe</code> block.</p>
|
|||
});
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>The end-to-end test verifies that the ordering mechanism of the select box is working correctly.</p>
|
||||
|
||||
<p>You can now rerun <code>./scripts/e2e-test.sh</code> or refresh the browser tab with the end-to-end test
|
||||
<code>runner.html</code> to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
<code>runner.html</code> to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>In the <code>PhoneListCtrl</code> controller, remove the statement that sets the <code>orderProp</code> value and
|
||||
you'll see that Angular will temporarily add a new "unknown" option to the drop-down list and the
|
||||
ordering will default to unordered/natural order.</p></li>
|
||||
you'll see that Angular will temporarily add a new "unknown" option to the drop-down list and the
|
||||
ordering will default to unordered/natural order.</p>
|
||||
</li>
|
||||
<li><p>Add an <code>{{orderProp}}</code> binding into the <code>index.html</code> template to display its current value as
|
||||
text.</p></li>
|
||||
text.</p>
|
||||
</li>
|
||||
<li><p>Reverse the sort order by adding a <code>-</code> symbol before the sorting value: <code><option value="-age">Oldest</option></code></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<h1>Summary</h2>
|
||||
<p>Now that you have added list sorting and tested the app, go to <a href="tutorial/step_05">step 5</a> to learn
|
||||
about Angular services and how Angular uses dependency injection.</p>
|
||||
|
||||
<ul doc-tutorial-nav="4"></ul></div>
|
||||
<ul doc-tutorial-nav="4"></ul></div></div>
|
||||
|
|
149
lib/angular/docs/partials/tutorial/step_05.html
Normal file → Executable file
149
lib/angular/docs/partials/tutorial/step_05.html
Normal file → Executable file
|
@ -1,23 +1,21 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_05.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_05.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="5"></ul>
|
||||
<div><div class="tutorial-page tutorial-5-xhrs-dependency-injection-page"><ul doc-tutorial-nav="5"></ul>
|
||||
|
||||
<p>Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
|
||||
from our server using one of angular's built-in <a href="api/ng">services</a> called <a href="api/ng.$http"><code>$http</code></a>. We will use angular's <a href="guide/di">dependency injection (DI)</a> to provide the service to the <code>PhoneListCtrl</code> controller.</p>
|
||||
|
||||
<p>Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
|
||||
from our server using one of angular's built-in <a href="api/ng">services</a> called <a href="api/ng.$http"><code>$http</code></a>. We will use angular's <a href="guide/di">dependency injection (DI)</a> to provide the service to the <code>PhoneListCtrl</code> controller.</p>
|
||||
<div doc-tutorial-reset="5">
|
||||
</div>
|
||||
|
||||
|
||||
<p>You should now see a list of 20 phones.</p>
|
||||
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-4...step-5">GitHub</a>:</p>
|
||||
|
||||
<h3>Data</h3>
|
||||
|
||||
<h3>Data</h2>
|
||||
<p>The <code>app/phones/phones.json</code> file in your project is a dataset that contains a larger list of phones
|
||||
stored in the JSON format.</p>
|
||||
|
||||
<p>Following is a sample of the file:
|
||||
<pre class="prettyprint linenums">
|
||||
[
|
||||
|
@ -31,19 +29,15 @@ stored in the JSON format.</p>
|
|||
...
|
||||
]
|
||||
</pre>
|
||||
|
||||
<h3>Controller</h3>
|
||||
|
||||
<p>We'll use angular's <a href="api/ng.$http"><code>$http</code></a> service in our controller to make an HTTP
|
||||
<h2>Controller</h2>
|
||||
<p>We'll use angular's <a href="api/ng.$http"><code>$http</code></a> service in our controller to make an HTTP
|
||||
request to your web server to fetch the data in the <code>app/phones/phones.json</code> file. <code>$http</code> is just
|
||||
one of several built-in <a href="api/ng">angular services</a> that handle common operations
|
||||
one of several built-in <a href="guide/dev_guide.services">angular services</a> that handle common operations
|
||||
in web apps. Angular injects these services for you where you need them.</p>
|
||||
|
||||
<p>Services are managed by angular's <a href="guide/di">DI subsystem</a>. Dependency injection
|
||||
<p>Services are managed by angular's <a href="guide/di">DI subsystem</a>. Dependency injection
|
||||
helps to make your web apps both well-structured (e.g., separate components for presentation, data,
|
||||
and control) and loosely coupled (dependencies between components are not resolved by the
|
||||
components themselves, but by the DI subsystem).</p>
|
||||
|
||||
<p><strong><code>app/js/controllers.js:</code></strong>
|
||||
<pre class="prettyprint linenums">
|
||||
function PhoneListCtrl($scope, $http) {
|
||||
|
@ -56,79 +50,59 @@ function PhoneListCtrl($scope, $http) {
|
|||
|
||||
//PhoneListCtrl.$inject = ['$scope', '$http'];
|
||||
</pre>
|
||||
|
||||
<p><code>$http</code> makes an HTTP GET request to our web server, asking for <code>phone/phones.json</code> (the url is
|
||||
relative to our <code>index.html</code> file). The server responds by providing the data in the json file.
|
||||
(The response might just as well have been dynamically generated by a backend server. To the
|
||||
browser and our app they both look the same. For the sake of simplicity we used a json file in this
|
||||
tutorial.)</p>
|
||||
|
||||
<p>The <code>$http</code> service returns a <a href="api/ng.$q"><code>promise object</code></a> with a <code>success</code>
|
||||
method. We call this method to handle the asynchronous response and assign the phone data to the
|
||||
scope controlled by this controller, as a model called <code>phones</code>. Notice that angular detected the
|
||||
json response and parsed it for us!</p>
|
||||
|
||||
<p>To use a service in angular, you simply declare the names of the dependencies you need as arguments
|
||||
to the controller's constructor function, as follows:</p>
|
||||
|
||||
<pre><code>function PhoneListCtrl($scope, $http) {...}
|
||||
</code></pre>
|
||||
|
||||
<p>Angular's dependency injector provides services to your controller when the controller is being
|
||||
to the controller's constructor function, as follows:</p>
|
||||
<pre><code>function PhoneListCtrl($scope, $http) {...}</code></pre>
|
||||
<p>Angular's dependency injector provides services to your controller when the controller is being
|
||||
constructed. The dependency injector also takes care of creating any transitive dependencies the
|
||||
service may have (services often depend upon other services).</p>
|
||||
|
||||
<p>Note that the names of arguments are significant, because the injector uses these to look up the
|
||||
dependencies.</p>
|
||||
|
||||
<p><img class="diagram" src="img/tutorial/xhr_service_final.png"></p>
|
||||
|
||||
<h4>'$' Prefix Naming Convention</h4>
|
||||
|
||||
<h4>'$' Prefix Naming Convention</h3>
|
||||
<p>You can create your own services, and in fact we will do exactly that in step 11. As a naming
|
||||
convention, angular's built-in services, Scope methods and a few other angular APIs have a '$'
|
||||
prefix in front of the name. Don't use a '$' prefix when naming your services and models, in order
|
||||
convention, angular's built-in services, Scope methods and a few other angular APIs have a '$'
|
||||
prefix in front of the name. Don't use a '$' prefix when naming your services and models, in order
|
||||
to avoid any possible naming collisions.</p>
|
||||
|
||||
<h4>A Note on Minification</h4>
|
||||
|
||||
<p>Since angular infers the controller's dependencies from the names of arguments to the controller's
|
||||
<h3>A Note on Minification</h4>
|
||||
<p>Since angular infers the controller's dependencies from the names of arguments to the controller's
|
||||
constructor function, if you were to <a href="http://en.wikipedia.org/wiki/Minification_(programming)">minify</a> the JavaScript code for <code>PhoneListCtrl</code> controller, all of its function arguments would be
|
||||
minified as well, and the dependency injector would not be able to identify services correctly.</p>
|
||||
|
||||
<p>To overcome issues caused by minification, just assign an array with service identifier strings
|
||||
into the <code>$inject</code> property of the controller function, just like the last line in the snippet
|
||||
(commented out) suggests:</p>
|
||||
|
||||
<pre><code>PhoneListCtrl.$inject = ['$scope', '$http'];
|
||||
</code></pre>
|
||||
|
||||
<pre><code>PhoneListCtrl.$inject = ['$scope', '$http'];</code></pre>
|
||||
<p>There is also one more way to specify this dependency list and avoid minification issues — using the
|
||||
bracket notation which wraps the function to be injected into an array of strings (representing the
|
||||
dependency names) followed by the function to be injected:</p>
|
||||
|
||||
<pre><code>var PhoneListCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */ }];
|
||||
</code></pre>
|
||||
|
||||
<p>Both of these methods work with any function that can be injected by Angular, so it's up to your
|
||||
project's style guide to decide which one you use.</p>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<pre><code>var PhoneListCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */ }];</code></pre>
|
||||
<p>Both of these methods work with any function that can be injected by Angular, so it's up to your
|
||||
project's style guide to decide which one you use.</p>
|
||||
<h2>Test</h3>
|
||||
<p><strong><code>test/unit/controllersSpec.js</code>:</strong></p>
|
||||
|
||||
<p>Because we started using dependency injection and our controller has dependencies, constructing the
|
||||
controller in our tests is a bit more complicated. We could use the <code>new</code> operator and provide the
|
||||
constructor with some kind of fake <code>$http</code> implementation. However, the recommended (and easier) way
|
||||
is to create a controller in the test environment in the same way that angular does it in the
|
||||
production code behind the scenes, as follows:</p>
|
||||
|
||||
<pre class="prettyprint linenums">
|
||||
describe('PhoneCat controllers', function() {
|
||||
|
||||
describe('PhoneListCtrl', function(){
|
||||
var scope, ctrl, $httpBackend;
|
||||
|
||||
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
|
||||
// This allows us to inject a service but then attach it to a variable
|
||||
// with the same name as the service.
|
||||
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.expectGET('phones/phones.json').
|
||||
|
@ -138,43 +112,41 @@ describe('PhoneCat controllers', function() {
|
|||
ctrl = $controller(PhoneListCtrl, {$scope: scope});
|
||||
}));
|
||||
</pre>
|
||||
|
||||
<p>Note: Because we loaded Jasmine and <code>angular-mocks.js</code> in our test environment, we got two helper
|
||||
methods <a href="api/angular.mock.module"><code>module</code></a> and <a href="api/angular.mock.inject"><code>inject</code></a> that we'll
|
||||
methods <a href="api/angular.mock.module"><code>module</code></a> and <a href="api/angular.mock.inject"><code>inject</code></a> that we'll
|
||||
use to access and configure the injector.</p>
|
||||
|
||||
<p>We created the controller in the test environment, as follows:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>We used the <code>inject</code> helper method to inject instances of
|
||||
<a href="api/ng.$rootScope"><code>$rootScope</code></a>,
|
||||
<a href="api/ng.$controller"><code>$controller</code></a> and
|
||||
<a href="api/ng.$httpBackend"><code>$httpBackend</code></a> services into the Jasmine's <code>beforeEach</code>
|
||||
<a href="api/ng.$httpBackend"><code>$httpBackend</code></a> services into the Jasmine's <code>beforeEach</code>
|
||||
function. These instances come from an injector which is recreated from scratch for every single
|
||||
test. This guarantees that each test starts from a well known starting point and each test is
|
||||
isolated from the work done in other tests.</p></li>
|
||||
<li><p>We created a new scope for our controller by calling <code>$rootScope.$new()</code></p></li>
|
||||
isolated from the work done in other tests.</p>
|
||||
</li>
|
||||
<li><p>We created a new scope for our controller by calling <code>$rootScope.$new()</code></p>
|
||||
</li>
|
||||
<li><p>We called the injected <code>$controller</code> function passing the <code>PhoneListCtrl</code> function and the created
|
||||
scope as parameters.</p></li>
|
||||
scope as parameters.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Because our code now uses the <code>$http</code> service to fetch the phone list data in our controller, before
|
||||
we create the <code>PhoneListCtrl</code> child scope, we need to tell the testing harness to expect an
|
||||
incoming request from the controller. To do this we:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Request <code>$httpBackend</code> service to be injected into our <code>beforeEach</code> function. This is a mock
|
||||
version of the service that in a production environment facilitates all XHR and JSONP requests.
|
||||
The mock version of this service allows you to write tests without having to deal with
|
||||
native APIs and the global state associated with them — both of which make testing a nightmare.</p></li>
|
||||
native APIs and the global state associated with them — both of which make testing a nightmare.</p>
|
||||
</li>
|
||||
<li><p>Use the <code>$httpBackend.expectGET</code> method to train the <code>$httpBackend</code> service to expect an incoming
|
||||
HTTP request and tell it what to respond with. Note that the responses are not returned until we call
|
||||
the <code>$httpBackend.flush</code> method.</p></li>
|
||||
the <code>$httpBackend.flush</code> method.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Now, we will make assertions to verify that the <code>phones</code> model doesn't exist on <code>scope</code> before
|
||||
<p>Now, we will make assertions to verify that the <code>phones</code> model doesn't exist on <code>scope</code> before
|
||||
the response is received:</p>
|
||||
|
||||
<pre class="prettyprint linenums">
|
||||
it('should create "phones" model with 2 phones fetched from xhr', function() {
|
||||
expect(scope.phones).toBeUndefined();
|
||||
|
@ -184,44 +156,33 @@ the response is received:</p>
|
|||
{name: 'Motorola DROID'}]);
|
||||
});
|
||||
</pre>
|
||||
|
||||
<ul>
|
||||
<li><p>We flush the request queue in the browser by calling <code>$httpBackend.flush()</code>. This causes the
|
||||
promise returned by the <code>$http</code> service to be resolved with the trained response.</p></li>
|
||||
<li><p>We make the assertions, verifying that the phone model now exists on the scope.</p></li>
|
||||
promise returned by the <code>$http</code> service to be resolved with the trained response.</p>
|
||||
</li>
|
||||
<li><p>We make the assertions, verifying that the phone model now exists on the scope.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Finally, we verify that the default value of <code>orderProp</code> is set correctly:</p>
|
||||
|
||||
<pre class="prettyprint linenums">
|
||||
it('should set the default value of orderProp model', function() {
|
||||
expect(scope.orderProp).toBe('age');
|
||||
});
|
||||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>You should now see the following output in the Testacular tab:</p>
|
||||
|
||||
<pre><code> Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
|
||||
</code></pre>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
<p>You should now see the following output in the Karma tab:</p>
|
||||
<pre><code> Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)</code></pre>
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>At the bottom of <code>index.html</code>, add a <code>{{phones | json}}</code> binding to see the list of phones
|
||||
displayed in json format.</p></li>
|
||||
displayed in json format.</p>
|
||||
</li>
|
||||
<li><p>In the <code>PhoneListCtrl</code> controller, pre-process the http response by limiting the number of phones
|
||||
to the first 5 in the list. Use the following code in the $http callback:</p>
|
||||
|
||||
<pre><code> $scope.phones = data.splice(0, 5);
|
||||
</code></pre></li>
|
||||
<pre><code> $scope.phones = data.splice(0, 5);</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<p>Now that you have learned how easy it is to use angular services (thanks to Angular's dependency
|
||||
<h1>Summary</h2>
|
||||
<p>Now that you have learned how easy it is to use angular services (thanks to Angular's dependency
|
||||
injection), go to <a href="tutorial/step_06">step 6</a>, where you will add some
|
||||
thumbnail images of phones and some links.</p>
|
||||
|
||||
<ul doc-tutorial-nav="5"></ul></div>
|
||||
<ul doc-tutorial-nav="5"></ul></div></div>
|
||||
|
|
49
lib/angular/docs/partials/tutorial/step_06.html
Normal file → Executable file
49
lib/angular/docs/partials/tutorial/step_06.html
Normal file → Executable file
|
@ -1,24 +1,22 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_06.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_06.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="6"></ul>
|
||||
<div><div class="tutorial-page tutorial-6-templating-links-images-page"><ul doc-tutorial-nav="6"></ul>
|
||||
|
||||
|
||||
<p>In this step, you will add thumbnail images for the phones in the phone list, and links that, for
|
||||
now, will go nowhere. In subsequent steps you will use the links to display additional information
|
||||
about the phones in the catalog.</p>
|
||||
|
||||
<div doc-tutorial-reset="6">
|
||||
</div>
|
||||
|
||||
|
||||
<p>You should now see links and images of the phones in the list.</p>
|
||||
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-5...step-6">GitHub</a>:</p>
|
||||
|
||||
<h3>Data</h3>
|
||||
|
||||
<h3>Data</h2>
|
||||
<p>Note that the <code>phones.json</code> file contains unique ids and image urls for each of the phones. The
|
||||
urls point to the <code>app/img/phones/</code> directory.</p>
|
||||
|
||||
<p><strong><code>app/phones/phones.json</code></strong> (sample snippet):
|
||||
<pre class="prettyprint linenums">
|
||||
[
|
||||
|
@ -32,9 +30,7 @@ urls point to the <code>app/img/phones/</code> directory.</p>
|
|||
...
|
||||
]
|
||||
</pre>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h2>Template</h2>
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -47,20 +43,16 @@ urls point to the <code>app/img/phones/</code> directory.</p>
|
|||
</ul>
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>To dynamically generate links that will in the future lead to phone detail pages, we used the
|
||||
now-familiar double-curly brace binding in the <code>href</code> attribute values. In step 2, we added the
|
||||
<code>{{phone.name}}</code> binding as the element content. In this step the <code>{{phone.id}}</code> binding is used in
|
||||
the element attribute.</p>
|
||||
|
||||
<p>We also added phone images next to each record using an image tag with the <a href="api/ng.directive:ngSrc"><code>ngSrc</code></a> directive. That directive prevents the
|
||||
browser from treating the angular <code>{{ expression }}</code> markup literally, and initiating a request to
|
||||
invalid url <code>http://localhost:8000/app/{{phone.imageUrl}}</code>, which it would have done if we had only
|
||||
specified an attribute binding in a regular <code>src</code> attribute (<code><img class="diagram" src="{{phone.imageUrl}}"></code>).
|
||||
specified an attribute binding in a regular <code>src</code> attribute (<code><img class="diagram" src="{{phone.imageUrl}}"></code>).
|
||||
Using the <code>ngSrc</code> directive prevents the browser from making an http request to an invalid location.</p>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<h2>Test</h3>
|
||||
<p><strong><code>test/e2e/scenarios.js</code></strong>:
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -71,29 +63,22 @@ Using the <code>ngSrc</code> directive prevents the browser from making an http
|
|||
});
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>We added a new end-to-end test to verify that the app is generating correct links to the phone
|
||||
views that we will implement in the upcoming steps.</p>
|
||||
|
||||
<p>You can now rerun <code>./scripts/e2e-test.sh</code> or refresh the browser tab with the end-to-end test
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>Replace the <code>ng-src</code> directive with a plain old <code>src</code> attribute. Using tools such as Firebug,
|
||||
or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that the app is indeed
|
||||
or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that the app is indeed
|
||||
making an extraneous request to <code>/app/%7B%7Bphone.imageUrl%7D%7D</code> (or
|
||||
<code>/app/{{phone.imageUrl}}</code>).</p>
|
||||
|
||||
<p>The issue here is that the browser will fire a request for that invalid image address as soon as
|
||||
it hits the <code>img</code> tag, which is before Angular has a chance to evaluate the expression and inject
|
||||
the valid address.</p></li>
|
||||
the valid address.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<h1>Summary</h2>
|
||||
<p>Now that you have added phone images and links, go to <a href="tutorial/step_07">step 7</a> to learn about Angular
|
||||
layout templates and how Angular makes it easy to create applications that have multiple views.</p>
|
||||
|
||||
<ul doc-tutorial-nav="6"></ul></div>
|
||||
<ul doc-tutorial-nav="6"></ul></div></div>
|
||||
|
|
114
lib/angular/docs/partials/tutorial/step_07.html
Normal file → Executable file
114
lib/angular/docs/partials/tutorial/step_07.html
Normal file → Executable file
|
@ -1,63 +1,53 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_07.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_07.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="7"></ul>
|
||||
<div><div class="tutorial-page tutorial-7-routing-multiple-views-page"><ul doc-tutorial-nav="7"></ul>
|
||||
|
||||
|
||||
<p>In this step, you will learn how to create a layout template and how to build an app that has
|
||||
multiple views by adding routing.</p>
|
||||
|
||||
<div doc-tutorial-reset="7">
|
||||
</div>
|
||||
|
||||
|
||||
<p>Note that when you now navigate to <code>app/index.html</code>, you are redirected to <code>app/index.html#/phones</code>
|
||||
and the same phone list appears in the browser. When you click on a phone link the stub of a phone
|
||||
detail page is displayed.</p>
|
||||
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-6...step-7">GitHub</a>.</p>
|
||||
|
||||
<h3>Multiple Views, Routing and Layout Template</h3>
|
||||
|
||||
<h3>Multiple Views, Routing and Layout Template</h2>
|
||||
<p>Our app is slowly growing and becoming more complex. Before step 7, the app provided our users with
|
||||
a single view (the list of all phones), and all of the template code was located in the
|
||||
<code>index.html</code> file. The next step in building the app is to add a view that will show detailed
|
||||
information about each of the devices in our list.</p>
|
||||
|
||||
<p>To add the detailed view, we could expand the <code>index.html</code> file to contain template code for both
|
||||
views, but that would get messy very quickly. Instead, we are going to turn the <code>index.html</code>
|
||||
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.</p>
|
||||
|
||||
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.</p>
|
||||
<p>Application routes in Angular are declared via the
|
||||
<a href="api/ng.$routeProvider"><code>$routeProvider</code></a>, which is the provider of the
|
||||
<a href="api/ng.$route"><code>$route service</code></a>. This service makes it easy to wire together
|
||||
controllers, view templates, and the current
|
||||
URL location in the browser. Using this feature we can implement <a href="http://en.wikipedia.org/wiki/Deep_linking">deep linking</a>, which lets us utilize the browser's
|
||||
URL location in the browser. Using this feature we can implement <a href="http://en.wikipedia.org/wiki/Deep_linking">deep linking</a>, which lets us utilize the browser's
|
||||
history (back and forward navigation) and bookmarks.</p>
|
||||
|
||||
<h4>A Note About DI, Injector and Providers</h4>
|
||||
|
||||
<p>As you <a href="tutorial/step_05">noticed</a>, <a href="guide/di">dependency injection</a> (DI) is the core feature of
|
||||
AngularJS, so it's important for you to understand a thing or two about how it works.</p>
|
||||
|
||||
AngularJS, so it's important for you to understand a thing or two about how it works.</p>
|
||||
<p>When the application bootstraps, Angular creates an injector that will be used for all DI stuff in
|
||||
this app. The injector itself doesn't know anything about what <code>$http</code> or <code>$route</code> services do, in
|
||||
fact it doesn't even know about the existence of these services unless it is configured with proper
|
||||
this app. The injector itself doesn't know anything about what <code>$http</code> or <code>$route</code> services do, in
|
||||
fact it doesn't even know about the existence of these services unless it is configured with proper
|
||||
module definitions. The sole responsibilities of the injector are to load specified module
|
||||
definition(s), register all service providers defined in these modules and when asked inject
|
||||
definition(s), register all service providers defined in these modules, and when asked, inject
|
||||
a specified function with dependencies (services) that it lazily instantiates via their providers.</p>
|
||||
|
||||
<p>Providers are objects that provide (create) instances of services and expose configuration APIs
|
||||
that can be used to control the creation and runtime behavior of a service. In case of the <code>$route</code>
|
||||
service, the <code>$routeProvider</code> exposes APIs that allow you to define routes for your application.</p>
|
||||
|
||||
<p>Angular modules solve the problem of removing global state from the application and provide a way
|
||||
of configuring the injector. As opposed to AMD or require.js modules, Angular modules don't try to
|
||||
of configuring the injector. As opposed to AMD or require.js modules, Angular modules don't try to
|
||||
solve the problem of script load ordering or lazy script fetching. These goals are orthogonal and
|
||||
both module systems can live side by side and fulfil their goals.</p>
|
||||
|
||||
<h3>The App Module</h3>
|
||||
|
||||
<h2>The App Module</h2>
|
||||
<p><strong><code>app/js/app.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
angular.module('phonecat', []).
|
||||
|
@ -68,49 +58,40 @@ angular.module('phonecat', []).
|
|||
otherwise({redirectTo: '/phones'});
|
||||
}]);
|
||||
</pre>
|
||||
|
||||
<p>In order to configure our application with routes, we need to create a module for our application.
|
||||
We call this module <code>phonecat</code> and using the <code>config</code> API we request the <code>$routeProvider</code> to be
|
||||
injected into our config function and use <code>$routeProvider.when</code> API to define our routes.</p>
|
||||
|
||||
<p>Note that during the injector configuration phase, the providers can be injected as well, but they
|
||||
will not be available for injection once the injector is created and starts creating service
|
||||
instances.</p>
|
||||
|
||||
<p>Our application routes were defined as follows:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>The phone list view will be shown when the URL hash fragment is <code>/phones</code>. To construct this
|
||||
view, Angular will use the <code>phone-list.html</code> template and the <code>PhoneListCtrl</code> controller.</p></li>
|
||||
<li><p>The phone details view will be shown when the URL hash fragment matches '/phone/:phoneId', where
|
||||
view, Angular will use the <code>phone-list.html</code> template and the <code>PhoneListCtrl</code> controller.</p>
|
||||
</li>
|
||||
<li><p>The phone details view will be shown when the URL hash fragment matches '/phone/:phoneId', where
|
||||
<code>:phoneId</code> is a variable part of the URL. To construct the phone details view, angular will use the
|
||||
<code>phone-detail.html</code> template and the <code>PhoneDetailCtrl</code> controller.</p></li>
|
||||
<code>phone-detail.html</code> template and the <code>PhoneDetailCtrl</code> controller.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>We reused the <code>PhoneListCtrl</code> controller that we constructed in previous steps and we added a new,
|
||||
empty <code>PhoneDetailCtrl</code> controller to the <code>app/js/controllers.js</code> file for the phone details view.</p>
|
||||
|
||||
<p>The statement <code>$route.otherwise({redirectTo: '/phones'})</code> triggers a redirection to <code>/phones</code> when
|
||||
the browser address doesn't match either of our routes.</p>
|
||||
|
||||
<p>The statement <code>$route.otherwise({redirectTo: '/phones'})</code> triggers a redirection to <code>/phones</code> when
|
||||
the browser address doesn't match either of our routes.</p>
|
||||
<p>Note the use of the <code>:phoneId</code> parameter in the second route declaration. The <code>$route</code> service uses
|
||||
the route declaration — <code>'/phones/:phoneId'</code> — as a template that is matched against the current
|
||||
the route declaration — <code>'/phones/:phoneId'</code> — as a template that is matched against the current
|
||||
URL. All variables defined with the <code>:</code> notation are extracted into the
|
||||
<a href="api/ng.$routeParams"><code>$routeParams</code></a> object.</p>
|
||||
|
||||
<p>In order for our application to bootstrap with our newly created module we'll also need to specify
|
||||
<p>In order for our application to bootstrap with our newly created module we'll also need to specify
|
||||
the module name as the value of the <a href="api/ng.directive:ngApp"><code>ngApp</code></a>
|
||||
directive:</p>
|
||||
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<!doctype html>
|
||||
<html lang="en" ng-app="phonecat">
|
||||
...
|
||||
</pre>
|
||||
|
||||
<h3>Controllers</h3>
|
||||
|
||||
<h2>Controllers</h2>
|
||||
<p><strong><code>app/js/controllers.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -120,12 +101,9 @@ function PhoneDetailCtrl($scope, $routeParams) {
|
|||
|
||||
//PhoneDetailCtrl.$inject = ['$scope', '$routeParams'];
|
||||
</pre>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h2>Template</h2>
|
||||
<p>The <code>$route</code> service is usually used in conjunction with the <a href="api/ng.directive:ngView"><code>ngView</code></a> directive. The role of the <code>ngView</code> directive is to include the view template for the current
|
||||
route into the layout template, which makes it a perfect fit for our <code>index.html</code> template.</p>
|
||||
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<html lang="en" ng-app="phonecat">
|
||||
|
@ -142,11 +120,9 @@ route into the layout template, which makes it a perfect fit for our <code>index
|
|||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
<p>Note that we removed most of the code in the <code>index.html</code> template and replaced it with a single
|
||||
line containing a div with the <code>ng-view</code> attribute. The code that we removed was placed into the
|
||||
<code>phone-list.html</code> template:</p>
|
||||
|
||||
<p><strong><code>app/partials/phone-list.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<div class="container-fluid">
|
||||
|
@ -177,26 +153,20 @@ line containing a div with the <code>ng-view</code> attribute. The code that we
|
|||
</div>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<div style="display:none">
|
||||
TODO!
|
||||
<img class="diagram" src="img/tutorial/tutorial_07_final.png">
|
||||
</div>
|
||||
|
||||
<p>We also added a placeholder template for the phone details view:</p>
|
||||
|
||||
<p><strong><code>app/partials/phone-detail.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
TBD: detail view for {{phoneId}}
|
||||
</pre>
|
||||
|
||||
<p>Note how we are using <code>phoneId</code> model defined in the <code>PhoneDetailCtrl</code> controller.</p>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<h2>Test</h3>
|
||||
<p>To automatically verify that everything is wired properly, we wrote end-to-end tests that navigate
|
||||
to various URLs and verify that the correct view was rendered.</p>
|
||||
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
it('should redirect index.html to index.html#/phones', function() {
|
||||
|
@ -217,29 +187,23 @@ to various URLs and verify that the correct view was rendered.</p>
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>You can now rerun <code>./scripts/e2e-test.sh</code> or refresh the browser tab with the end-to-end test
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li>Try to add an <code>{{orderProp}}</code> binding to <code>index.html</code>, and you'll see that nothing happens even
|
||||
<li>Try to add an <code>{{orderProp}}</code> binding to <code>index.html</code>, and you'll see that nothing happens even
|
||||
when you are in the phone list view. This is because the <code>orderProp</code> model is visible only in the
|
||||
scope managed by <code>PhoneListCtrl</code>, which is associated with the <code><div ng-view></code> element. If you add
|
||||
the same binding into the <code>phone-list.html</code> template, the binding will work as expected.</li>
|
||||
</ul>
|
||||
|
||||
<div style="display: none">
|
||||
* In `PhoneCatCtrl`, create a new model called "`hero`" with `this.hero = 'Zoro'`. In
|
||||
`PhoneListCtrl` let's shadow it with `this.hero = 'Batman'`, and in `PhoneDetailCtrl` we'll use
|
||||
`this.hero = "Captain Proton"`. Then add the `<p>hero = {{hero}}</p>` to all three of our templates
|
||||
(`index.html`, `phone-list.html`, and `phone-detail.html`). Open the app and you'll see scope
|
||||
* In <code>PhoneCatCtrl</code>, create a new model called "<code>hero</code>" with <code>this.hero = 'Zoro'</code>. In
|
||||
<code>PhoneListCtrl</code> let's shadow it with <code>this.hero = 'Batman'</code>, and in <code>PhoneDetailCtrl</code> we'll use
|
||||
<code>this.hero = "Captain Proton"</code>. Then add the <code><p>hero = {{hero}}</p></code> to all three of our templates
|
||||
(<code>index.html</code>, <code>phone-list.html</code>, and <code>phone-detail.html</code>). Open the app and you'll see scope
|
||||
inheritance and model property shadowing do some wonders.
|
||||
</div>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<p>With the routing set up and the phone list view implemented, we're ready to go to <a href="tutorial/step_08">step 8</a> to implement the phone details view.</p>
|
||||
|
||||
<ul doc-tutorial-nav="7"></ul></div>
|
||||
<h1>Summary</h2>
|
||||
<p>With the routing set up and the phone list view implemented, we're ready to go to <a href="tutorial/step_08">step 8</a> to implement the phone details view.</p>
|
||||
<ul doc-tutorial-nav="7"></ul></div></div>
|
||||
|
|
67
lib/angular/docs/partials/tutorial/step_08.html
Normal file → Executable file
67
lib/angular/docs/partials/tutorial/step_08.html
Normal file → Executable file
|
@ -1,27 +1,24 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_08.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_08.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="8"></ul>
|
||||
<div><div class="tutorial-page tutorial-8-more-templating-page"><ul doc-tutorial-nav="8"></ul>
|
||||
|
||||
|
||||
<p>In this step, you will implement the phone details view, which is displayed when a user clicks on a
|
||||
phone in the phone list.</p>
|
||||
|
||||
<div doc-tutorial-reset="8">
|
||||
</div>
|
||||
|
||||
|
||||
<p>Now when you click on a phone on the list, the phone details page with phone-specific information
|
||||
is displayed.</p>
|
||||
|
||||
<p>To implement the phone details view we will use <a href="api/ng.$http"><code>$http</code></a> to fetch
|
||||
our data, and we'll flesh out the <code>phone-detail.html</code> view template.</p>
|
||||
|
||||
our data, and we'll flesh out the <code>phone-detail.html</code> view template.</p>
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-7...step-8">GitHub</a>:</p>
|
||||
|
||||
<h3>Data</h3>
|
||||
|
||||
<h3>Data</h2>
|
||||
<p>In addition to <code>phones.json</code>, the <code>app/phones/</code> directory also contains one json file for each
|
||||
phone:</p>
|
||||
|
||||
<p><strong><code>app/phones/nexus-s.json</code>:</strong> (sample snippet)
|
||||
<pre class="prettyprint linenums">
|
||||
{
|
||||
|
@ -43,15 +40,11 @@ phone:</p>
|
|||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Each of these files describes various properties of the phone using the same data structure. We'll
|
||||
<p>Each of these files describes various properties of the phone using the same data structure. We'll
|
||||
show this data in the phone detail view.</p>
|
||||
|
||||
<h3>Controller</h3>
|
||||
|
||||
<p>We'll expand the <code>PhoneDetailCtrl</code> by using the <code>$http</code> service to fetch the json files. This works
|
||||
<h2>Controller</h2>
|
||||
<p>We'll expand the <code>PhoneDetailCtrl</code> by using the <code>$http</code> service to fetch the json files. This works
|
||||
the same way as the phone list controller.</p>
|
||||
|
||||
<p><strong><code>app/js/controllers.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
function PhoneDetailCtrl($scope, $routeParams, $http) {
|
||||
|
@ -62,16 +55,12 @@ function PhoneDetailCtrl($scope, $routeParams, $http) {
|
|||
|
||||
//PhoneDetailCtrl.$inject = ['$scope', '$routeParams', '$http'];
|
||||
</pre>
|
||||
|
||||
<p>To construct the URL for the HTTP request, we use <code>$routeParams.phoneId</code> extracted from the current
|
||||
route by the <code>$route</code> service.</p>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h2>Template</h2>
|
||||
<p>The TBD placeholder line has been replaced with lists and bindings that comprise the phone details.
|
||||
Note where we use the angular <code>{{expression}}</code> markup and <code>ngRepeat</code> to project phone data from
|
||||
our model into the view.</p>
|
||||
|
||||
<p><strong><code>app/partials/phone-detail.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<img ng-src="{{phone.images[0]}}" class="phone">
|
||||
|
@ -101,17 +90,14 @@ our model into the view.</p>
|
|||
</li>
|
||||
</ul>
|
||||
</pre>
|
||||
|
||||
<div style="display: none">
|
||||
TODO!
|
||||
<img class="diagram" src="img/tutorial/tutorial_08-09_final.png">
|
||||
</div>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<h2>Test</h3>
|
||||
<p>We wrote a new unit test that is similar to the one we wrote for the <code>PhoneListCtrl</code> controller in
|
||||
step 5.</p>
|
||||
|
||||
<p><strong><code>test/unit/controllersSpec.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -137,15 +123,10 @@ step 5.</p>
|
|||
});
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>You should now see the following output in the Testacular tab:</p>
|
||||
|
||||
<pre><code>Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)
|
||||
</code></pre>
|
||||
|
||||
<p>You should now see the following output in the Karma tab:</p>
|
||||
<pre><code>Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)</code></pre>
|
||||
<p>We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
|
||||
heading on the page is "Nexus S".</p>
|
||||
|
||||
heading on the page is "Nexus S".</p>
|
||||
<p><strong><code>test/e2e/scenarios.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -162,20 +143,14 @@ heading on the page is "Nexus S".</p>
|
|||
});
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>You can now rerun <code>./scripts/e2e-test.sh</code> or refresh the browser tab with the end-to-end test
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li>Using the <a href="guide/dev_guide.e2e-testing">Angular's end-to-end test runner API</a>, write a test
|
||||
<li>Using the <a href="guide/dev_guide.e2e-testing">Angular's end-to-end test runner API</a>, write a test
|
||||
that verifies that we display 4 thumbnail images on the Nexus S details page.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<h1>Summary</h2>
|
||||
<p>Now that the phone details view is in place, proceed to <a href="tutorial/step_09">step 9</a> to learn how to
|
||||
write your own custom display filter.</p>
|
||||
|
||||
<ul doc-tutorial-nav="8"></ul></div>
|
||||
<ul doc-tutorial-nav="8"></ul></div></div>
|
||||
|
|
84
lib/angular/docs/partials/tutorial/step_09.html
Normal file → Executable file
84
lib/angular/docs/partials/tutorial/step_09.html
Normal file → Executable file
|
@ -1,26 +1,23 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_09.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_09.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="9"></ul>
|
||||
<div><div class="tutorial-page tutorial-9-filters-page"><ul doc-tutorial-nav="9"></ul>
|
||||
|
||||
|
||||
<p>In this step you will learn how to create your own custom display filter.</p>
|
||||
|
||||
<div doc-tutorial-reset="9">
|
||||
</div>
|
||||
|
||||
|
||||
<p>Navigate to one of the detail pages.</p>
|
||||
|
||||
<p>In the previous step, the details page displayed either "true" or "false" to indicate whether
|
||||
<p>In the previous step, the details page displayed either "true" or "false" to indicate whether
|
||||
certain phone features were present or not. We have used a custom filter to convert those text
|
||||
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see what the filter code looks like.</p>
|
||||
|
||||
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see what the filter code looks like.</p>
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-8...step-9">GitHub</a>:</p>
|
||||
|
||||
<h3>Custom Filter</h3>
|
||||
|
||||
<h3>Custom Filter</h2>
|
||||
<p>In order to create a new filter, you are going to create a <code>phonecatFilters</code> module and register
|
||||
your custom filter with this module:</p>
|
||||
|
||||
<p><strong><code>app/js/filters.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
angular.module('phonecatFilters', []).filter('checkmark', function() {
|
||||
|
@ -29,26 +26,19 @@ angular.module('phonecatFilters', []).filter('checkmark', function() {
|
|||
};
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>The name of our filter is "checkmark". The <code>input</code> evaluates to either <code>true</code> or <code>false</code>, and we
|
||||
return one of two unicode characters we have chosen to represent true or false (<code>\u2713</code> and
|
||||
<code>\u2718</code>).</p>
|
||||
|
||||
<p>The name of our filter is "checkmark". The <code>input</code> evaluates to either <code>true</code> or <code>false</code>, and we
|
||||
return one of the two unicode characters we have chosen to represent true (<code>\u2713</code> -> ✓) or false (<code>\u2718</code> -> ✘).</p>
|
||||
<p>Now that our filter is ready, we need to register the <code>phonecatFilters</code> module as a dependency for
|
||||
our main <code>phonecat</code> module.</p>
|
||||
|
||||
<p><strong><code>app/js/app.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
angular.module('phonecat', ['phonecatFilters']).
|
||||
...
|
||||
</pre>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h2>Template</h2>
|
||||
<p>Since the filter code lives in the <code>app/js/filters.js</code> file, we need to include this file in our
|
||||
layout template.</p>
|
||||
|
||||
<p><strong><code>app/index.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -56,14 +46,9 @@ layout template.</p>
|
|||
<script src="js/filters.js"></script>
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>The syntax for using filters in Angular templates is as follows:</p>
|
||||
|
||||
<pre><code>{{ expression | filter }}
|
||||
</code></pre>
|
||||
|
||||
<p>Let's employ the filter in the phone details template:</p>
|
||||
|
||||
<pre><code>{{ expression | filter }}</code></pre>
|
||||
<p>Let's employ the filter in the phone details template:</p>
|
||||
<p><strong><code>app/partials/phone-detail.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -75,11 +60,8 @@ layout template.</p>
|
|||
</dl>
|
||||
...
|
||||
</pre>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<h2>Test</h3>
|
||||
<p>Filters, like any other component, should be tested and these tests are very easy to write.</p>
|
||||
|
||||
<p><strong><code>test/unit/filtersSpec.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
describe('filter', function() {
|
||||
|
@ -97,35 +79,27 @@ describe('filter', function() {
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>Note that you need to configure our test injector with the <code>phonecatFilters</code> module before any of
|
||||
our filter tests execute.</p>
|
||||
|
||||
<p>You should now see the following output in the Testacular tab:</p>
|
||||
|
||||
<pre><code> Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)
|
||||
</code></pre>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
<p>You should now see the following output in the Karma tab:</p>
|
||||
<pre><code> Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)</code></pre>
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>Let's experiment with some of the <a href="api/ng.$filter"><code>built-in Angular filters</code></a> and add the
|
||||
<li><p>Let's experiment with some of the <a href="api/ng.$filter"><code>built-in Angular filters</code></a> and add the
|
||||
following bindings to <code>index.html</code>:</p>
|
||||
|
||||
<ul><li><code>{{ "lower cap string" | uppercase }}</code></li>
|
||||
<li><code>{{ {foo: "bar", baz: 23} | json }}</code></li>
|
||||
<ul>
|
||||
<li><code>{{ "lower cap string" | uppercase }}</code></li>
|
||||
<li><code>{{ {foo: "bar", baz: 23} | json }}</code></li>
|
||||
<li><code>{{ 1304375948024 | date }}</code></li>
|
||||
<li><code>{{ 1304375948024 | date:"MM/dd/yyyy @ h:mma" }}</code></li></ul></li>
|
||||
<li><code>{{ 1304375948024 | date:"MM/dd/yyyy @ h:mma" }}</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>We can also create a model with an input element, and combine it with a filtered binding. Add
|
||||
the following to index.html:</p>
|
||||
|
||||
<pre><code><input ng-model="userInput"> Uppercased: {{ userInput | uppercase }}
|
||||
</code></pre></li>
|
||||
<pre><code> <input ng-model="userInput"> Uppercased: {{ userInput | uppercase }}</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<h1>Summary</h2>
|
||||
<p>Now that you have learned how to write and test a custom filter, go to <a href="tutorial/step_10">step 10</a> to
|
||||
learn how we can use Angular to enhance the phone details page further.</p>
|
||||
|
||||
<ul doc-tutorial-nav="9"></ul></div>
|
||||
<ul doc-tutorial-nav="9"></ul></div></div>
|
||||
|
|
70
lib/angular/docs/partials/tutorial/step_10.html
Normal file → Executable file
70
lib/angular/docs/partials/tutorial/step_10.html
Normal file → Executable file
|
@ -1,21 +1,20 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_10.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_10.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="10"></ul>
|
||||
<div><div class="tutorial-page tutorial-10-event-handlers-page"><ul doc-tutorial-nav="10"></ul>
|
||||
|
||||
|
||||
<p>In this step, you will add a clickable phone image swapper to the phone details page.</p>
|
||||
|
||||
<div doc-tutorial-reset="10">
|
||||
</div>
|
||||
|
||||
|
||||
<p>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 at how we can do this with Angular.</p>
|
||||
|
||||
clicking on the desired thumbnail image. Let's have a look at how we can do this with Angular.</p>
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-9...step-10">GitHub</a>:</p>
|
||||
|
||||
<h3>Controller</h3>
|
||||
|
||||
<h3>Controller</h2>
|
||||
<p><strong><code>app/js/controllers.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -32,14 +31,10 @@ function PhoneDetailCtrl($scope, $routeParams, $http) {
|
|||
|
||||
//PhoneDetailCtrl.$inject = ['$scope', '$routeParams', '$http'];
|
||||
</pre>
|
||||
|
||||
<p>In the <code>PhoneDetailCtrl</code> controller, we created the <code>mainImageUrl</code> model property and set its
|
||||
default value to the first phone image URL.</p>
|
||||
|
||||
<p>We also created a <code>setImage</code> event handler function that will change the value of <code>mainImageUrl</code>.</p>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h2>Template</h2>
|
||||
<p><strong><code>app/partials/phone-detail.html</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
<img ng-src="{{mainImageUrl}}" class="phone">
|
||||
|
@ -53,25 +48,20 @@ default value to the first phone image URL.</p>
|
|||
</ul>
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>We bound the <code>ngSrc</code> directive of the large image to the <code>mainImageUrl</code> property.</p>
|
||||
|
||||
<p>We also registered an <a href="api/ng.directive:ngClick"><code><code>ngClick</code></code></a>
|
||||
handler with thumbnail images. When a user clicks on one of the thumbnail images, the handler will
|
||||
use the <code>setImage</code> event handler function to change the value of the <code>mainImageUrl</code> property to the
|
||||
URL of the thumbnail image.</p>
|
||||
|
||||
<div style="display: none">
|
||||
TODO!
|
||||
<img class="diagram" src="img/tutorial/tutorial_10-11_final.png">
|
||||
</div>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<h2>Test</h3>
|
||||
<p>To verify this new feature, we added two end-to-end tests. One verifies that the main image is set
|
||||
to the first phone image by default. The second test clicks on several thumbnail images and
|
||||
verifies that the main image changed appropriately.</p>
|
||||
|
||||
<p><strong><code>test/e2e/scenarios.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -94,41 +84,31 @@ verifies that the main image changed appropriately.</p>
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>You can now rerun <code>./scripts/e2e-test.sh</code> or refresh the browser tab with the end-to-end test
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
|
||||
<h2>Experiments</h2>
|
||||
|
||||
runner to see the tests run, or you can see them running on <a href="http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html">Angular's server</a>.</p>
|
||||
<h2>Experiments</h1>
|
||||
<ul>
|
||||
<li><p>Let's add a new controller method to <code>PhoneDetailCtrl</code>:</p>
|
||||
|
||||
<pre><code> $scope.hello = function(name) {
|
||||
alert('Hello ' + (name || 'world') + '!');
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<li><p>Let's add a new controller method to <code>PhoneDetailCtrl</code>:</p>
|
||||
<pre><code> $scope.hello = function(name) {
|
||||
alert('Hello ' + (name || 'world') + '!');
|
||||
}</code></pre>
|
||||
<p>and add:</p>
|
||||
|
||||
<pre><code> <button ng-click="hello('Elmo')">Hello</button>
|
||||
</code></pre>
|
||||
|
||||
<p>to the <code>phone-details.html</code> template.</p></li>
|
||||
<pre><code> <button ng-click="hello('Elmo')">Hello</button></code></pre>
|
||||
<p>to the <code>phone-details.html</code> template.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div style="display: none">
|
||||
TODO!
|
||||
The controller methods are inherited between controllers/scopes, so you can use the same snippet
|
||||
in the `phone-list.html` template as well.
|
||||
in the <code>phone-list.html</code> template as well.
|
||||
|
||||
* Move the `hello` method from `PhoneCatCtrl` to `PhoneListCtrl` and you'll see that the button
|
||||
declared in `index.html` will stop working, while the one declared in the `phone-list.html`
|
||||
* Move the <code>hello</code> method from <code>PhoneCatCtrl</code> to <code>PhoneListCtrl</code> and you'll see that the button
|
||||
declared in <code>index.html</code> will stop working, while the one declared in the <code>phone-list.html</code>
|
||||
template remains operational.
|
||||
</div>
|
||||
|
||||
<h2>Summary</h2>
|
||||
|
||||
<p>With the phone image swapper in place, we're ready for <a href="tutorial/step_11">step 11</a> (the last step!) to
|
||||
<h1>Summary</h2>
|
||||
<p>With the phone image swapper in place, we're ready for <a href="tutorial/step_11">step 11</a> (the last step!) to
|
||||
learn an even better way to fetch data.</p>
|
||||
|
||||
<ul doc-tutorial-nav="10"></ul></div>
|
||||
<ul doc-tutorial-nav="10"></ul></div></div>
|
||||
|
|
78
lib/angular/docs/partials/tutorial/step_11.html
Normal file → Executable file
78
lib/angular/docs/partials/tutorial/step_11.html
Normal file → Executable file
|
@ -1,24 +1,22 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_11.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/step_11.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><ul doc-tutorial-nav="11"></ul>
|
||||
<div><div class="tutorial-page tutorial-11-rest-and-custom-services-page"><ul doc-tutorial-nav="11"></ul>
|
||||
|
||||
|
||||
<p>In this step, you will improve the way our app fetches data.</p>
|
||||
|
||||
<div doc-tutorial-reset="11">
|
||||
</div>
|
||||
|
||||
|
||||
<p>The last improvement we will make to our app is to define a custom service that represents a <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">RESTful</a> client. Using this client we
|
||||
can make XHR requests for data in an easier way, without having to deal with the lower-level <a href="api/ng.$http"><code>$http</code></a> API, HTTP methods and URLs.</p>
|
||||
|
||||
<p>The most important changes are listed below. You can see the full diff on <a href="https://github.com/angular/angular-phonecat/compare/step-10...step-11">GitHub</a>:</p>
|
||||
|
||||
<h3>Template</h3>
|
||||
|
||||
<h3>Template</h2>
|
||||
<p>The custom service is defined in <code>app/js/services.js</code> so we need to include this file in our layout
|
||||
template. Additionally, we also need to load the <code>angular-resource.js</code> file, which contains the
|
||||
<code>ngResource</code> module and in it the <code>$resource</code> service, that we'll soon use:</p>
|
||||
|
||||
<code>ngResource</code> module and in it the <code>$resource</code> service, that we'll soon use:</p>
|
||||
<p><strong><code>app/index.html</code>.</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -26,9 +24,7 @@ template. Additionally, we also need to load the <code>angular-resource.js</code
|
|||
<script src="lib/angular/angular-resource.js"></script>
|
||||
...
|
||||
</pre>
|
||||
|
||||
<h3>Service</h3>
|
||||
|
||||
<h2>Service</h2>
|
||||
<p><strong><code>app/js/services.js</code>.</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
angular.module('phonecatServices', ['ngResource']).
|
||||
|
@ -38,33 +34,26 @@ angular.module('phonecatServices', ['ngResource']).
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>We used the module API to register a custom service using a factory function. We passed in the name
|
||||
of the service - 'Phone' - and the factory function. The factory function is similar to a
|
||||
controller's constructor in that both can declare dependencies via function arguments. The Phone
|
||||
of the service - 'Phone' - and the factory function. The factory function is similar to a
|
||||
controller's constructor in that both can declare dependencies via function arguments. The Phone
|
||||
service declared a dependency on the <code>$resource</code> service.</p>
|
||||
|
||||
<p>The <a href="api/ngResource.$resource"><code>$resource</code></a> service makes it easy to create a
|
||||
<a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">RESTful</a> client with just a few
|
||||
lines of code. This client can then be used in our application, instead of the lower-level <a href="api/ng.$http"><code>$http</code></a> service.</p>
|
||||
|
||||
<p><strong><code>app/js/app.js</code>.</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
angular.module('phonecat', ['phonecatFilters', 'phonecatServices']).
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>We need to add 'phonecatServices' to 'phonecat' application's requires array.</p>
|
||||
|
||||
<h3>Controller</h3>
|
||||
|
||||
<p>We need to add 'phonecatServices' to 'phonecat' application's requires array.</p>
|
||||
<h2>Controller</h2>
|
||||
<p>We simplified our sub-controllers (<code>PhoneListCtrl</code> and <code>PhoneDetailCtrl</code>) by factoring out the
|
||||
lower-level <a href="api/ng.$http"><code>$http</code></a> service, replacing it with a new service called
|
||||
<code>Phone</code>. Angular's <a href="api/ngResource.$resource"><code>$resource</code></a> service is easier to
|
||||
<code>Phone</code>. Angular's <a href="api/ngResource.$resource"><code>$resource</code></a> service is easier to
|
||||
use than <code>$http</code> for interacting with data sources exposed as RESTful resources. It is also easier
|
||||
now to understand what the code in our controllers is doing.</p>
|
||||
|
||||
<p><strong><code>app/js/controllers.js</code>.</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
...
|
||||
|
@ -90,45 +79,32 @@ function PhoneDetailCtrl($scope, $routeParams, Phone) {
|
|||
|
||||
//PhoneDetailCtrl.$inject = ['$scope', '$routeParams', 'Phone'];
|
||||
</pre>
|
||||
|
||||
<p>Notice how in <code>PhoneListCtrl</code> we replaced:</p>
|
||||
|
||||
<pre><code>$http.get('phones/phones.json').success(function(data) {
|
||||
<pre><code>$http.get('phones/phones.json').success(function(data) {
|
||||
$scope.phones = data;
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
});</code></pre>
|
||||
<p>with:</p>
|
||||
|
||||
<pre><code>$scope.phones = Phone.query();
|
||||
</code></pre>
|
||||
|
||||
<pre><code>$scope.phones = Phone.query();</code></pre>
|
||||
<p>This is a simple statement that we want to query for all phones.</p>
|
||||
|
||||
<p>An important thing to notice in the code above is that we don't pass any callback functions when
|
||||
<p>An important thing to notice in the code above is that we don't pass any callback functions when
|
||||
invoking methods of our Phone service. Although it looks as if the result were returned
|
||||
synchronously, that is not the case at all. What is returned synchronously is a "future" — an
|
||||
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.</p>
|
||||
|
||||
<p>Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
|
||||
we require, so in these cases, we can add a callback to process the server response. The
|
||||
<code>PhoneDetailCtrl</code> controller illustrates this by setting the <code>mainImageUrl</code> in a callback.</p>
|
||||
|
||||
<h3>Test</h3>
|
||||
|
||||
<h2>Test</h3>
|
||||
<p>We have modified our unit tests to verify that our new service is issuing HTTP requests and
|
||||
processing them as expected. The tests also check that our controllers are interacting with the
|
||||
service correctly.</p>
|
||||
|
||||
<p>The <a href="api/ngResource.$resource">$resource</a> service augments the response object
|
||||
with methods for updating and deleting the resource. If we were to use the standard <code>toEqual</code>
|
||||
matcher, our tests would fail because the test values would not match the responses exactly. To
|
||||
solve the problem, we use a newly-defined <code>toEqualData</code> <a href="http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html">Jasmine matcher</a>. When the
|
||||
<code>toEqualData</code> matcher compares two objects, it takes only object properties into account and
|
||||
ignores methods.</p>
|
||||
|
||||
<p><strong><code>test/unit/controllersSpec.js</code>:</strong>
|
||||
<pre class="prettyprint linenums">
|
||||
describe('PhoneCat controllers', function() {
|
||||
|
@ -202,14 +178,8 @@ describe('PhoneCat controllers', function() {
|
|||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
<p>You should now see the following output in the Testacular tab:</p>
|
||||
|
||||
<pre><code>Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)
|
||||
</code></pre>
|
||||
|
||||
<p>You should now see the following output in the Karma tab:</p>
|
||||
<pre><code>Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)</code></pre>
|
||||
<h2>Summary</h2>
|
||||
|
||||
<p>There you have it! We have created a web app in a relatively short amount of time. In the <a href="tutorial/the_end">closing notes</a> we'll cover where to go from here.</p>
|
||||
|
||||
<ul doc-tutorial-nav="11"></ul></div>
|
||||
<p>There you have it! We have created a web app in a relatively short amount of time. In the <a href="tutorial/the_end">closing notes</a> we'll cover where to go from here.</p>
|
||||
<ul doc-tutorial-nav="11"></ul></div></div>
|
||||
|
|
15
lib/angular/docs/partials/tutorial/the_end.html
Normal file → Executable file
15
lib/angular/docs/partials/tutorial/the_end.html
Normal file → Executable file
|
@ -1,19 +1,16 @@
|
|||
<h1><code ng:non-bindable=""></code>
|
||||
<span class="hint"></span>
|
||||
<a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/the_end.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
|
||||
<div><span class="hint"></span>
|
||||
</div>
|
||||
</h1>
|
||||
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/tutorial/the_end.ngdoc" class="improve-docs btn btn-primary">Improve this doc</a><p>Our application is now complete. Feel free to experiment with the code further, and jump back to
|
||||
<div><div class="tutorial-page tutorial-the-end-page"><p>Our application is now complete. Feel free to experiment with the code further, and jump back to
|
||||
previous steps using the <code>git checkout</code> command.</p>
|
||||
|
||||
<p>For more details and examples of the Angular concepts we touched on in this tutorial, see the
|
||||
<a href="guide/index">Developer Guide</a>.</p>
|
||||
|
||||
<p>For several more examples of code, see the <a href="cookbook/index">Cookbook</a>.</p>
|
||||
|
||||
<p>When you are ready to start developing a project using Angular, we recommend that you bootstrap
|
||||
your development with the <a href="https://github.com/angular/angular-seed">angular-seed</a> project.</p>
|
||||
|
||||
<p>We hope this tutorial was useful to you and that you learned enough about Angular to make you want
|
||||
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your
|
||||
own, and that you might be interested in <a href="misc/contribute">contributing</a> to Angular.</p>
|
||||
|
||||
<p>If you have questions or feedback or just want to say "hi", please post a message at <a href="https://groups.google.com/forum/#!forum/angular">https://groups.google.com/forum/#!forum/angular</a>.</p></div>
|
||||
<p>If you have questions or feedback or just want to say "hi", please post a message at <a href="https://groups.google.com/forum/#!forum/angular"><a href="https://groups.google.com/forum/#!forum/angular">https://groups.google.com/forum/#!forum/angular</a></a>.</p>
|
||||
</div></div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue