docs(attribute directives): copy edits squashed (#2508)

This commit is contained in:
Kapunahele Wong 2016-10-13 18:42:23 -04:00 committed by Ward Bell
parent 0f9a00f144
commit f49633a62c
1 changed files with 194 additions and 194 deletions

View File

@ -4,134 +4,136 @@ block includes
:marked :marked
An **Attribute** directive changes the appearance or behavior of a DOM element. An **Attribute** directive changes the appearance or behavior of a DOM element.
:marked :marked
In this chapter we will # Contents
* [write an attribute directive to change the background color](#write-directive)
* [apply the attribute directive to an element in a template](#apply-directive)
* [respond to user-initiated events](#respond-to-user) * [Directives overview](#directive-overview)
* [pass values into the directive using data binding](#bindings) * [Build a simple attribute directive](#write-directive)
* [Apply the attribute directive to an element in a template](#apply-directive)
* [Respond to user-initiated events](#respond-to-user)
* [Pass values into the directive using data binding](#bindings)
* [Bind to a second property](#second-property)
Try the <live-example></live-example>. Try the <live-example></live-example>.
.l-main-section
a#directive-overview
:marked
## Directives overview ## Directives overview
There are three kinds of directives in Angular: There are three kinds of directives in Angular:
1. Components 1. Components&mdash;directives with a template.
1. Structural directives 1. Structural directives&mdash;change the DOM layout by adding and removing DOM elements.
1. Attribute directives 1. Attribute directives&mdash;change the appearance or behavior of an element.
A *Component* is really a directive with a template. *Components* are the most common of the three directives. Read more about creating them
It's the most common of the three directives and we tend to write lots of them as we build applications. in step three of [QuickStart](../quickstart.html#root-component).
[*Structural* directives](structural-directives.html) can change the DOM layout by adding and removing DOM elements. *Structural Directives* change the structure of the view. Two examples are [NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.html#ngIf)
[NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.html#ngIf) are two familiar examples. in the [Template Syntax](template-syntax.html) page.
An *Attribute* directive can change the appearance or behavior of an element. *Attribute directives* are used as attributes of elements. The built-in [NgStyle](template-syntax.html#ngStyle) directive in the [Template Syntax](template-syntax.html) page, for example,
The built-in [NgStyle](template-syntax.html#ngStyle) directive, for example,
can change several element styles at the same time. can change several element styles at the same time.
We are going to write our own attribute directive to set an element's background color
when the user hovers over that element.
.l-sub-section
:marked
We don't need *any* directive to simply set the background color.
We can set it with the special [Style Binding](template-syntax.html#style-binding) like this:
+makeExample('attribute-directives/ts/app/app.component.1.html','p-style-background')
:marked
That wouldn't be nearly as much fun as creating our own directive.
Besides, we're not just *setting* the color; we'll be *changing* the color
in response to a user action, a mouse hover.
.l-main-section .l-main-section
a#write-directive a#write-directive
:marked :marked
## Build a simple attribute directive ## Build a simple attribute directive
An attribute directive minimally requires building a controller class annotated with An attribute directive minimally requires building a controller class annotated with
`@Directive`, which specifies the selector identifying `@Directive`, which specifies the selector that identifies
the attribute associated with the directive. the attribute.
The controller class implements the desired directive behavior. The controller class implements the desired directive behavior.
Let's build a small illustrative example together. This page demonstrates building a simple attribute
directive to set an element's background color
when the user hovers over that element.
.l-sub-section
:marked
Technically, a directive isn't necessary to simply set the background color. Style binding can set styles as follows:
+makeExample('attribute-directives/ts/app/app.component.1.html','p-style-background')
:marked
Read more about [style binding](template-syntax.html#style-binding) on the [Template Syntax](template-syntax.html) page.
For a simple example, though, this will demonstrate how attribute directives work.
:marked :marked
### Our first draft ### Write the directive code
Create a new project folder (`attribute-directives`) and follow the steps in the [QuickStart](../quickstart.html). Create a new project folder (`attribute-directives`) and follow the steps in [QuickStart](../quickstart.html).
include ../_quickstart_repo include ../_quickstart_repo
:marked :marked
Create the following source file in the indicated folder with the given code: Create the following source file in the indicated folder with the following code:
+makeExample('app/highlight.directive.1.ts') +makeExample('app/highlight.directive.1.ts')
block highlight-directive-1 block highlight-directive-1
:marked :marked
We begin by importing some symbols from the Angular `core`. The `import` statement specifies symbols from the Angular `core`:
We need the `Directive` symbol for the `@Directive` decorator. 1. `Directive` provides the functionality of the `@Directive` decorator.
We need the `ElementRef` to [inject](dependency-injection.html) into the directive's constructor 1. `ElementRef` [injects](dependency-injection.html) into the directive's constructor
so we can access the DOM element. so the code can access the DOM element.
We also need `Renderer` so we can change the DOM element's style. 1. `Input` allows data to flow from the binding expression into the directive.
We don't need `Input` immediately but we will need it later in the chapter. 1. `Renderer` allows the code to change the DOM element's style.
Next, the `@Directive` decorator function contains the directive metadata in a configuration object
as an argument.
Then we define the directive metadata in a configuration object passed
as an argument to the `@Directive` decorator function.
:marked :marked
`@Directive` requires a CSS selector to identify `@Directive` requires a CSS selector to identify
the HTML in the template that is associated with our directive. the HTML in the template that is associated with the directive.
The [CSS selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) The [CSS selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)
is the attribute name in square brackets. is the attribute name in square brackets.
Our directive's selector is `[myHighlight]`. Here, the directive's selector is `[myHighlight]`.
Angular will locate all elements in the template that have an attribute named `myHighlight`. Angular will locate all elements in the template that have an attribute named `myHighlight`.
.l-sub-section .l-sub-section
:marked :marked
### Why not call it "highlight"? ### Why not call it "highlight"?
*highlight* is a nicer name than *myHighlight* and, technically, it would work if we called it that. Though *highlight* is a more concise name than *myHighlight* and would work,
a best practice is to prefix selector names to ensure
they don't conflict with standard HTML attributes.
This also reduces the risk colliding with third-party directive names.
However, we recommend picking a selector name with a prefix to ensure Make sure you do **not** prefix the `highlight` directive name with **`ng`** because
that it cannot conflict with any standard HTML attribute, now or in the future. that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose. For a simple demo, the short prefix, `my`, helps distinguish your custom directive.
There is also less risk of colliding with a third-party directive name when we give ours a prefix.
We do **not** prefix our `highlight` directive name with **`ng`**.
That prefix belongs to Angular.
We need a prefix of our own, preferably short, and `my` will do for now.
p p
| After the #[code @Directive] metadata comes the directive's controller class, which contains the logic for the directive. | After the #[code @Directive] metadata comes the directive's controller class, called #[code HighlightDirective], which contains the logic for the directive.
+ifDocsFor('ts') +ifDocsFor('ts')
| We export `HighlightDirective` to make it accessible to other components. | Exporting #[code HighlightDirective] makes it accessible to other components.
:marked :marked
Angular creates a new instance of the directive's controller class for Angular creates a new instance of the directive's controller class for
each matching element, injecting an Angular `ElementRef` and `Renderer` each matching element, injecting an Angular `ElementRef` and `Renderer`
into the constructor. into the constructor.
`ElementRef` is a service that grants us direct access to the DOM element `ElementRef` is a service that grants direct access to the DOM element
through its `nativeElement` property and with `Renderer` we can set the element style. through its `nativeElement` property and `Renderer` allows the code to set the element style.
.l-main-section .l-main-section
a#apply-directive a#apply-directive
:marked :marked
## Apply the attribute directive ## Apply the attribute directive
The `AppComponent` in this sample is a test harness for our `HighlightDirective`. To use the new `HighlightDirective`, create a template that
Let's give it a new template that
applies the directive as an attribute to a paragraph (`p`) element. applies the directive as an attribute to a paragraph (`p`) element.
In Angular terms, the `<p>` element will be the attribute **host**. In Angular terms, the `<p>` element will be the attribute **host**.
p p
| We'll put the template in its own | Put the template in its own
code #[+adjExPath('app.component.html')] code #[+adjExPath('app.component.html')]
| file that looks like this: | file that looks like this:
+makeExample('attribute-directives/ts/app/app.component.1.html',null,'app/app.component.html')(format=".") +makeExample('attribute-directives/ts/app/app.component.1.html',null,'app/app.component.html')(format=".")
:marked :marked
A separate template file is clearly overkill for a 2-line template. Now reference this template in the `AppComponent`:
Hang in there; we're going to expand it later.
Meanwhile, we'll revise the `AppComponent` to reference this template.
+makeExample('attribute-directives/ts/app/app.component.ts',null,'app/app.component.ts') +makeExample('attribute-directives/ts/app/app.component.ts',null,'app/app.component.ts')
:marked :marked
We'll add an `import` statement to fetch the 'Highlight' directive and, Next, add an `import` statement to fetch the `Highlight` directive and
added that class to the `declarations` NgModule metadata so that Angular add that class to the `declarations` NgModule metadata. This way Angular
will recognize our directive when it encounters `myHighlight` in the template. recognizes the directive when it encounters `myHighlight` in the template.
+makeExample('attribute-directives/ts/app/app.module.ts',null,'app/app.module.ts') +makeExample('attribute-directives/ts/app/app.module.ts',null,'app/app.module.ts')
:marked :marked
We run the app and see that our directive highlights the paragraph text. Now when the app runs, the `myHighlight` directive highlights the paragraph text.
figure.image-display figure.image-display
img(src="/resources/images/devguide/attribute-directives/first-highlight.png" alt="First Highlight") img(src="/resources/images/devguide/attribute-directives/first-highlight.png" alt="First Highlight")
@ -145,160 +147,159 @@ figure.image-display
code-example(format="nocode"). code-example(format="nocode").
EXCEPTION: Template parse errors: EXCEPTION: Template parse errors:
Can't bind to 'myHighlight' since it isn't a known property of 'p'. Can't bind to 'myHighlight' since it isn't a known property of 'p'.
:marked
Angular detects that we're trying to bind to *something* but it doesn't know what.
We have to tell it by listing `HighlightDirective` in the `declarations` metadata array.
:marked
Let's recap what happened.
Angular found the `myHighlight` attribute on the `<p>` element. It created :marked
Angular detects that you're trying to bind to *something* but it doesn't know what,
so it looks to the `declarations` metadata array. By specifying `HighlightDirective`
in the array, Angular knows to check the import statements and from there,
to go to `highlight.directive.ts` to find out what `myHighlight` does.
:marked
To summarize, Angular found the `myHighlight` attribute on the `<p>` element. It created
an instance of the `HighlightDirective` class, an instance of the `HighlightDirective` class,
injecting a reference to the element into the constructor injecting a reference to the element into the constructor
where we set the `<p>` element's background style to yellow. where the `<p>` element's background style is set to yellow.
.l-main-section .l-main-section
a#respond-to-user a#respond-to-user
:marked :marked
## Respond to user action ## Respond to user-initiated events
We are not satisfied to simply set an element color. Currently, `myHighlight` simply sets an element color.
Our directive should set the color in response to a user action. The directive should set the color when the user hovers over an element.
Specifically, we want to set the color when the user hovers over an element.
We'll need to This requires two things:
1. detect when the user hovers into and out of the element, 1. detecting when the user hovers into and out of the element.
2. respond to those actions by setting and clearing the highlight color, respectively. 2. responding to those actions by setting and clearing the highlight color.
We apply the `@HostListener` !{_decorator} to methods which are called when an event is raised. To do this, you can apply the `@HostListener` !{_decorator} to methods which are called when an event is raised.
+makeExample('attribute-directives/ts/app/highlight.directive.2.ts','host')(format=".") +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','host')(format=".")
.l-sub-section .l-sub-section
:marked :marked
The `@HostListener` !{_decorator} refers to the DOM element that hosts our attribute directive, the `<p>` in our case. The `@HostListener` !{_decorator} refers to the DOM element that hosts an attribute directive, the `<p>` in this case.
We could have attached event listeners by manipulating the host DOM element directly, but It is possible to attach event listeners by manipulating the host DOM element directly, but
there are at least three problems with such an approach: there are at least three problems with such an approach:
1. We have to write the listeners correctly. 1. You have to write the listeners correctly.
1. We must *detach* our listener when the directive is destroyed to avoid memory leaks. 1. The code must *detach* the listener when the directive is destroyed to avoid memory leaks.
1. We'd be talking to DOM API directly which, we learned, is something to avoid. 1. Talking to DOM API directly isn't a best practice.
Let's roll with the `@HostListener` !{_decorator}.
:marked :marked
Now we implement the two mouse event handlers: Now implement the two mouse event handlers:
+makeExample('attribute-directives/ts/app/highlight.directive.2.ts','mouse-methods')(format=".") +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','mouse-methods')(format=".")
:marked :marked
Notice that they delegate to a helper method that sets the color via a private local variable, `#{_priv}el`. Notice that they delegate to a helper method that sets the color via a private local variable, `#{_priv}el`.
We revise the constructor to capture the `ElementRef.nativeElement` in this variable. Next, revise the constructor to capture the `ElementRef.nativeElement` in this variable.
+makeExample('attribute-directives/ts/app/highlight.directive.2.ts','ctor')(format=".") +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','ctor')(format=".")
:marked :marked
Here's the updated directive: Here's the updated directive:
+makeExample('app/highlight.directive.2.ts') +makeExample('app/highlight.directive.2.ts')
:marked :marked
We run the app and confirm that the background color appears as we move the mouse over the `p` and Run the app and confirm that the background color appears when the mouse hovers over the `p` and
disappears as we move out. disappears as it moves out.
figure.image-display figure.image-display
img(src="/resources/images/devguide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight") img(src="/resources/images/devguide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight")
.l-main-section .l-main-section
a#bindings a#bindings
:marked :marked
## Configure the directive with binding ## Pass values into the directive using data binding
Currently the highlight color is hard-coded within the directive. That's inflexible. Currently the highlight color is hard-coded within the directive. That's inflexible.
We should set the color externally with a binding like this: A better practice is to set the color externally with a binding as follows:
+makeExample('attribute-directives/ts/app/app.component.html','pHost') +makeExample('attribute-directives/ts/app/app.component.html','pHost')
:marked :marked
We'll extend our directive class with a bindable **input** `highlightColor` property and use it when we highlight text. You can extend the directive class with a bindable **input** `highlightColor` property and use it to highlight text.
Here is the final version of the class: Here is the final version of the class:
+makeExcerpt('app/highlight.directive.ts', 'class') +makeExcerpt('app/highlight.directive.ts', 'class')
a#input a#input
:marked :marked
The new `highlightColor` property is called an *input* property because data flows from the binding expression into our directive. The new `highlightColor` property is called an *input* property because data flows from the binding expression into the directive.
Notice the `@Input()` #{_decorator} applied to the property. Notice the `@Input()` #{_decorator} applied to the property.
+makeExcerpt('app/highlight.directive.ts', 'color') +makeExcerpt('app/highlight.directive.ts', 'color')
:marked :marked
`@Input` adds metadata to the class that makes the `highlightColor` property available for `@Input` adds metadata to the class that makes the `highlightColor` property available for
property binding under the `myHighlight` alias. property binding under the `myHighlight` alias.
We must add this input metadata or Angular will reject the binding. Without this input metadata Angular rejects the binding.
See the [appendix](#why-input) below to learn why. See the [appendix](#why-input) below for more information.
.l-sub-section .l-sub-section
:marked :marked
### @Input(_alias_) ### @Input(_alias_)
The developer who uses this directive expects to bind to the attribute name, `myHighlight`. Currently, the code **aliases** the `highlightColor` property with the attribute name by
The directive property name is `highlightColor`. That's a disconnect.
We could resolve the discrepancy by renaming the property to `myHighlight` and define it as follows:
+makeExcerpt('app/highlight.directive.ts', 'highlight', '')
:marked
Maybe we don't want that property name inside the directive perhaps because it
doesn't express our intention well.
We can **alias** the `highlightColor` property with the attribute name by
passing `myHighlight` into the `@Input` #{_decorator}: passing `myHighlight` into the `@Input` #{_decorator}:
+makeExcerpt('app/highlight.directive.ts', 'color', '') +makeExcerpt('app/highlight.directive.ts', 'color', '')
:marked
The code binds to the attribute name, `myHighlight`, but the
the directive property name is `highlightColor`. That's a disconnect.
You can resolve the discrepancy by renaming the property to `myHighlight` and define it as follows:
+makeExcerpt('app/highlight.directive.ts', 'highlight', '')
:marked :marked
Now that we're getting the highlight color as an input, we modify the `onMouseEnter()` method to use Now that you're getting the highlight color as an input, modify the `onMouseEnter()` method to use
it instead of the hard-coded color name. it instead of the hard-coded color name and define red as the default color.
We also define red as the default color to fallback on in case
the user neglects to bind with a color.
+makeExcerpt('attribute-directives/ts/app/highlight.directive.ts', 'mouse-enter', '') +makeExcerpt('attribute-directives/ts/app/highlight.directive.ts', 'mouse-enter', '')
:marked :marked
Now we'll update our `AppComponent` template to let To let users pick the highlight color and bind their choice to the directive,
users pick the highlight color and bind their choice to our directive. update `app.component.html` as follows:
Here is the updated template:
+makeExcerpt('attribute-directives/ts/app/app.component.html', 'v2', '') +makeExcerpt('attribute-directives/ts/app/app.component.html', 'v2', '')
.l-sub-section .l-sub-section
:marked :marked
### Where is the templated *color* property? ### Where is the templated *color* property?
The eagle-eyed may notice that the radio button click handlers in the template set a `color` property You may notice that the radio button click handlers in the template set a `color` property
and we are binding that `color` to the directive. and the code is binding that `color` to the directive.
We should expect to find a `color` on the host `AppComponent`. However, you never defined a color property for the host `AppComponent`.
Yet this code works. Where is the template `color` value going?
**We never defined a color property for the host *AppComponent***!
And yet this code works. Where is the template `color` value going?
Browser debugging reveals that Angular dynamically added a `color` property Browser debugging reveals that Angular dynamically added a `color` property
to the runtime instance of the `AppComponent`. to the runtime instance of the `AppComponent`.
This is *convenient* behavior but it is also *implicit* behavior that could be confusing. This is *convenient* behavior but it is also *implicit* behavior that could be confusing.
While it's cool that this technique works, we recommend adding the `color` property to the `AppComponent`. For clarity, consider adding the `color` property to the `AppComponent`.
:marked :marked
Here is our second version of the directive in action. Here is the second version of the directive in action.
figure.image-display figure.image-display
img(src="/resources/images/devguide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2") img(src="/resources/images/devguide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2")
.l-main-section .l-main-section
a#second-property
:marked :marked
## Bind to a second property ## Bind to a second property
Our directive only has a single, customizable property. What if we had ***two properties***? This example directive only has a single customizable property. A real app often needs more.
Let's allow the template developer to set the default color, the color that prevails until the user picks a highlight color. Let's allow the template developer to set the default color&mdash;the color that prevails until the user picks a highlight color.
We'll add a second **input** property to `HighlightDirective` called `defaultColor`: To do this, first add a second **input** property to `HighlightDirective` called `defaultColor`:
+makeExample('attribute-directives/ts/app/highlight.directive.ts', 'defaultColor')(format=".") +makeExample('attribute-directives/ts/app/highlight.directive.ts', 'defaultColor')(format=".")
:marked :marked
The `defaultColor` property has a setter that overrides the hard-coded default color, "red". The `defaultColor` property has a setter that overrides the hard-coded default color, "red".
We don't need a getter. You don't need a getter.
How do we bind to it? We already "burned" the `myHighlight` attribute name as a binding target. How do you bind to it? The app is already using `myHighlight` attribute name as a binding target.
Remember that a *component is a directive too*. Remember that a *component is a directive, too*.
We can add as many component property bindings as we need by stringing them along in the template You can add as many component property bindings as you need by stringing them along in the template
as in this example that sets the `a`, `b`, `c` properties to the string literals 'a', 'b', and 'c'. as in this example that sets the `a`, `b`, `c` properties to the string literals 'a', 'b', and 'c'.
code-example(format="." ). code-example(format="." ).
&lt;my-component [a]="'a'" [b]="'b'" [c]="'c'">&lt;my-component> &lt;my-component [a]="'a'" [b]="'b'" [c]="'c'">&lt;my-component>
:marked :marked
We do the same thing with an attribute directive. The same holds true for an attribute directive.
+makeExample('attribute-directives/ts/app/app.component.html', 'defaultColor')(format=".") +makeExample('attribute-directives/ts/app/app.component.html', 'defaultColor')(format=".")
:marked :marked
Here we're binding the user's color choice to the `myHighlight` attribute as we did before. Here the code is binding the user's color choice to the `myHighlight` attribute as before.
We're *also* binding the literal string, 'violet', to the `defaultColor`. It is *also* binding the literal string, 'violet', to the `defaultColor`.
Here is the final version of the directive in action. Here is the final version of the directive in action.
figure.image-display figure.image-display
@ -307,11 +308,11 @@ figure.image-display
.l-main-section .l-main-section
:marked :marked
## Summary ## Summary
We now know how to This page covered how to:
- [build a simple **attribute directive** to attach behavior to an HTML element](#write-directive), - [Build a simple **attribute directive** to attach behavior to an HTML element](#write-directive).
- [use that directive in a template](#apply-directive), - [Use that directive in a template](#apply-directive).
- [respond to **events** to change behavior based on an event](#respond-to-user), - [Respond to **events** to change behavior based on an event](#respond-to-user).
- and [use **binding** to pass values to the attribute directive](#bindings). - [Use **binding** to pass values to the attribute directive](#bindings).
The final source: The final source:
@ -338,38 +339,37 @@ a#why-input
:marked :marked
### Appendix: Input properties ### Appendix: Input properties
Earlier we declared the `highlightColor` property to be an ***input*** property of our In this demo, the `highlightColor` property is an ***input*** property of
`HighlightDirective` `HighlightDirective`.
We've seen properties in bindings before. You've seen properties in bindings before but never had to declare them as anything. Why now?
We never had to declare them as anything. Why now?
Angular makes a subtle but important distinction between binding **sources** and **targets**. Angular makes a subtle but important distinction between binding **sources** and **targets**.
In all previous bindings, the directive or component property was a binding ***source***. In all previous bindings, the directive or component property was a binding ***source***.
A property is a *source* if it appears in the template expression to the ***right*** of the equals (=). A property is a *source* if it appears in the template expression to the ***right*** of the equals (=).
A property is a *target* when it appears in **square brackets** ([ ]) to the **left** of the equals (=) ... A property is a *target* when it appears in **square brackets** ([ ]) to the **left** of the equals (=)
as it is does when we bind to the `myHighlight` property of the `HighlightDirective`, as it is does when binding to the `myHighlight` property of the `HighlightDirective`.
+makeExample('attribute-directives/ts/app/app.component.html','pHost')(format=".") +makeExample('attribute-directives/ts/app/app.component.html','pHost')(format=".")
:marked :marked
The 'color' in `[myHighlight]="color"` is a binding ***source***. The 'color' in `[myHighlight]="color"` is a binding ***source***.
A source property doesn't require a declaration. A source property doesn't require a declaration.
The 'myHighlight' in `[myHighlight]="color"` *is* a binding ***target***. The 'myHighlight' in `[myHighlight]="color"` *is* a binding ***target***.
We must declare it as an *input* property. You must declare it as an *input* property or
Angular rejects the binding with a clear error if we don't. Angular rejects the binding with a clear error.
Angular treats a *target* property differently for a good reason. Angular treats a *target* property differently for a good reason.
A component or directive in target position needs protection. A component or directive in target position needs protection.
Imagine that our `HighlightDirective` did truly wonderous things. Imagine that `HighlightDirective` did truly wonderous things in a
We graciously made a gift of it to the world. popular open source project.
To our surprise, some people &mdash; perhaps naively &mdash; Surprisingly, some people &mdash; perhaps naively &mdash;
started binding to *every* property of our directive. start binding to *every* property of the directive.
Not just the one or two properties we expected them to target. *Every* property. Not just the one or two properties you expected them to target. *Every* property.
That could really mess up our directive in ways we didn't anticipate and have no desire to support. That could really mess up your directive in ways you didn't anticipate and have no desire to support.
The *input* declaration ensures that consumers of our directive can only bind to The ***input*** declaration ensures that consumers of your directive can only bind to
the properties of our public API ... nothing else. the properties of the public API but nothing else.