Friday, 25 May 2018

Angular - Input and Output properties

An Input property is a settable property annotated with an @Input decorator. Values flow into the property when it is data bound with a property binding
An Output property is an observable property annotated with an @Output decorator. The property almost always returns an Angular EventEmitter. Values flow out of the component as events bound with an event binding.
You can only bind to another component or directive through its Input and Output properties.
Remember that all components are directives.
You are usually binding a template to its own component class. In such binding expressions, the component's property or method is to the right of the (=).
src/app/app.component.html
<img [src]="iconUrl"/>
<button (click)="onSave()">Save</button>
The iconUrl and onSave are members of the AppComponent class. They are not decorated with @Input() or @Output. Angular does not object.
You can always bind to a public property of a component in its own template. It doesn't have to be an Input or Output property
A component's class and template are closely coupled. They are both parts of the same thing. Together they are the component. Exchanges between a component class and its template are internal implementation details.

Binding to a different component:
You can also bind to a property of a different component. In such bindings, the other component's property is to the left of the (=).
In the following example, the AppComponent template binds AppComponent class members to properties of the HeroDetailComponent whose selector is 'app-hero-detail'.
src/app/app.component.html
<app-hero-detail [hero]="currentHero" (deleteRequest)="deleteHero($event)">
</app-hero-detail>
The Angular compiler may reject these bindings with errors like this one:
Uncaught Error: Template parse errors:
Can't bind to 'hero' since it isn't a known property of 'app-hero-detail'
You know that HeroDetailComponent has hero and deleteRequest properties. But the Angular compiler refuses to recognize them.
The Angular compiler won't bind to properties of a different component unless they are Input or Output properties.
There's a good reason for this rule.
It's OK for a component to bind to its own properties. The component author is in complete control of those bindings.
But other components shouldn't have that kind of unrestricted access. You'd have a hard time supporting your component if anyone could bind to any of its properties. Outside components should only be able to bind to the component's public binding API.
Angular asks you to be explicit about that API. It's up to you to decide which properties are available for binding by external components.
You can't use the TypeScript public and private access modifiers to shape the component's public binding API.
All data bound properties must be TypeScript public properties. Angular never binds to a TypeScript private property.
Angular requires some other way to identify properties that outside components are allowed to bind to. That other way is the @Input() and @Output() decorators.

Declaring Input and Output properties:
In the sample for this guide, the bindings to HeroDetailComponent do not fail because the data bound properties are annotated with @Input() and @Output() decorators.
src/app/hero-detail.component.ts
@Input() hero: Hero;
@Output() deleteRequest = new EventEmitter<Hero>();
Alternatively, you can identify members in the inputs and outputs arrays of the directive metadata, as in this example:
src/app/hero-detail.component.ts
  inputs: ['hero'],
  outputs: ['deleteRequest'],
})


Input or output?
Input properties usually receive data values. Output properties expose event producers, such as EventEmitter objects.
The terms input and output reflect the perspective of the target directive.



HeroDetailComponent.hero is an input property from the perspective of HeroDetailComponent because data flows into that property from a template binding expression.
HeroDetailComponent.deleteRequest is an output property from the perspective of HeroDetailComponent because events stream out of that property and toward the handler in a template binding statement.

 Aliasing input/output properties:
Sometimes the public name of an input/output property should be different from the internal name.
This is frequently the case with attribute directives. Directive consumers expect to bind to the name of the directive. For example, when you apply a directive with a myClick selector to a <div> tag, you expect to bind to an event property that is also called myClick.
src/app/app.component.html
<div (myClick)="clickMessage=$event" clickable>click with myClick</div>
However, the directive name is often a poor choice for the name of a property within the directive class. The directive name rarely describes what the property does. The myClick directive name is not a good name for a property that emits click messages.
Fortunately, you can have a public name for the property that meets conventional expectations, while using a different name internally. In the example immediately above, you are actually binding through the myClick alias to the directive's own clicks property.
You can specify the alias for the property name by passing it into the input/output decorator like this:
src/app/click.directive.ts
@Output('myClick') clicks = new EventEmitter<string>(); //  @Output(alias) propertyName = ...
You can also alias property names in the inputs and outputs arrays. You write a colon-delimited (:) string with the directive property name on the left and the public alias on the right:
src/app/click.directive.ts
  outputs: ['clicks:myClick']  // propertyName:alias
})





No comments:

Post a Comment