docs(guide/directive): split long lines

This commit is contained in:
Pete Bacon Darwin 2013-11-14 13:22:39 +00:00
parent f6fa7c9c95
commit 089bf5f0e3

View file

@ -94,14 +94,16 @@ Here are some equivalent examples of elements that match `ngBind`:
<div class="alert alert-success"> <div class="alert alert-success">
**Best Practice:** Prefer using the dash-delimited format (e.g. `ng-bind` for `ngBind`). **Best Practice:** Prefer using the dash-delimited format (e.g. `ng-bind` for `ngBind`).
If you want to use an HTML validating tool, you can instead use the `data`-prefixed version (e.g. `data-ng-bind` for `ngBind`). If you want to use an HTML validating tool, you can instead use the `data`-prefixed version (e.g.
`data-ng-bind` for `ngBind`).
The other forms shown above are accepted for legacy reasons but we advise you to avoid them. The other forms shown above are accepted for legacy reasons but we advise you to avoid them.
</div> </div>
`$compile` can match directives based on element names, attributes, class names, as well as comments. `$compile` can match directives based on element names, attributes, class names, as well as comments.
All of the Angular-provided directives match attribute name, tag name, comments, or class name. All of the Angular-provided directives match attribute name, tag name, comments, or class name.
The following demonstrates the various ways a directive (`myDir` in this case) can be referenced from within a template: The following demonstrates the various ways a directive (`myDir` in this case) can be referenced
from within a template:
```html ```html
<my-dir></my-dir> <my-dir></my-dir>
@ -127,10 +129,11 @@ directives when possible.
### Text and attribute bindings ### Text and attribute bindings
During the compilation process the {@link api/ng.$compile compiler} matches text and attributes using the During the compilation process the {@link api/ng.$compile compiler} matches text and attributes
{@link api/ng.$interpolate $interpolate} service to see if they contain embedded expressions. These expressions using the {@link api/ng.$interpolate $interpolate} service to see if they contain embedded
are registered as {@link api/ng.$rootScope.Scope#methods_$watch watches} and will update as part of normal {@link expressions. These expressions are registered as {@link api/ng.$rootScope.Scope#methods_$watch watches}
api/ng.$rootScope.Scope#methods_$digest digest} cycle. An example of interpolation is shown below: and will update as part of normal {@link api/ng.$rootScope.Scope#methods_$digest digest} cycle. An
example of interpolation is shown below:
```html ```html
<a ng-href="img/{{username}}.jpg">Hello {{username}}!</a> <a ng-href="img/{{username}}.jpg">Hello {{username}}!</a>
@ -150,8 +153,8 @@ For example, considering this template:
``` ```
We would expect Angular to be able to bind to this, but when we check the console we see We would expect Angular to be able to bind to this, but when we check the console we see
something like `Error: Invalid value for attribute cx="{{cx}}"`. Because of the SVG DOM API's restrictions, something like `Error: Invalid value for attribute cx="{{cx}}"`. Because of the SVG DOM API's
you cannot simply write `cx="{{cx}}"`. restrictions, you cannot simply write `cx="{{cx}}"`.
With `ng-attr-cx` you can work around this problem. With `ng-attr-cx` you can work around this problem.
@ -171,18 +174,19 @@ For example, we could fix the example above by instead writing:
## Creating Directives ## Creating Directives
First let's talk about the API for registering directives. Much like controllers, directives are registered on First let's talk about the API for registering directives. Much like controllers, directives are
modules. To register a directive, you use the `module.directive` API. `module.directive` takes the registered on modules. To register a directive, you use the `module.directive` API.
{@link guide/directive#creating-custom-directives_matching-directives normalized} directive name followed `module.directive` takes the
by a **factory function.** This factory function should return {@link guide/directive#creating-custom-directives_matching-directives normalized} directive name
an object with the different options to tell `$compile` how the directive should behave when matched. followed by a **factory function.** This factory function should return an object with the different
options to tell `$compile` how the directive should behave when matched.
The factory function is invoked only once when the The factory function is invoked only once when the
{@link api/ng.$compile compiler} matches the directive for the first time. You can {@link api/ng.$compile compiler} matches the directive for the first time. You can perform any
perform any initialization work here. The function is invoked using {@link initialization work here. The function is invoked using
api/AUTO.$injector#methods_invoke $injector.invoke} which {@link api/AUTO.$injector#methods_invoke $injector.invoke} which makes it injectable just like a
makes it injectable just like a controller. controller.
<div class="alert alert-success"> <div class="alert alert-success">
**Best Practice:** Prefer using the definition object over returning a function. **Best Practice:** Prefer using the definition object over returning a function.
@ -205,9 +209,9 @@ For the following examples, we'll use the prefix `my` (e.g. `myCustomer`).
### Template-expanding directive ### Template-expanding directive
Let's say you have a chunk of your template that represents a customer's information. This template is repeated Let's say you have a chunk of your template that represents a customer's information. This template
many times in your code. When you change it in one place, you have to change it in several others. This is a is repeated many times in your code. When you change it in one place, you have to change it in
good opportunity to use a directive to simplify your template. several others. This is a good opportunity to use a directive to simplify your template.
Let's create a directive that simply replaces its contents with a static template: Let's create a directive that simply replaces its contents with a static template:
@ -233,21 +237,22 @@ Let's create a directive that simply replaces its contents with a static templat
</file> </file>
</example> </example>
Notice that we have bindings in this directive. After `$compile` compiles and links `<div my-customer></div>`, Notice that we have bindings in this directive. After `$compile` compiles and links
it will try to match directives on the element's children. This means you can compose directives of other directives. `<div my-customer></div>`, it will try to match directives on the element's children. This means you
We'll see how to do that in {@link can compose directives of other directives. We'll see how to do that in
guide/directive#creating-custom-directives_demo_creating-directives-that-communicate an example} below. {@link guide/directive#creating-custom-directives_demo_creating-directives-that-communicate an example}
below.
In the example above we in-lined the value of the `template` option, but this will become annoying as the size In the example above we in-lined the value of the `template` option, but this will become annoying
of your template grows. as the size of your template grows.
<div class="alert alert-success"> <div class="alert alert-success">
**Best Practice:** Unless your template is very small, it's typically better to break it apart into its own **Best Practice:** Unless your template is very small, it's typically better to break it apart into
HTML file and load it with the `templateUrl` option. its own HTML file and load it with the `templateUrl` option.
</div> </div>
If you are familiar with `ngInclude`, `templateUrl` works just like it. Here's the same example using `templateUrl` If you are familiar with `ngInclude`, `templateUrl` works just like it. Here's the same example
instead: using `templateUrl` instead:
<example module="docsTemplateUrlDirective"> <example module="docsTemplateUrlDirective">
<file name="script.js"> <file name="script.js">
@ -278,8 +283,8 @@ Great! But what if we wanted to have our directive match the tag name `<my-custo
If we simply put a `<my-customer>` element into the HMTL, it doesn't work. If we simply put a `<my-customer>` element into the HMTL, it doesn't work.
<div class="alert alert-waring"> <div class="alert alert-waring">
**Note:** When you create a directive, it is restricted to attribute only by default. In order to create **Note:** When you create a directive, it is restricted to attribute only by default. In order to
directives that are triggered by element name, you need to use the `restrict` option. create directives that are triggered by element name, you need to use the `restrict` option.
</div> </div>
The `restrict` option is typically set to: The `restrict` option is typically set to:
@ -318,28 +323,33 @@ Let's change our directive to use `restrict: 'E'`:
</file> </file>
</example> </example>
For more on the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object For more on the
`restrict`, see the API docs}. {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object `restrict`}
property, see the
{@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object API docs}.
<div class="alert alert-info"> <div class="alert alert-info">
**When should I use an attribute versus an element?** **When should I use an attribute versus an element?**
Use an element when you are creating a component that is in control of the template. The common case for this Use an element when you are creating a component that is in control of the template. The common case
is when you are creating a Domain-Specific Language for parts of your template. for this is when you are creating a Domain-Specific Language for parts of your template.
Use an attribute when you are decorating an existing element with new functionality. Use an attribute when you are decorating an existing element with new functionality.
</div> </div>
Using an element for the `myCustomer` directive is clearly the right choice because you're not decorating an element Using an element for the `myCustomer` directive is clearly the right choice because you're not
with some "customer" behavior; you're defining the core behavior of the element as a customer component. decorating an element with some "customer" behavior; you're defining the core behavior of the
element as a customer component.
### Isolating the Scope of a Directive ### Isolating the Scope of a Directive
Our `myCustomer` directive above is great, but it has a fatal flaw. We can only use it once within a given scope. Our `myCustomer` directive above is great, but it has a fatal flaw. We can only use it once within a
given scope.
In its current implementation, we'd need to create a different controller each time In order to re-use such a directive: In its current implementation, we'd need to create a different controller each time In order to
re-use such a directive:
<example module="docsScopeProblemExample"> <example module="docsScopeProblemExample">
<file name="script.js"> <file name="script.js">
@ -380,8 +390,8 @@ In its current implementation, we'd need to create a different controller each t
This is clearly not a great solution. This is clearly not a great solution.
What we want to be able to do is separate the scope inside a directive from the scope What we want to be able to do is separate the scope inside a directive from the scope
outside, and then map the outer scope to a directive's inner scope. We can do this by creating what we call an outside, and then map the outer scope to a directive's inner scope. We can do this by creating what
**isolate scope**. To do this, we can use a directive's `scope` option: we call an **isolate scope**. To do this, we can use a directive's `scope` option:
<example module="docsIsolateScopeDirective"> <example module="docsIsolateScopeDirective">
<file name="script.js"> <file name="script.js">
@ -412,8 +422,8 @@ outside, and then map the outer scope to a directive's inner scope. We can do th
</file> </file>
</example> </example>
Looking at `index.html`, the first `<my-customer>` element binds the inner scope's `customer` to `naomi`, Looking at `index.html`, the first `<my-customer>` element binds the inner scope's `customer` to
which we have exposed on our controller's scope. The second binds `customer` to `igor`. `naomi`, which we have exposed on our controller's scope. The second binds `customer` to `igor`.
Let's take a closer look at the scope option: Let's take a closer look at the scope option:
@ -425,16 +435,18 @@ scope: {
//... //...
``` ```
The property name (`customer`) corresponds to the variable name of the `myCustomer` directive's isolated scope. The property name (`customer`) corresponds to the variable name of the `myCustomer` directive's
The value of the property (`=customer`) tells `$compile` to bind to the `customer` attribute. isolated scope. The value of the property (`=customer`) tells `$compile` to bind to the `customer`
attribute.
<div class="alert alert-warning"> <div class="alert alert-warning">
**Note:** These `=attr` attributes in the `scope` option of directives are normalized just like directive names. **Note:** These `=attr` attributes in the `scope` option of directives are normalized just like
To bind to the attribute in `<div bind-to-this="thing">`, you'd specify a binding of `=bindToThis`. directive names. To bind to the attribute in `<div bind-to-this="thing">`, you'd specify a binding
of `=bindToThis`.
</div> </div>
For cases where the attribute name is the same as the value you want to bind to inside For cases where the attribute name is the same as the value you want to bind to inside the
the directive's scope, you can use this shorthand syntax: directive's scope, you can use this shorthand syntax:
```javascript ```javascript
//... //...
@ -445,11 +457,11 @@ scope: {
//... //...
``` ```
Besides making it possible to bind different data to the scope inside a directive, using an isolated scope has another Besides making it possible to bind different data to the scope inside a directive, using an isolated
effect. scope has another effect.
We can show this by adding another property, `vojta`, to our scope and trying to access it We can show this by adding another property, `vojta`, to our scope and trying to access it from
from within our directive's template: within our directive's template:
<example module="docsIsolationExample"> <example module="docsIsolationExample">
<file name="script.js"> <file name="script.js">
@ -505,7 +517,8 @@ In this example we will build a directive that displays the current time.
Once a second, it updates the DOM to reflect the current time. Once a second, it updates the DOM to reflect the current time.
Directives that want to modify the DOM typically use the `link` option. Directives that want to modify the DOM typically use the `link` option.
`link` takes a function with the following signature, `function link(scope, element, attrs) { ... }` where: `link` takes a function with the following signature, `function link(scope, element, attrs) { ... }`
where:
* `scope` is an Angular scope object. * `scope` is an Angular scope object.
* `element` is the jqLite-wrapped element that this directive matches. * `element` is the jqLite-wrapped element that this directive matches.
@ -566,8 +579,9 @@ if the directive is deleted so we don't introduce a memory leak.
</example> </example>
There are a couple of things to note here. There are a couple of things to note here.
Just like the `module.controller` API, the function argument in `module.directive` is dependency injected. Just like the `module.controller` API, the function argument in `module.directive` is dependency
Because of this, we can use `$timeout` and `dateFilter` inside our directive's `link` function. injected. Because of this, we can use `$timeout` and `dateFilter` inside our directive's `link`
function.
We register an event `element.on('$destroy', ...)`. What fires this `$destroy` event? We register an event `element.on('$destroy', ...)`. What fires this `$destroy` event?
@ -581,8 +595,9 @@ but if you registered a listener on a service, or registered a listener on a DOM
being deleted, you'll have to clean it up yourself or you risk introducing a memory leak. being deleted, you'll have to clean it up yourself or you risk introducing a memory leak.
<div class="alert alert-success"> <div class="alert alert-success">
**Best Practice:** Directives should clean up after themselves. You can use `element.on('$destroy', ...)` **Best Practice:** Directives should clean up after themselves. You can use
or `scope.$on('$destroy', ...)` to run a clean-up function when the directive is removed. `element.on('$destroy', ...)` or `scope.$on('$destroy', ...)` to run a clean-up function when the
directive is removed.
</div> </div>
@ -620,11 +635,11 @@ To do this, we need to use the `transclude` option.
</file> </file>
</example> </example>
What does this `transclude` option do, exactly? `transclude` makes the contents of a directive with this What does this `transclude` option do, exactly? `transclude` makes the contents of a directive with
option have access to the scope **outside** of the directive rather than inside. this option have access to the scope **outside** of the directive rather than inside.
To illustrate this, see the example below. Notice that we've added a `link` function in `script.js` that To illustrate this, see the example below. Notice that we've added a `link` function in `script.js`
redefines `name` as `Jeff`. What do you think the `{{name}}` binding will resolve to now? that redefines `name` as `Jeff`. What do you think the `{{name}}` binding will resolve to now?
<example module="docsTransclusionExample"> <example module="docsTransclusionExample">
<file name="script.js"> <file name="script.js">
@ -670,11 +685,12 @@ pass in each model you wanted to use separately. If you have to pass in each mod
use, then you can't really have arbitrary contents, can you? use, then you can't really have arbitrary contents, can you?
<div class="alert alert-success"> <div class="alert alert-success">
**Best Practice:** only use `transclude: true` when you want to create a directive that wraps arbitrary content. **Best Practice:** only use `transclude: true` when you want to create a directive that wraps
arbitrary content.
</div> </div>
Next, we want to add buttons to this dialog box, and allow someone using the directive to bind their own Next, we want to add buttons to this dialog box, and allow someone using the directive to bind their
behavior to it. own behavior to it.
<example module="docsIsoFnBindExample"> <example module="docsIsoFnBindExample">
<file name="script.js"> <file name="script.js">
@ -894,5 +910,6 @@ point for creating your own directives.
You might also be interested in an in-depth explanation of the compilation process that's You might also be interested in an in-depth explanation of the compilation process that's
available in the {@link guide/compiler compiler guide}. available in the {@link guide/compiler compiler guide}.
The {@link api/ng.$compile `$compile` API} page has a comprehensive list of directive options for reference. The {@link api/ng.$compile `$compile` API} page has a comprehensive list of directive options for
reference.