Reputation: 6810
I'm trying to make a wrapper component for a color picker using ngx-color-picker
and Angular Materials FormField
. I configured it as required
but it's outline doesn't turn red when invalid like the other form fields... How can I achieve this behavior on my custom form field?
color-picker.component.ts
import { Component, Input, forwardRef } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
// inspiration:
// https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html
export const requiredValidator = (c: FormControl): ValidationErrors | null => {
return
c.value === '' ||
c.value === null ||
c.value === undefined ||
c.value.length === 0
? {
required: {
valid: false,
},
}
: null
}
@Component({
selector: 'nda-color-picker',
templateUrl: './color-picker.component.html',
styleUrls: ['./color-picker.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ColorPickerComponent),
multi: true,
},
],
})
export class ColorPickerComponent implements ControlValueAccessor, Validator {
@Input() label: string
_color: string
get color() {
return this._color
}
set color(value: string) {
this._color = value
this.propagateChange(this._color)
}
constructor() {}
writeValue(value: any) {
if (value !== undefined) {
this.color = value
}
}
propagateChange = (_: any) => {}
registerOnChange(fn) {
this.propagateChange = fn
}
registerOnTouched() {}
validate(control: AbstractControl): ValidationErrors | null {
return requiredValidator(control as FormControl)
}
}
color-picker.component.html
<mat-form-field appearance="outline" [floatLabel]="'always'">
<mat-label>{{ label }}</mat-label>
<input
matTooltip="{{ color }}"
cpOKButton="true"
cpCancelButton="true"
[required]="required"
matInput
[ngStyle]="{ color: color, background: color }"
[colorPicker]="color"
(colorPickerChange)="color = $event"
/>
</mat-form-field>
form-component.html
<form
[formGroup]="transportForm"
autocomplete="off"
(ngSubmit)="handleSubmit()"
>A
<div mat-dialog-content>
<div fxLayout="row wrap" fxLayoutGap="1rem">
<mat-form-field appearance="outline">
<mat-label>Icon</mat-label>
<input
matInput
placeholder="Icon"
formControlName="icon"
required
/>
</mat-form-field>
<nda-color-picker
label="Badge Color Code"
formControlName="badgeColorCode"
required
></nda-color-picker>
<nda-color-picker
label="Text Color Code"
formControlName="textColorCode"
required
></nda-color-picker>
<mat-form-field appearance="outline">
<mat-label>Badge Type</mat-label>
<input
matInput
placeholder="Badge Type"
formControlName="badgeType"
/>
</mat-form-field>
</div>
</div>
<!-- dialog actions -->
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="space-between center">
<div>
<button
type="button"
*ngIf="data && data.code"
color="warn"
mat-flat-button
(click)="handleDelete()"
>
DELETE
</button>
</div>
<div class="btn-container">
<button type="reset" mat-stroked-button (click)="handleCancel()">
CANCEL
</button>
<button
mat-flat-button
color="accent"
[disabled]="transportForm.pristine"
>
SAVE
</button>
</div>
<div
*ngIf="!transportForm.valid"
class="mat-small dialog-error-message"
>
* Fill out all required fields
</div>
</div>
</form>
------ UPDATE ------
I updated the color-picker.component
with a validator function and class implementing Validator interface. The validator function is actually called and works as expected. But the form field isn't marked as invalid as reactive form fields normally are (css class .ng-invalid
).
Upvotes: 1
Views: 2570
Reputation: 57909
ibenjelloun, there a bug in your code. Replace your function get value() to return null if ratting equals 0 else if select an start and deselect don't give you error
get value(): number {
let ratting= this.stars.reduce((total, starred) => {
return total + (starred ? 1 : 0);
}, 0);
return ratting?ratting:null;
}
Olefrank if you want that the control was who give the error add providers and create function validate, see the ibenjelloun forked stackblitz
Upvotes: 0
Reputation: 7713
You can use ReactiveFormsModule
custom classes to set styles for different statuses :
.ng-invalid {
border: 1px solid red;
}
You can find more documentation about ReactiveFormsModule
css classes in angular.io...css-classes.
Upvotes: 1