114 lines
4.9 KiB
HTML
Executable file
114 lines
4.9 KiB
HTML
Executable file
<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><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>
|
|
<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</h2>
|
|
<p><strong><code>app/js/controllers.js</code>:</strong>
|
|
<pre class="prettyprint linenums">
|
|
...
|
|
function PhoneDetailCtrl($scope, $routeParams, $http) {
|
|
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
|
$scope.phone = data;
|
|
$scope.mainImageUrl = data.images[0];
|
|
});
|
|
|
|
$scope.setImage = function(imageUrl) {
|
|
$scope.mainImageUrl = imageUrl;
|
|
}
|
|
}
|
|
|
|
//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>
|
|
<h2>Template</h2>
|
|
<p><strong><code>app/partials/phone-detail.html</code>:</strong>
|
|
<pre class="prettyprint linenums">
|
|
<img ng-src="{{mainImageUrl}}" class="phone">
|
|
|
|
...
|
|
|
|
<ul class="phone-thumbs">
|
|
<li ng-repeat="img in phone.images">
|
|
<img ng-src="{{img}}" ng-click="setImage(img)">
|
|
</li>
|
|
</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>
|
|
|
|
<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">
|
|
...
|
|
describe('Phone detail view', function() {
|
|
|
|
...
|
|
|
|
it('should display the first phone image as the main phone image', function() {
|
|
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
|
|
});
|
|
|
|
|
|
it('should swap main image if a thumbnail image is clicked on', function() {
|
|
element('.phone-thumbs li:nth-child(3) img').click();
|
|
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.2.jpg');
|
|
|
|
element('.phone-thumbs li:nth-child(1) img').click();
|
|
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
|
|
});
|
|
});
|
|
});
|
|
</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</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>
|
|
<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>
|
|
</ul>
|
|
<div style="display: none">
|
|
TODO!
|
|
The controller methods are inherited between controllers/scopes, so you can use the same snippet
|
|
in the <code>phone-list.html</code> template as well.
|
|
|
|
* 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>
|
|
|
|
|
|
<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></div>
|