Since this is an introductory tutorial, we are not going to dive deep into all features provided
by AngularJS **components**. You can read more about components and their usage patterns in the
[Components](guide/component) section of the Developer Guide.
In fact, one could think of components as an opinionated and stripped-down version of their more
complex and verbose (but powerful) siblings, **directives**, which are AngularJS's way of teaching
HTML new tricks. You can read all about them in the [Directives](guide/directive) section of the
Developer Guide.
(**Note:** Directives are an advanced topic, so you might want to postpone studying them, until
you have mastered the basics.)
To create a component, we use the {@link angular.Module#component .component()} method of an
{@link module AngularJS module}. We must provide the name of the component and the Component
Definition Object (CDO for short).
Remember that (since components are also directives) the name of the component is in `camelCase`
(e.g. `myAwesomeComponent`), but we will use `kebab-case` (e.g. `my-awesome-component`) when
referring to it in our HTML. (See [here][case-styles] for a description of different case styles.)
In its simplest form, the CDO will just contain a template and a controller. (We can actually omit
the controller and AngularJS will create a dummy controller for us. This is useful for simple
"presentational" components, that don't attach any behavior to the template.)
Let's see an example:
```js
angular.
module('myApp').
component('greetUser', {
template: 'Hello, {{$ctrl.user}}!',
controller: function GreetUserController() {
this.user = 'world';
}
});
```
```html
` element.
template:
'' +
'- ' +
'{{phone.name}}' +
'
{{phone.snippet}}
' +
' ' +
'
',
controller: function PhoneListController() {
this.phones = [
{
name: 'Nexus S',
snippet: 'Fast just got faster with Nexus S.'
}, {
name: 'Motorola XOOM™ with Wi-Fi',
snippet: 'The Next, Next Generation tablet.'
}, {
name: 'MOTOROLA XOOM™',
snippet: 'The Next, Next Generation tablet.'
}
];
}
});
```
Voilà! The resulting output should look the same, but let's see what we have gained:
* Our phone list is reusable. Just drop `` anywhere in the page to get a
list of phones.
* Our main view (`index.html`) is cleaner and more declarative. Just by looking at it, we know there
is a list of phones. We are not bothered with implementation details.
* Our component is isolated and safe from "external influences". Likewise, we don't have to worry,
that we might accidentally break something in some other part of the application. What happens
inside our component, stays inside our component.
* It's easier to test our component in isolation.
**A note on file naming:**
It is a good practice to distinguish different types of entities by suffix. In this tutorial, we
are using the `.component` suffix for components, so the definition of a `someComponent`
component would be in a file named `some-component.component.js`.
## Testing
Although we have combined our controller with a template into a component, we still can (and should)
unit test the controller separately, since this is where our application logic and data reside.
In order to retrieve and instantiate a component's controller, AngularJS provides the
{@link ngMock.$componentController $componentController} service.
The `$controller` service that we used in the previous step can only instantiate controllers that
were registered by name, using the `.controller()` method. We could have registered our component
controller this way, too, if we wanted to. Instead, we chose to define it inline — inside
the CDO — to keep things localized, but either way works equally well.
**`app/phone-list.component.spec.js`:**
```js
describe('phoneList', function() {
// Load the module that contains the `phoneList` component before each test
beforeEach(module('phonecatApp'));
// Test the controller
describe('PhoneListController', function() {
it('should create a `phones` model with 3 phones', inject(function($componentController) {
var ctrl = $componentController('phoneList');
expect(ctrl.phones.length).toBe(3);
}));
});
});
```
The test retrieves the controller associated with the `phoneList` component, instantiates it and
verifies that the phones array property on it contains three records. Note that the data is now on
the controller instance itself, not on a `scope`.
### Running Tests
Same as before, execute `npm test` to run the tests and then watch the files for changes.
## Experiments
* Try the experiments from the previous step, this time on the `phoneList` component.
* Add a couple more phone lists on the page, by just adding more ``
elements in `index.html`. Now add another binding to the `phoneList` component's template:
```js
template:
'Total number of phones: {{$ctrl.phones.length}}
' +
'' +
...
```
Reload the page and watch the new "feature" propagate to all phone lists. In real-world
applications, where the phone lists could appear on several different pages, being able to change
or add something in one place (e.g. a component's template) and have that change propagate
throughout the application, is a big win.
## Summary
You have learned how to organize your application and presentation logic into isolated, reusable
components. Let's go to {@link step_04 step 4} to learn how to organize our code in directories and
files, so it remains easy to locate as our application grows.
[case-styles]: https://en.wikipedia.org/wiki/Letter_case#Special_case_styles
[jasmine-docs]: https://jasmine.github.io/api/3.3/global
[jasmine-home]: https://jasmine.github.io/
[karma]: https://karma-runner.github.io/
[mvc-pattern]: https://en.wikipedia.org/wiki/Model–View–Controller