mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-22 13:21:51 +00:00
docs(tutorial): improve wording and consistency
This commit is contained in:
parent
575f63ac50
commit
0f7237d764
8 changed files with 96 additions and 54 deletions
|
|
@ -33,7 +33,7 @@ The view component is constructed by Angular from this template:
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<html ng-app>
|
<html ng-app="phonecatApp">
|
||||||
<head>
|
<head>
|
||||||
...
|
...
|
||||||
<script src="lib/angular/angular.js"></script>
|
<script src="lib/angular/angular.js"></script>
|
||||||
|
|
@ -47,6 +47,7 @@ __`app/index.html`:__
|
||||||
<p>{{phone.snippet}}</p>
|
<p>{{phone.snippet}}</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
@ -60,24 +61,25 @@ We replaced the hard-coded phone list with the
|
||||||
repeater tells Angular to create a `<li>` element for each phone in the list using the first `<li>`
|
repeater tells Angular to create a `<li>` element for each phone in the list using the first `<li>`
|
||||||
tag as the template.
|
tag as the template.
|
||||||
|
|
||||||
* As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote
|
We have added a new directive, called `ng-controller`, which attaches a `PhoneListCtrl`
|
||||||
|
__controller__ to the DOM at this point.
|
||||||
|
|
||||||
|
* As we've learned in {@link step_00 step 0}, the curly braces around `phone.name` and `phone.snippet` denote
|
||||||
bindings. As opposed to evaluating constants, these expressions are referring to our application
|
bindings. As opposed to evaluating constants, these expressions are referring to our application
|
||||||
model, which was set up in our `PhoneListCtrl` controller.
|
model, which was set up in our `PhoneListCtrl` controller.
|
||||||
|
|
||||||
<img class="diagram" src="img/tutorial/tutorial_02.png">
|
<img class="diagram" src="img/tutorial/tutorial_02.png">
|
||||||
|
|
||||||
|
|
||||||
## Model and Controller
|
## Model and Controller
|
||||||
|
|
||||||
The data __model__ (a simple array of phones in object literal notation) is instantiated within
|
The data __model__ (a simple array of phones in object literal notation) is now instantiated within
|
||||||
the `PhoneListCtrl` __controller__:
|
the `PhoneListCtrl` __controller__. The __controller__ is simply a constructor function that takes a
|
||||||
|
`$scope` parameter:
|
||||||
|
|
||||||
__`app/js/controllers.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
|
|
||||||
var myApp = angular.module('myApp',[]);
|
function PhoneListCtrl($scope) {
|
||||||
|
|
||||||
myApp.controller('PhoneListCtrl', ['$scope', function($scope) {
|
|
||||||
$scope.phones = [
|
$scope.phones = [
|
||||||
{"name": "Nexus S",
|
{"name": "Nexus S",
|
||||||
"snippet": "Fast just got faster with Nexus S."},
|
"snippet": "Fast just got faster with Nexus S."},
|
||||||
|
|
@ -86,41 +88,47 @@ myApp.controller('PhoneListCtrl', ['$scope', function($scope) {
|
||||||
{"name": "MOTOROLA XOOM™",
|
{"name": "MOTOROLA XOOM™",
|
||||||
"snippet": "The Next, Next Generation tablet."}
|
"snippet": "The Next, Next Generation tablet."}
|
||||||
];
|
];
|
||||||
}]);
|
}
|
||||||
|
|
||||||
|
var phonecatApp = angular.module('phonecatApp',[]);
|
||||||
|
phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
Here we have declared a controller called __PhoneListCtrl__ and registered it in an AngularJS
|
||||||
|
module, `phonecatApp`. Notice that our `ng-app` directive (on the `<html>` tag) now specifies the `phonecatApp`
|
||||||
|
module name as the module to load when bootstrapping the Angular application.
|
||||||
|
|
||||||
Although the controller is not yet doing very much controlling, it is playing a crucial role. By
|
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
|
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
|
the model and the view. We connected the dots between the presentation, data, and logic components
|
||||||
as follows:
|
as follows:
|
||||||
|
|
||||||
* `PhoneListCtrl` — the name of our controller function (located in the JavaScript file
|
* The {@link api/ng.directive:ngController ngController} directive, located on the `<body>` tag,
|
||||||
`controllers.js`), matches the value of the
|
references the the name of our controller, `PhoneListCtrl` (located in the JavaScript file
|
||||||
{@link api/ng.directive:ngController ngController} directive located
|
`controllers.js`).
|
||||||
on the `<body>` tag.
|
|
||||||
|
|
||||||
* The phone data is then attached to the *scope* (`$scope`) that was injected into our controller
|
* The `PhoneListCtrl` controller attaches the phone data to the `$scope` that was injected into our
|
||||||
function. The controller scope is a prototypical descendant of the root scope that was created
|
controller function. This *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
|
when the application was defined. This controller scope is available to all bindings located within
|
||||||
the `<body ng-controller="PhoneListCtrl">` tag.
|
the `<body ng-controller="PhoneListCtrl">` tag.
|
||||||
|
|
||||||
The concept of a scope in Angular is crucial; a scope can be seen as the glue which allows the
|
### Scope
|
||||||
|
|
||||||
|
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
|
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
|
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
|
sync. Any changes made to the model are reflected in the view; any changes that occur in the view
|
||||||
are reflected in the model.
|
are reflected in the model.
|
||||||
|
|
||||||
To learn more about Angular scopes, see the {@link api/ng.$rootScope.Scope angular scope documentation}.
|
To learn more about Angular scopes, see the {@link api/ng.$rootScope.Scope angular scope documentation}.
|
||||||
|
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
The "Angular way" makes it easy to test code as it is being developed. Take a look at the following
|
The "Angular way" of separating controller from the view, makes it easy to test code as it is being
|
||||||
unit test for your newly created controller:
|
developed. If our controller is available on the global namespace then we can simply instantiate it
|
||||||
|
with a mock `scope` object. Take a look at the following unit test for our controller:
|
||||||
|
|
||||||
__`test/unit/controllersSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -138,11 +146,33 @@ describe('PhoneCat controllers', function() {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
The test instantiates our PhoneListCtrl and verifies that its phones array property contains three
|
The test instantiates `PhoneListCtrl` and verifies that the phones array property on the scope
|
||||||
records. This example demonstrates how easy it is to create a unit test for code in Angular. Since
|
contains three records. This example demonstrates how easy it is to create a unit test for code in
|
||||||
testing is such a critical part of software development, we make it easy to create tests in Angular
|
Angular. Since testing is such a critical part of software development, we make it easy to create
|
||||||
so that developers are encouraged to write them.
|
tests in Angular so that developers are encouraged to write them.
|
||||||
|
|
||||||
|
### Testing non-Global Controllers
|
||||||
|
In practice, you will not want to have your controller functions in the global namespace. In this
|
||||||
|
case Angular provides a service, `$controller`, which will retrieve your controller by name. Here
|
||||||
|
is the same test using `$controller`:
|
||||||
|
|
||||||
|
__`test/unit/controllersSpec.js`:__
|
||||||
|
<pre>
|
||||||
|
describe('PhoneCat controllers', function() {
|
||||||
|
|
||||||
|
describe('PhoneListCtrl', function(){
|
||||||
|
|
||||||
|
it('should create "phones" model with 3 phones', inject(function($controller) {
|
||||||
|
var scope = {},
|
||||||
|
ctrl = $controller('PhoneListCtrl', { $scope: scope });
|
||||||
|
|
||||||
|
expect(scope.phones.length).toBe(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
### Writing and Running Tests
|
||||||
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
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
|
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 {@link
|
this tutorial in Jasmine. You can learn about Jasmine on the {@link
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,7 @@ necessary!
|
||||||
|
|
||||||
__`app/js/controllers.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
var myApp = angular.module('myApp',[]);
|
function PhoneListCtrl($scope) {
|
||||||
|
|
||||||
myApp.controller('PhoneListCtrl', ['$scope', function($scope) {
|
|
||||||
$scope.phones = [
|
$scope.phones = [
|
||||||
{"name": "Nexus S",
|
{"name": "Nexus S",
|
||||||
"snippet": "Fast just got faster with Nexus S.",
|
"snippet": "Fast just got faster with Nexus S.",
|
||||||
|
|
@ -81,7 +79,11 @@ myApp.controller('PhoneListCtrl', ['$scope', function($scope) {
|
||||||
];
|
];
|
||||||
|
|
||||||
$scope.orderProp = 'age';
|
$scope.orderProp = 'age';
|
||||||
}]);
|
}
|
||||||
|
|
||||||
|
var phonecatApp = angular.module('phonecatApp',[]);
|
||||||
|
phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
* We modified the `phones` model - the array of phones - and added an `age` property to each phone
|
* We modified the `phones` model - the array of phones - and added an `age` property to each phone
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@ function PhoneListCtrl($scope, $http) {
|
||||||
$scope.orderProp = 'age';
|
$scope.orderProp = 'age';
|
||||||
}
|
}
|
||||||
|
|
||||||
//PhoneListCtrl.$inject = ['$scope', '$http'];
|
var phonecatApp = angular.module('phonecatApp',[]);
|
||||||
|
phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
`$http` makes an HTTP GET request to our web server, asking for `phone/phones.json` (the url is
|
`$http` makes an HTTP GET request to our web server, asking for `phone/phones.json` (the url is
|
||||||
|
|
@ -106,21 +107,30 @@ constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minific
|
||||||
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
||||||
minified as well, and the dependency injector would not be able to identify services correctly.
|
minified as well, and the dependency injector would not be able to identify services correctly.
|
||||||
|
|
||||||
To overcome issues caused by minification, just assign an array with service identifier strings
|
There are two ways to overcome issues caused by minification.
|
||||||
into the `$inject` property of the controller function, just like the last line in the snippet
|
|
||||||
(commented out) suggests:
|
|
||||||
|
|
||||||
|
* You can create a `$inject` property on the controller function which holds an array of strings.
|
||||||
|
Each string in the array is the name of the service to inject for the corresponding parameter.
|
||||||
|
In the case of our example we would write:
|
||||||
|
|
||||||
|
function PhoneListCtrl($scope, $http) {...}
|
||||||
PhoneListCtrl.$inject = ['$scope', '$http'];
|
PhoneListCtrl.$inject = ['$scope', '$http'];
|
||||||
|
phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);
|
||||||
|
|
||||||
There is also one more way to specify this dependency list and avoid minification issues — using the
|
* Use the inline bracket notation which wraps the function to be injected into an array of strings
|
||||||
bracket notation which wraps the function to be injected into an array of strings (representing the
|
(representing the dependency names) followed by the function to be injected:
|
||||||
dependency names) followed by the function to be injected:
|
|
||||||
|
|
||||||
var PhoneListCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */ }];
|
function PhoneListCtrl($scope, $http) {...}
|
||||||
|
phonecatApp.controller('PhoneListCtrl', ['$scope', '$http', PhoneListCtrl]);
|
||||||
|
|
||||||
Both of these methods work with any function that can be injected by Angular, so it's up to your
|
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.
|
project's style guide to decide which one you use.
|
||||||
|
|
||||||
|
When using the second method, it is common to provide the constructor function inline as an
|
||||||
|
anonymous function when registering the controller:
|
||||||
|
|
||||||
|
phonecatApp.controller('PhoneListCtrl', ['$scope', '$http', function($scope, $http) {...}]);
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
@ -147,7 +157,7 @@ describe('PhoneCat controllers', function() {
|
||||||
respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
|
respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
|
||||||
|
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
ctrl = $controller(PhoneListCtrl, {$scope: scope});
|
ctrl = $controller('PhoneListCtrl', {$scope: scope});
|
||||||
}));
|
}));
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
@ -167,8 +177,8 @@ isolated from the work done in other tests.
|
||||||
|
|
||||||
* We created a new scope for our controller by calling `$rootScope.$new()`
|
* We created a new scope for our controller by calling `$rootScope.$new()`
|
||||||
|
|
||||||
* We called the injected `$controller` function passing the `PhoneListCtrl` function and the created
|
* We called the injected `$controller` function passing the name of the`PhoneListCtrl` controller
|
||||||
scope as parameters.
|
and the created scope as parameters.
|
||||||
|
|
||||||
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
||||||
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ both module systems can live side by side and fulfil their goals.
|
||||||
|
|
||||||
__`app/js/app.js`:__
|
__`app/js/app.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
var myApp = angular.module('phonecat', []).
|
var phonecatApp = angular.module('phonecatApp', []).
|
||||||
config(['$routeProvider', function($routeProvider) {
|
config(['$routeProvider', function($routeProvider) {
|
||||||
$routeProvider.
|
$routeProvider.
|
||||||
when('/phones', {templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl}).
|
when('/phones', {templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl}).
|
||||||
|
|
@ -124,7 +124,7 @@ __`app/index.html`:__
|
||||||
__`app/js/controllers.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
myApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
|
phonecatApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
|
||||||
$scope.phoneId = $routeParams.phoneId;
|
$scope.phoneId = $routeParams.phoneId;
|
||||||
}]);
|
}]);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@ the same way as the phone list controller.
|
||||||
|
|
||||||
__`app/js/controllers.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
var myApp = angular.module('myApp',[]);
|
var phonecatApp = angular.module('phonecatApp',[]);
|
||||||
myApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http) {
|
phonecatApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http) {
|
||||||
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
||||||
$scope.phone = data;
|
$scope.phone = data;
|
||||||
});
|
});
|
||||||
|
|
@ -132,7 +132,7 @@ __`test/unit/controllersSpec.js`:__
|
||||||
|
|
||||||
$routeParams.phoneId = 'xyz';
|
$routeParams.phoneId = 'xyz';
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
ctrl = $controller(PhoneDetailCtrl, {$scope: scope});
|
ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ our main `phonecat` module.
|
||||||
__`app/js/app.js`:__
|
__`app/js/app.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
angular.module('phonecat', ['phonecatFilters']).
|
angular.module('phonecatApp', ['phonecatFilters']).
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ GitHub}:
|
||||||
__`app/js/controllers.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
var myApp = angular.module('myApp',[]);
|
var phonecatApp = angular.module('phonecatApp',[]);
|
||||||
myApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http) {
|
phonecatApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http) {
|
||||||
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
||||||
$scope.phone = data;
|
$scope.phone = data;
|
||||||
$scope.mainImageUrl = data.images[0];
|
$scope.mainImageUrl = data.images[0];
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ __`app/index.html`.__
|
||||||
|
|
||||||
__`app/js/services.js`.__
|
__`app/js/services.js`.__
|
||||||
<pre>
|
<pre>
|
||||||
var myApp = angular.module('phonecatServices', ['ngResource']).
|
var phonecatApp = angular.module('phonecatServices', ['ngResource']).
|
||||||
factory('Phone', function($resource){
|
factory('Phone', function($resource){
|
||||||
return $resource('phones/:phoneId.json', {}, {
|
return $resource('phones/:phoneId.json', {}, {
|
||||||
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
|
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
|
||||||
|
|
@ -60,11 +60,11 @@ api/ng.$http $http} service.
|
||||||
__`app/js/app.js`.__
|
__`app/js/app.js`.__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
angular.module('phonecat', ['phonecatFilters', 'phonecatServices']).
|
angular.module('phonecatApp', ['phonecatFilters', 'phonecatServices']).
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
We need to add 'phonecatServices' to 'phonecat' application's requires array.
|
We need to add the 'phonecatServices' module dependency to 'phonecatApp' module's requires array.
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
@ -79,12 +79,12 @@ __`app/js/controllers.js`.__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
||||||
myApp.controller('PhoneListCtrl', ['$scope', 'Phone', function($scope, Phone) {
|
phonecatApp.controller('PhoneListCtrl', ['$scope', 'Phone', function($scope, Phone) {
|
||||||
$scope.phones = Phone.query();
|
$scope.phones = Phone.query();
|
||||||
$scope.orderProp = 'age';
|
$scope.orderProp = 'age';
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
myApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', 'Phone', function($scope, $routeParams, Phone) {
|
phonecatApp.controller('PhoneDetailCtrl', ['$scope', '$routeParams', 'Phone', function($scope, $routeParams, Phone) {
|
||||||
$scope.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) {
|
$scope.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) {
|
||||||
$scope.mainImageUrl = phone.images[0];
|
$scope.mainImageUrl = phone.images[0];
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue