Skip to content

Commit 12a9950

Browse files
committed
feat: rating-conrol
1 parent 0d15a0b commit 12a9950

3 files changed

Lines changed: 47 additions & 16 deletions

File tree

apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,15 @@
1313
[formControl]="feedbackForm.controls.email"
1414
placeholder="Email"
1515
type="email" />
16-
<app-rating-control (ratingUpdated)="rating = $event"></app-rating-control>
16+
<app-rating-control [formControl]="feedbackForm.controls.rating"></app-rating-control>
1717
<textarea
1818
class="feedback-form-control"
1919
[formControl]="feedbackForm.controls.comment"
2020
placeholder="Сomment text"></textarea>
2121
<button
2222
class="feedback-form-submit"
2323
type="submit"
24-
[disabled]="
25-
!feedbackForm.touched || rating === null || feedbackForm.invalid
26-
">
24+
[disabled]="feedbackForm.invalid">
2725
Submit
2826
</button>
2927
</form>

apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,16 @@ export class FeedbackFormComponent {
2525
email: new FormControl('', {
2626
validators: Validators.required,
2727
}),
28+
rating: new FormControl('', {
29+
validators: Validators.required,
30+
}),
2831
comment: new FormControl(),
2932
});
3033

31-
rating: string | null = null;
32-
3334
submitForm(): void {
34-
this.feedBackSubmit.emit({
35-
...this.feedbackForm.value,
36-
rating: this.rating,
37-
});
35+
if (this.feedbackForm.invalid) return;
3836

37+
this.feedBackSubmit.emit(this.feedbackForm.value);
3938
this.feedbackForm.reset();
4039
}
4140
}

apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.ts

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,54 @@
1-
import { Component, EventEmitter, Output } from '@angular/core';
1+
import { Component, forwardRef } from '@angular/core';
2+
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
3+
4+
// eslint-disable-next-line @typescript-eslint/no-empty-function
5+
function noop() {}
26

37
@Component({
48
standalone: true,
59
selector: 'app-rating-control',
610
templateUrl: 'rating-control.component.html',
711
styleUrls: ['rating-control.component.scss'],
12+
providers: [
13+
{
14+
provide: NG_VALUE_ACCESSOR,
15+
useExisting: forwardRef(() => RatingControlComponent),
16+
multi: true,
17+
},
18+
],
819
})
9-
export class RatingControlComponent {
10-
@Output()
11-
readonly ratingUpdated: EventEmitter<string> = new EventEmitter<string>();
20+
export class RatingControlComponent implements ControlValueAccessor {
21+
protected isDisabled = false;
22+
23+
protected value: number | null = null;
24+
25+
private _onChange: (value: string) => void = noop;
26+
private _onTouch = noop;
1227

13-
value: number | null = null;
28+
writeValue(value: number | null): void {
29+
this.value = value;
30+
}
31+
32+
registerOnChange(fn: (value: string) => void): void {
33+
this._onChange = fn;
34+
}
35+
36+
registerOnTouched(fn: typeof noop): void {
37+
this._onTouch = fn;
38+
}
39+
40+
setDisabledState(isDisabled: boolean): void {
41+
this.isDisabled = isDisabled;
42+
}
1443

1544
setRating(index: number): void {
45+
if (this.isDisabled) {
46+
return;
47+
}
48+
1649
this.value = index + 1;
17-
this.ratingUpdated.emit(`${this.value}`);
50+
this._onTouch();
51+
this._onChange(this.value.toString());
1852
}
1953

2054
isStarActive(index: number, value: number | null): boolean {

0 commit comments

Comments
 (0)