Hi guys I hope you are doing well lately I'm learning angular through a book and came across custom Directives,@Input and @Output decorators I totally understood how to use these latters very well the only thing that left me perplexed is the argument passed in the @Input and @Output decorators well here is the code of the book
import { Directive, ElementRef, Input, SimpleChanges, Output, EventEmitter } from "@angular/core";
import { Product } from "./product.model";
@Directive({
selector: "[pa-attr]"
})
export class PaAttrDirective {
constructor(private element: ElementRef) {
this.element.nativeElement.addEventListener("click", () => {
if (this.product != null) {
this.click.emit(this.product.category);
}
});
}
@Input("pa-attr")
bgClass: string | null = "";
@Input("pa-product")
product: Product = new Product();
@Output("pa-category")
click = new EventEmitter<string>();
ngOnChanges(changes: SimpleChanges) {
let change = changes["bgClass"];
let classList = this.element.nativeElement.classList;
if (!change.isFirstChange() && classList.contains(change.previousValue)) {
classList.remove(change.previousValue);
}
if (!classList.contains(change.currentValue)) {
classList.add(change.currentValue);
}
}
}
The template where those latters are applied goes like this:
<tbody>
<tr *ngFor="let item of getProducts(); let i = index"
[pa-attr]="getProducts().length < 6 ? 'table-success' : 'table-warning'"
[pa-product]="item" (pa-category)="newProduct.category = $event">
<td>{{i + 1}}</td>
<td>{{item.name}}</td>
<td [pa-attr]="item.category == 'Soccer' ? 'table-info' : null">
{{item.category}}
</td>
<td [pa-attr]="'table-info'">{{item.price}}</td>
</tr>
</tbody>
So my question is:The arguments inside the second @Input and @Output are not declared anywhere like the argument in the first @Input so what is the use of these two arguments?
also are we allowed to use any argument inside these decorators without predeclaring them like the directive in the first @Input?
The directive selector [pa-attr]
is not required to match an input parameter, it's just shortcut that you don't need an extra selector which is added to your html code and it makes that one input basically required, because if its not there the directive will not be attached.
Assuming your selector would look like this and the rest of the code was the same your html would look like that:
@Directive({
selector: "my-directive"
})
<tbody>
<tr *ngFor="let item of getProducts(); let i = index"
my-directive
[pa-attr]="getProducts().length < 6 ? 'table-success' : 'table-warning'"
[pa-product]="item" (pa-category)="newProduct.category = $event">
<td>{{i + 1}}</td>
<td>{{item.name}}</td>
<td [pa-attr]="item.category == 'Soccer' ? 'table-info' : null">
{{item.category}}
</td>
<td [pa-attr]="'table-info'">{{item.price}}</td>
</tr>
</tbody>
In that case the directive could still be attached, even while the [pa-attr]
would be missing, which might lead to errors in its functionallity.
Additionally @Input
and @Output
do not require an argument, if none is passed the name of the variable will be the input selector on the component. But as it is in your example, variables are often camel case while html tags are often kebab case.