Source: https://alligator.io/angular/custom-form-control/
import { Component, forwardRef, HostBinding, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'rating-input',
template: `
<span
*ngFor="let starred of stars; let i = index"
(click)="onTouched(); rate(i + (starred ? (value > i + 1 ? 1 : 0) : 1))">
<ng-container *ngIf="starred; else noStar">⭐</ng-container>
<ng-template #noStar>·</ng-template>
</span>
`,
styles: [`
span {
display: inline-block;
width: 25px;
line-height: 25px;
text-align: center;
cursor: pointer;
}
`],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RatingInputComponent),
multi: true
}
]
})
export class RatingInputComponent implements ControlValueAccessor {
stars: boolean[] = Array(5).fill(false);
@Input() disabled = false;
@HostBinding('style.opacity')
get opacity() {
return this.disabled ? 0.25 : 1;
}
onChange = (rating: number) => { };
onTouched = () => { };
get value(): number {
return this.stars.reduce((total, starred) => {
return total + (starred ? 1 : 0);
}, 0);
}
rate(rating: number) {
if (!this.disabled) {
this.writeValue(rating);
}
}
// ControlValueAccessor implementation
writeValue(rating: number): void {
this.stars = this.stars.map((_, i) => rating > i);
this.onChange(this.value)
}
registerOnChange(fn: (rating: number) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
132800cookie-checkAngular Advanced Control example