@angular/forms#NG_VALUE_ACCESSOR TypeScript Examples
The following examples show how to use
@angular/forms#NG_VALUE_ACCESSOR.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: boolean-value-accessor.directive.ts From elements with MIT License | 6 votes |
@Directive({
selector: 'ino-checkbox,ino-control-item[role="checkbox"],ino-switch',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: BooleanValueAccessorDirective,
multi: true,
},
],
})
export class BooleanValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef, private renderer: Renderer2) {
super(el);
}
@HostListener('checkedChange', ['$event.detail'])
_handleInoChange(value: any) {
this.handleChangeEvent(value);
}
writeValue(value: any): void {
this.el.nativeElement.checked = this.lastValue = value == null ? '' : value;
}
}
Example #2
Source File: form-component-superclass.ts From s-libs with MIT License | 6 votes |
/**
* Use in the `providers` of a component that implements `ControlValueAccessor` to reduce some boilerplate.
*
* ```ts
* @Component({ providers: [provideValueAccessor(MyFormControl)] }
* class MyFormControl extends BaseFormControl {
* // ...
* }
* ```
*/
export function provideValueAccessor(type: Type<any>): Provider {
return {
provide: NG_VALUE_ACCESSOR,
useExisting: type,
multi: true,
};
}
Example #3
Source File: text-value-accessor.directive.ts From elements with MIT License | 6 votes |
@Directive({
selector:
'ino-autocomplete,ino-currency-input,ino-input,ino-textarea,ino-range,ino-select,ino-datepicker',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: TextValueAccessorDirective,
multi: true,
},
],
})
export class TextValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}
@HostListener('valueChange', ['$event.detail'])
_handleInputEvent(value: string): void {
this.handleChangeEvent(value);
}
@HostListener('inoBlur')
_handleInoBlur() {
this.handleBlurEvent();
}
}
Example #4
Source File: switch.component.ts From alauda-ui with MIT License | 6 votes |
@Component({
selector: 'aui-switch',
templateUrl: './switch.component.html',
styleUrls: ['./switch.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
preserveWhitespaces: false,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SwitchComponent),
multi: true,
},
],
})
export class SwitchComponent extends CommonFormControl<boolean> {
bem: Bem = buildBem(prefix);
@Input()
loading = false;
onSwitch() {
if (this.disabled) {
return;
}
this.emitValue(!this.model);
}
onBlur() {
if (this.onTouched) {
this.onTouched();
}
}
}
Example #5
Source File: mood-radio.component.ts From onchat-web with Apache License 2.0 | 6 votes |
@Component({
selector: 'app-mood-radio',
templateUrl: './mood-radio.component.html',
styleUrls: ['./mood-radio.component.scss'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MoodRadioComponent),
multi: true
}]
})
export class MoodRadioComponent implements ControlValueAccessor {
private _value: Mood;
set value(value: Mood) {
this._value = value;
this.onValueChange(value);
}
get value(): Mood {
return this._value;
}
readonly mood: typeof Mood = Mood;
constructor() { }
private onValueChange(value: Mood) { }
writeValue(value: Mood): void {
this._value = value;
}
registerOnChange(fn: SafeAny): void {
this.onValueChange = fn;
}
registerOnTouched(fn: SafeAny): void { }
}
Example #6
Source File: datetime-input.ts From angular-material-components with MIT License | 5 votes |
MAT_DATEPICKER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxMatDatetimeInput),
multi: true
}
Example #7
Source File: warehouse-manage-form.component.ts From ng-ant-admin with MIT License | 5 votes |
EXE_COUNTER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => WarehouseManageFormComponent)
}
Example #8
Source File: datetime-input.ts From ngx-mat-datetime-picker with MIT License | 5 votes |
MAT_DATEPICKER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxMatDatetimeInput),
multi: true
}
Example #9
Source File: markdown.component.ts From ng-util with MIT License | 5 votes |
@Component({
selector: 'nu-markdown',
template: ``,
exportAs: 'nuMarkdown',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NuMarkdownComponent),
multi: true,
},
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NuMarkdownComponent extends NuMarkdownBaseComponent implements ControlValueAccessor {
private onChange = (_: string) => {};
protected init(): void {
this.ngZone.runOutsideAngular(() => {
const options = {
value: this._value,
cache: {
enable: false,
},
mode: 'sv',
minHeight: 350,
input: (value: string) => {
this.ngZone.run(() => {
this._value = value;
this.onChange(value);
});
},
...this.config?.defaultOptions,
...this.options,
};
this._instance = new Vditor(this.el.nativeElement, options);
this.ngZone.run(() => this.ready.emit(this._instance));
});
}
private setDisabled(): void {
if (!this.instance) {
return;
}
if (this.disabled) {
this.instance.disabled();
} else {
this.instance.enable();
}
}
writeValue(value: string): void {
this._value = value || '';
if (this.instance) {
this.instance.setValue(this._value);
}
}
registerOnChange(fn: (_: string) => void): void {
this.onChange = fn;
}
registerOnTouched(_: () => void): void {}
setDisabledState(_isDisabled: boolean): void {
this.disabled = _isDisabled;
this.setDisabled();
}
}
Example #10
Source File: color-input.component.ts From angular-material-components with MIT License | 5 votes |
MAT_COLORPICKER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxMatColorPickerInput),
multi: true
}
Example #11
Source File: custom-inputs-fields-form.component.ts From fyle-mobile-app with MIT License | 5 votes |
@Component({
selector: 'app-custom-inputs-fields-form',
templateUrl: './custom-inputs-fields-form.component.html',
styleUrls: ['./custom-inputs-fields-form.component.scss'],
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: CustomInputsFieldsFormComponent, multi: true }],
})
export class CustomInputsFieldsFormComponent implements OnInit, ControlValueAccessor, OnDestroy, OnChanges {
@Input() customInputs: CustomInputs[];
@Input() combinedCustomProperties: CombinedOptions;
@Input() disableFormElements: boolean;
onChangeSub: Subscription;
customFieldsForm: FormGroup;
customFields: CustomInputs[];
constructor(private formBuilder: FormBuilder, private injector: Injector) {}
ngOnInit() {
this.customFieldsForm = this.formBuilder.group({
fields: new FormArray([]),
});
}
generateCustomForm() {
const customFieldsFormArray = this.customFieldsForm?.controls?.fields as FormArray;
customFieldsFormArray.clear();
for (const customField of this.customInputs) {
customFieldsFormArray.push(
this.formBuilder.group({
name: [customField.name],
value: [customField.value],
})
);
}
customFieldsFormArray.updateValueAndValidity();
this.customFields = this.customInputs.map((customField, i) => ({
...customField,
control: customFieldsFormArray.at(i),
}));
}
onTouched = () => {};
ngOnDestroy(): void {
this.onChangeSub.unsubscribe();
}
ngOnChanges() {
if (this.customFieldsForm?.controls) {
this.generateCustomForm();
}
}
writeValue(value: any) {
if (value) {
this.customFieldsForm.controls.fields.patchValue(value);
}
}
registerOnChange(onChange): void {
this.onChangeSub = this.customFieldsForm.valueChanges.subscribe(onChange);
}
registerOnTouched(onTouched): void {
this.onTouched = onTouched;
}
}
Example #12
Source File: fs-value-accessor.directive.ts From elements with MIT License | 5 votes |
@Directive({
selector: 'ino-input-file,input[type=file]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: FsValueAccessorDirective,
multi: true,
},
],
})
export class FsValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}
@HostListener('changeFile', ['$event.detail'])
_handleInputEvent(value: any): void {
if (this.el.nativeElement.multiple) {
this.handleChangeEvent(value.files);
} else {
this.handleChangeEvent(value.files[0]);
}
}
writeValue(value: any): void {
if (value instanceof FileList) {
this.el.nativeElement.files = value;
} else if (Array.isArray(value) && !value.length) {
this.el.nativeElement.files = null;
} else if (value === null) {
this.el.nativeElement.files = null;
} else {
// Since we cannot manually construct a FileList instance, we have to ignore
// any attempt to push a non-FileList instance into the input.
if (console && console.warn && console.log) {
console.warn(
'Ignoring attempt to assign non-FileList to input[type=file].'
);
console.log('Value:', value);
}
}
}
}
Example #13
Source File: knob.ts From EDA with GNU Affero General Public License v3.0 | 5 votes |
KNOB_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Knob),
multi: true
}
Example #14
Source File: select.component.ts From xBull-Wallet with GNU Affero General Public License v3.0 | 5 votes |
@Component({
selector: 'app-select',
templateUrl: './select.component.html',
styleUrls: ['./select.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectComponent),
multi: true
}
]
})
export class SelectComponent implements OnInit {
@Input() options: ISelectOptions[] = [];
@Input() disabled = false;
@Input() title = 'Input';
@Input() placeholder = 'Select a value...';
@Input() mode: 'dark' | 'light' = 'dark';
@Input() iconPath?: string;
value = '';
onChange: (quantity: any) => void = (quantity) => {};
onTouched: () => void = () => {};
constructor() { }
ngOnInit(): void {
}
onInput(value: any): void {
this.writeValue(value);
this.onTouched();
this.onChange(this.value);
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
writeValue(value: any): void {
if (!!value) {
this.value = value;
} else {
this.value = '';
}
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
Example #15
Source File: account-select.component.ts From digital-bank-ui with Mozilla Public License 2.0 | 5 votes |
@Component({
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AccountSelectComponent), multi: true }],
selector: 'ngx-account-select',
templateUrl: './account-select.component.html',
})
export class AccountSelectComponent implements ControlValueAccessor, OnInit {
formControl: FormControl;
@Input() title: string;
@Input() required: boolean;
@Input() type: AccountType;
accounts: Observable<Account[]>;
_onTouchedCallback: () => void = noop;
private _onChangeCallback: (_: any) => void = noop;
constructor(private accountingService: AccountingService) {}
ngOnInit(): void {
this.formControl = new FormControl('');
this.accounts = this.formControl.valueChanges.pipe(
distinctUntilChanged(),
debounceTime(500),
tap(name => this.changeValue(name)),
filter(name => name),
switchMap(name => this.onSearch(name)),
);
}
changeValue(value: string): void {
this._onChangeCallback(value);
}
writeValue(value: any): void {
this.formControl.setValue(value);
}
registerOnChange(fn: any): void {
this._onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
this._onTouchedCallback = fn;
}
setDisabledState(isDisabled: boolean): void {
if (isDisabled) {
this.formControl.disable();
} else {
this.formControl.enable();
}
}
onSearch(searchTerm?: string): Observable<Account[]> {
const fetchRequest: FetchRequest = {
page: {
pageIndex: 0,
size: 5,
},
searchTerm: searchTerm,
};
return this.accountingService.fetchAccounts(fetchRequest, this.type).pipe(map((accountPage: AccountPage) => accountPage.accounts));
}
}
Example #16
Source File: nas-model.directive.ts From s-libs with MIT License | 5 votes |
constructor(
@Self()
@Inject(NG_VALUE_ACCESSOR)
valueAccessors: ControlValueAccessor[],
) {
this.#valueAccessor = valueAccessors[0];
}
Example #17
Source File: date-picker.ts From sba-angular with MIT License | 5 votes |
DATE_PICKER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => BsDatePicker),
multi: true
}
Example #18
Source File: checkbox.component.ts From taiga-front-next with GNU Affero General Public License v3.0 | 5 votes |
@Component({
selector: 'tg-checkbox',
templateUrl: './checkbox.component.html',
styleUrls: ['./checkbox.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: TgCheckboxComponent,
multi: true,
},
],
})
export class TgCheckboxComponent implements ControlValueAccessor {
constructor(
private renderer: Renderer2
) {}
@ViewChild('checkbox') public checkbox: ElementRef;
@Input() labelPosition: LabelPosition = 'after';
@Input() ariaLabel?: string | null = null;
@Input() id = `tg-checkbox-${nextId++}`;
// tslint:disable-next-line: variable-name
onChange = (_isChecked: boolean) => {};
onTouched = () => {};
public writeValue(isChecked: boolean): void {
this.onChange(isChecked);
}
public registerOnChange(fn: (isDisabled: boolean) => void): void {
this.onChange = fn;
}
public registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
public setDisabledState(isDisabled: boolean): void {
this.renderer.setProperty(this.checkbox.nativeElement, 'disabled', isDisabled);
}
public check = (event: any): void => {
const isChecked: boolean = event.target.checked;
this.writeValue(isChecked);
}
}
Example #19
Source File: input.component.ts From xBull-Wallet with GNU Affero General Public License v3.0 | 5 votes |
@Component({
selector: 'app-input',
templateUrl: './input.component.html',
styleUrls: ['./input.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputComponent),
multi: true
}
]
})
export class InputComponent implements OnInit, ControlValueAccessor {
@Input() mask = '';
@Input() disabled = false;
@Input() title = 'Input';
@Input() type: 'text' | 'number' | 'password' = 'text';
@Input() placeholder = 'Write here...';
@Input() mode: 'dark' | 'light' = 'dark';
@Input() iconPath?: string;
@Output() enter: EventEmitter<InputEvent> = new EventEmitter<InputEvent>();
value = '';
control = new FormControl('');
onChange: (quantity: any) => void = (quantity) => {};
onTouched: () => void = () => {};
ngOnInit(): void {
}
onInput(value: any): void {
this.writeValue(this.control.value);
this.onTouched();
this.onChange(this.control.value);
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
writeValue(value: any): void {
if (!!value) {
this.control.setValue(value);
this.value = value;
} else {
this.value = '';
}
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
onEnter(event: any): void {
this.enter.emit(event);
}
}
Example #20
Source File: range-picker.component.ts From alauda-ui with MIT License | 5 votes |
@Component({
selector: 'aui-range-picker',
templateUrl: './range-picker.template.html',
// provide tooltip class
encapsulation: ViewEncapsulation.Emulated,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RangePickerComponent),
multi: true,
},
],
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./range-picker.style.scss'],
})
export class RangePickerComponent extends CommonFormControl<
ConfigType[],
Dayjs[]
> {
@Input()
clearable = true;
@Input()
clearText: string;
@Input()
format = 'YYYY-MM-DD';
@Input()
showFooter = true;
@Input()
showTime = true;
@Input()
disabledDate: DisabledDateFn = () => false;
@Input()
minDate: Dayjs;
@Input()
maxDate: Dayjs;
@Input()
disabledTime: { left: DisabledTimeFn; right: DisabledTimeFn } = {
left: () => null,
right: () => null,
};
@Input()
weekStartDay = 0;
@Input()
size: ComponentSize;
@Output()
openChange = new EventEmitter<boolean>();
value: [Dayjs, Dayjs];
override valueIn(obj: [ConfigType, ConfigType]) {
return obj?.map(i => dayjs(i));
}
override writeValue(obj: [Dayjs, Dayjs]) {
super.writeValue(obj);
this.value = obj;
this.cdr.markForCheck();
}
clearValue() {
this.value = null;
this.emitValue(null);
}
}
Example #21
Source File: textarea.component.ts From xBull-Wallet with GNU Affero General Public License v3.0 | 5 votes |
@Component({
selector: 'app-textarea',
templateUrl: './textarea.component.html',
styleUrls: ['./textarea.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TextareaComponent),
multi: true
}
]
})
export class TextareaComponent implements OnInit, ControlValueAccessor {
@Input() disabled = false;
@Input() title = 'Textarea';
@Input() placeholder = 'Write here...';
value = '';
onChange: (quantity: any) => void = (quantity) => {};
onTouched: () => void = () => {};
constructor() { }
ngOnInit(): void {
}
onInput(value: any): void {
this.writeValue(value);
this.onTouched();
this.onChange(this.value);
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
writeValue(value: any): void {
if (!!value) {
this.value = value;
} else {
this.value = '';
}
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
Example #22
Source File: rating.component.ts From Angular-Cookbook with MIT License | 5 votes |
@Component({
selector: 'app-rating',
templateUrl: './rating.component.html',
styleUrls: ['./rating.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RatingComponent),
multi: true,
},
],
})
export class RatingComponent implements OnInit, ControlValueAccessor {
value = 2;
hoveredRating = 2;
isMouseOver = false;
@Input() disabled = false;
constructor() {}
onChange: any = () => {};
onTouched: any = () => {};
ngOnInit(): void {}
onRatingMouseEnter(rating: number) {
if (this.disabled) return;
this.hoveredRating = rating;
this.isMouseOver = true;
}
onRatingMouseLeave() {
this.hoveredRating = null;
this.isMouseOver = false;
}
selectRating(rating: number) {
if (this.disabled) return;
this.value = rating;
this.onChange(rating);
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
writeValue(value: number) {
this.value = value;
}
}
Example #23
Source File: checkbox-group.component.ts From alauda-ui with MIT License | 5 votes |
@Component({
selector: 'aui-checkbox-group',
templateUrl: './checkbox-group.component.html',
styleUrls: ['./checkbox-group.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxGroupComponent),
multi: true,
},
],
})
export class CheckboxGroupComponent<T> extends CommonFormControl<T[]> {
private _trackFn: TrackFn<T>;
@Input()
direction: 'row' | 'column' = 'row';
@Input()
get trackFn() {
return this._trackFn;
}
set trackFn(val) {
if (val !== this._trackFn) {
this._trackFn = val;
}
}
@ContentChildren(forwardRef(() => CheckboxComponent), {
descendants: true,
})
checkboxes: QueryList<CheckboxComponent<T>>;
onCheckboxChange(checkbox: CheckboxComponent<T>) {
if (this.onTouched) {
this.onTouched();
}
const values = this.checkboxes
.filter(item => (item === checkbox ? !item.model : item.model))
.map(item => item.label);
this.emitValue(values);
}
onCheckboxBlur() {
if (this.onTouched) {
this.onTouched();
}
}
}
Example #24
Source File: password-input.component.ts From ReCapProject-Frontend with MIT License | 5 votes |
@Component({
selector: 'app-password-input',
templateUrl: './password-input.component.html',
styleUrls: ['./password-input.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => PasswordInputComponent),
multi: true,
},
],
host: {
'(change)': 'onChange($event.target.value)',
'(input)': 'onChange($event.target.value)',
'(blur)': 'onTouched()',
},
})
export class PasswordInputComponent implements OnInit, ControlValueAccessor {
@Input() id: string = 'password-input';
@Input() label: string = 'Enter your password';
@Input() invalidFeedback: string = 'Please enter your password.';
passwordHidden: boolean = true;
value: string = '';
onChange: any = () => {};
onTouched: any = () => {};
disabled = false;
@Input() errors: any;
@Input() touched: any;
@Input() dirty: any;
constructor() {}
ngOnInit(): void {}
writeValue(value: string): void {
this.value = value;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
togglePasswordHidden() {
this.passwordHidden = !this.passwordHidden;
}
isPasswordHidden(): string {
return this.passwordHidden ? 'password' : 'text';
}
isPasswordHiddenIcon(): string {
return this.passwordHidden ? 'fa-eye-slash' : 'fa-eye text-primary';
}
}
Example #25
Source File: validation-message.component.ts From ngx-admin-dotnet-starter with MIT License | 5 votes |
@Component({
selector: 'ngx-validation-message',
styleUrls: ['./validation-message.component.scss'],
template: `
<div class="warning">
<span class="caption status-danger"
*ngIf="showMinLength"> Min {{ label }} length is {{ minLength }} symbols </span>
<span class="caption status-danger"
*ngIf="showMaxLength"> Max {{ label }} length is {{ maxLength }} symbols </span>
<span class="caption status-danger" *ngIf="showPattern"> Incorrect {{ label }} </span>
<span class="caption status-danger" *ngIf="showRequired"> {{ label }} is required</span>
<span class="caption status-danger" *ngIf="showMin">Min value of {{ label }} is {{ min }}</span>
<span class="caption status-danger" *ngIf="showMax">Max value of {{ label }} is {{ max }}</span>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxValidationMessageComponent),
multi: true,
},
],
})
export class NgxValidationMessageComponent {
@Input()
label: string = '';
@Input()
showRequired?: boolean;
@Input()
min?: number;
@Input()
showMin?: boolean;
@Input()
max?: number;
@Input()
showMax: boolean;
@Input()
minLength?: number;
@Input()
showMinLength?: boolean;
@Input()
maxLength?: number;
@Input()
showMaxLength?: boolean;
@Input()
showPattern?: boolean;
}
Example #26
Source File: np-tags.component.ts From np-ui-lib with MIT License | 4 votes |
@Component({
selector: "np-tags",
templateUrl: "./np-tags.component.html",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.Default,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NpTagsComponent),
multi: true,
},
],
})
export class NpTagsComponent
implements ControlValueAccessor, AfterViewInit, AfterContentInit, OnDestroy {
private static controlCount = 1;
@Input() displayKey: string;
@Input() valueKey: string;
@Input() searchResult: BehaviorSubject<any[]>;
@Input() isServerSide: boolean;
@Input() forceToSelect: boolean;
@Input() itemTemplate: TemplateRef<any>;
@Input() searchDelay = 1000;
@Input() maxResultLimit: number;
@Input() minSearchCharLimit: number;
@Input() maxSelectLimit: number;
@Input() orderBy: string;
@Input() orderDir: string;
@Input() placeholder = "";
@Input() readOnly: boolean;
@Input() autoFocus: boolean;
@Input() tabIndex: number;
@Input() styleClass: string;
@Input() inputId: string = `np-tags_${NpTagsComponent.controlCount++}`;
@Output() onChange: EventEmitter<any> = new EventEmitter();
@Output() onSearch: EventEmitter<any> = new EventEmitter();
@Output() onCreateNewTag: EventEmitter<any> = new EventEmitter();
@Output() onFocus: EventEmitter<any> = new EventEmitter();
@Output() onBlur: EventEmitter<any> = new EventEmitter();
@ViewChild("templatePortalContent") templatePortalContent: TemplateRef<any>;
@ViewChild("control") inputViewChild: ElementRef;
selected: any[];
subscription: Subscription;
options: any[];
displayValue: string;
searchTimeout: any;
isLoading: boolean = false;
innerValue: any[];
isDisabled: boolean = false;
focused: boolean = false;
private templatePortal: TemplatePortal<any>;
private overlayRef: OverlayRef;
private onChangeCallback: (_: any) => void = () => { };
private onTouchedCallback: () => void = () => { };
constructor(
public overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private overlayPositionBuilder: OverlayPositionBuilder,
private elementRef: ElementRef,
private utility: NpUtilityService
) { }
ngAfterContentInit(): void {
this.subscription = this.searchResult.subscribe((data) => {
if (
this.maxResultLimit &&
this.maxResultLimit > 0 &&
data &&
data.length > this.maxResultLimit
) {
this.options = data.splice(0, this.maxResultLimit);
} else {
this.options = data;
}
if (this.isServerSide) {
this.isLoading = false;
if (data) {
if (!this.overlayRef.hasAttached()) {
this.overlayRef.attach(this.templatePortal);
}
}
}
});
}
ngAfterViewInit(): void {
const positionStrategy = this.overlayPositionBuilder
.flexibleConnectedTo(this.elementRef)
.withPositions(TopBottomOverlayPositions);
this.overlayRef = this.overlay.create({
positionStrategy,
hasBackdrop: true,
backdropClass: "np-tags-backdrop",
scrollStrategy: this.overlay.scrollStrategies.reposition(),
panelClass: this.styleClass,
});
this.templatePortal = new TemplatePortal(
this.templatePortalContent,
this.viewContainerRef
);
this.overlayRef.backdropClick().subscribe(() => this._close());
}
ngOnDestroy(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
get value(): any[] {
return this.innerValue ? this.innerValue : null;
}
set value(v: any[]) {
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
this.onChange.emit(v);
}
}
writeValue(v: any): void {
if (v !== this.innerValue) {
this.innerValue = v;
this.selected = Object.assign([], v);
}
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
this.onTouchedCallback = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}
focus(): void {
this.inputViewChild.nativeElement.focus();
}
_close(): void {
this.displayValue = null;
this.overlayRef.detach();
this.inputViewChild.nativeElement.focus();
}
_onInput($event: any): void {
if (!$event.target.value) {
return;
}
this.displayValue = $event.target.value.trim();
if (this.isDisabled || this.readOnly || !this.isServerSide) {
return;
}
if (this.minSearchCharLimit && this.minSearchCharLimit > 0) {
if (
this.displayValue === undefined ||
this.displayValue === null ||
this.displayValue.length < this.minSearchCharLimit
) {
return;
}
}
this.isLoading = true;
if (this.searchTimeout) {
clearTimeout(this.searchTimeout);
}
const searchKeyword = this.displayValue;
this.searchTimeout = setTimeout(() => {
this.onSearch.emit(searchKeyword);
}, this.searchDelay);
}
_selectValue(val: any): void {
if (this._isSelected(val)) {
this._removeTag(val);
return;
}
if (
this.maxSelectLimit > 0 &&
this.value &&
this.value.length === this.maxSelectLimit
) {
return;
}
const currentVal = this.valueKey ? val[this.valueKey] : val;
if (!this.value) {
this.value = [currentVal];
this.selected = [val];
} else {
this.value.push(currentVal);
this.selected.push(val);
this.onChangeCallback(this.value);
this.onChange.emit(this.value);
}
}
_open(): void {
if (this.isServerSide || this.isDisabled || this.readOnly) {
return;
}
if (!this.overlayRef.hasAttached()) {
this.overlayRef.attach(this.templatePortal);
}
}
_createNewTag(): void {
if (
this.maxSelectLimit > 0 &&
this.value &&
this.value.length === this.maxSelectLimit
) {
return;
}
if (this.options === undefined || this.options === null) {
this.options = [];
}
let newObj: any;
if (this.displayKey) {
newObj = {};
newObj[this.displayKey] = this.displayValue;
if (this.valueKey) {
newObj[this.valueKey] = this.displayValue;
}
} else {
newObj = this.displayValue;
}
this.options.push(newObj);
this._selectValue(newObj);
this.onCreateNewTag.emit(newObj);
this.displayValue = null;
}
_getValueFromTag(val: any): void {
return this.displayKey ? val[this.displayKey] : val;
}
_removeTag(tag: any): void {
const idx = this.selected.findIndex((element) => this.utility.isEqual(element, tag));
if (idx > -1) {
if (this.value.length === 1) {
this.value = null;
this.selected = null;
} else {
this.value.splice(idx, 1);
this.selected.splice(idx, 1);
this.onChangeCallback(this.value);
this.onChange.emit(this.value);
}
}
}
_isSelected(tag: any): boolean {
return this.selected && (this.selected.findIndex((element) => this.utility.isEqual(element, tag))) > -1;
}
_onKeydown(event: KeyboardEvent): void {
if (event.key === "Tab" || event.key === "Escape") {
this._close();
}
if (event.key === "ArrowDown") {
this._open();
event.preventDefault();
}
if (
event.key === "Backspace" &&
this.value &&
this.value.length > 0 &&
(this.displayValue === undefined ||
this.displayValue === null ||
this.displayValue.length === 0)
) {
if (this.value.length > 1) {
this.value.pop();
this.selected.pop();
this.onChangeCallback(this.value);
this.onChange.emit(this.value);
} else {
this.value = null;
this.selected = null;
}
}
if (
event.key === "Enter" &&
!this.forceToSelect &&
this.displayValue &&
this.displayValue.length > 0
) {
this._createNewTag();
}
}
_trackBy(index: number): number {
return index;
}
_getDisplayValue(): string {
return this.displayValue || "";
}
_onBlur($event: any): void {
this.focused = false;
this.onTouchedCallback();
this.onBlur.emit($event);
}
_onFocus($event: any): void {
this.focused = true;
this.onFocus.emit($event);
}
}
Example #27
Source File: component.ts From alauda-ui with MIT License | 4 votes |
@Component({
selector: 'aui-date-picker-panel',
templateUrl: './template.html',
styleUrls: ['./style.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerPanelComponent),
multi: true,
},
],
})
export class DatePickerPanelComponent extends CommonFormControl<Dayjs> {
@Input()
clearable = true;
@Input()
clearText: string;
@Input()
set type(type: DatePickerType) {
this.navRange = getNavRangeByType(type);
this._type = type;
}
get type() {
return this._type;
}
private _type: DatePickerType;
@Input()
showTime = false;
@Input()
disabledDate: (date: Dayjs, type: DateNavRange) => boolean = () => false;
@Input()
disabledTime: DisabledTimeFn = () => null;
@Input()
weekStartDay = 0;
@Input()
showFooter = true;
@Input()
footerTemplate: TemplateRef<unknown>;
@Input()
extraFooter: TemplateRef<unknown>;
@Input()
minDate: Dayjs;
@Input()
maxDate: Dayjs;
@Output()
confirm = new EventEmitter<Dayjs>();
@Output()
clear = new EventEmitter<void>();
private _cacheSelectedDate: Dayjs;
private _cacheDisabledTimeFn: ReturnType<DisabledTimeFn>;
getDisabledTimeFn(
selectedDate: Dayjs,
type: keyof ReturnType<DisabledTimeFn>,
) {
if (selectedDate !== this._cacheSelectedDate) {
this._cacheDisabledTimeFn = this.disabledTime(selectedDate);
this._cacheSelectedDate = selectedDate;
}
return this._cacheDisabledTimeFn?.[type];
}
navRange: DateNavRange;
get currentNavType() {
return getTypeByNavRange(this.navRange);
}
anchor: Dayjs;
selectedDate: Dayjs;
selectedTime: TimePickerModel;
DateNavRange = DateNavRange;
DatePickerType = DatePickerType;
override writeValue(obj: Dayjs) {
super.writeValue(obj);
this.selectedDate = obj;
this.selectedTime = getTimePickerModel(obj);
this.anchor = obj || dayjs();
this.cdr.markForCheck();
}
panelValueChange(value: Dayjs) {
this.selectedDate = updateDate(
this.selectedDate || dayjs(),
value,
this.currentNavType,
);
this.anchor = this.selectedDate;
this.selectedDate = updateDateByTimeModel(
this.selectedDate,
this.selectedTime,
);
if (this.type === this.currentNavType) {
this.confirmValue(this.selectedDate, !this.showTime);
}
const nextNavRange = nextNavRangeType(
this.navRange,
getNavRangeByType(this.type),
);
if (this.navRange !== nextNavRange) {
this.navRange = nextNavRange;
}
}
confirmValue(value?: ConfigType, closeAfterConfirm = true) {
this.emitValue(value ? dayjs(value) : this.selectedDate);
closeAfterConfirm && this.confirm.next(null);
}
timeDateChange(time: TimePickerModel) {
if (!this.selectedDate) {
return;
}
this.selectedDate = updateDateByTimeModel(this.selectedDate, time);
this.emitValue(this.selectedDate);
}
setToday() {
this.confirmValue(dayjs(), true);
}
}
Example #28
Source File: np-switch.component.ts From np-ui-lib with MIT License | 4 votes |
@Component({
selector: "np-switch",
templateUrl: "./np-switch.component.html",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.Default,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NpSwitchComponent),
multi: true,
},
],
})
export class NpSwitchComponent implements ControlValueAccessor {
private static controlCount = 1;
@Input() trueLabelText: string;
@Input() falseLabelText: string;
@Input() readOnly: boolean;
@Input() autoFocus: boolean;
@Input() tabIndex: number;
@Input() styleClass: string;
@Input() inputId: string = `np-switch_${NpSwitchComponent.controlCount++}`;
@Output() onChange: EventEmitter<any> = new EventEmitter();
@Output() onFocus: EventEmitter<any> = new EventEmitter();
@Output() onBlur: EventEmitter<any> = new EventEmitter();
@ViewChild("control") inputViewChild: ElementRef;
innerValue: boolean;
isDisabled: boolean = false;
focused: boolean = false;
private onChangeCallback: (_: any) => void = () => { };
private onTouchedCallback: () => void = () => { };
get value(): boolean {
return this.innerValue;
}
set value(v: boolean) {
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
this.onChange.emit(v);
}
}
writeValue(v: boolean): void {
if (v !== this.innerValue) {
this.innerValue = v;
}
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
this.onTouchedCallback = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}
focus(): void {
this.inputViewChild.nativeElement.focus();
}
_onClickSwitch($event: any): void {
if (this.isDisabled || this.readOnly) {
return;
}
this.value = $event.target.checked;
}
_onBlur($event: any): void {
this.focused = false;
this.onTouchedCallback();
this.onBlur.emit($event);
}
_onFocus($event: any): void {
this.focused = true;
this.onFocus.emit($event);
}
_getInputId(): string {
return this.inputId + "_input";
}
}
Example #29
Source File: component.ts From alauda-ui with MIT License | 4 votes |
@Component({
selector: 'aui-date-range-picker-panel',
templateUrl: './template.html',
styleUrls: ['./style.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DateRangePickerPanelComponent),
multi: true,
},
],
})
export class DateRangePickerPanelComponent extends CommonFormControl<Dayjs[]> {
@Input()
clearable = true;
@Input()
clearText: string;
@Input()
showTime = true;
@Input()
showFooter = true;
@Input()
disabledDate: (date: Dayjs, navRange: DateNavRange) => boolean = () => false;
@Input()
disabledTime: { left: DisabledTimeFn; right: DisabledTimeFn } = {
left: () => null,
right: () => null,
};
@Input()
weekStartDay = 0;
@Input()
minDate: Dayjs;
@Input()
maxDate: Dayjs;
@Output()
clear = new EventEmitter<void>();
@Output()
confirm = new EventEmitter<void>();
bem = bem;
Side = Side;
DatePickerType = DatePickerType;
leftDateRange = DateNavRange.Month;
rightDateRange = DateNavRange.Month;
FOOTER_DATE_FORMAT = 'YYYY-MM-dd';
leftAnchor = dayjs();
rightAnchor = dayjs().add(1, MONTH);
get maxHeaderAvail() {
return minDate(this.rightAnchor, this.maxDate);
}
get minHeaderAvail() {
return maxDate(this.minDate, this.leftAnchor);
}
// 用于存放 range data 序列,数量为 2 时清除
rangeValue: Dayjs[] = [];
// 用于组装匹配日期序列
matchValues: Dayjs[];
startTime: TimePickerModel;
endTime: TimePickerModel;
override writeValue(obj: Dayjs[]) {
super.writeValue(obj);
this.rangeValue = obj || [];
this.matchValues = [...this.rangeValue];
this.startTime = getTimePickerModel(obj?.[0]);
this.endTime = getTimePickerModel(obj?.[1]);
if (obj?.length === 2) {
this.reorder(sortDates(obj));
}
this.cdr.markForCheck();
}
calendarRangeChange(type: DateNavRange, side: Side) {
if (side === Side.Left) {
this.leftDateRange = type;
} else {
this.rightDateRange = type;
}
}
// range 组件范围受控
getDateDisabledFn(side: Side, constrainValue: Dayjs) {
return composeDisabledDateFn((date: Dayjs, navRange: DateNavRange) => {
if (navRange === DateNavRange.Month) {
return false;
}
if (navRange === DateNavRange.Decade) {
return date[side === Side.Left ? 'isAfter' : 'isBefore'](
constrainValue,
YEAR,
);
}
return !date[side === Side.Left ? 'isBefore' : 'isAfter'](
constrainValue,
MONTH,
);
}, this.disabledDate);
}
private getDisabledTimeCachedFn(side: Side) {
let cacheSelectedDate: Dayjs;
let cacheDisabledTimeFn: ReturnType<DisabledTimeFn>;
return (value: Dayjs, key: keyof ReturnType<DisabledTimeFn>) => {
if (value !== cacheSelectedDate) {
cacheDisabledTimeFn = (this.disabledTime?.[side] || (() => null))(
value,
);
cacheSelectedDate = value;
}
return cacheDisabledTimeFn?.[key];
};
}
leftDisabledTimeFn = this.getDisabledTimeCachedFn(Side.Left);
rightDisabledTimeFn = this.getDisabledTimeCachedFn(Side.Right);
selectPickerPanel(value: Dayjs, side: Side) {
const navRange =
side === Side.Left ? this.leftDateRange : this.rightDateRange;
const type = getTypeByNavRange(navRange);
const dateValue = updateDate(
side === Side.Left ? this.leftAnchor : this.rightAnchor,
value,
type,
);
const nextRange = nextNavRangeType(navRange, DateNavRange.Month);
if (side === Side.Left) {
this.leftAnchor = dateValue;
this.leftDateRange = nextRange;
} else {
this.rightAnchor = dateValue;
this.rightDateRange = nextRange;
}
if (navRange !== DateNavRange.Month) {
return;
}
if (this.leftAnchor.isSame(this.rightAnchor, MONTH)) {
this.rightAnchor = this.rightAnchor.add(1, MONTH);
}
this.rangeValue =
this.rangeValue.length === 2
? [dateValue]
: sortDates([...this.rangeValue, dateValue]);
this.matchValues = [...this.rangeValue];
this.syncTime();
if (this.rangeValue.length === 2) {
this.reorder(this.rangeValue);
this.confirmValue(this.rangeValue, !this.showTime);
}
}
reorder(sortedDate: Dayjs[]) {
if (!sortedDate[0].isSame(sortedDate[1], MONTH)) {
this.leftAnchor = updateDate(
this.leftAnchor,
sortedDate[0],
DatePickerType.Day,
);
this.rightAnchor = updateDate(
this.leftAnchor,
sortedDate[1],
DatePickerType.Day,
);
}
}
hoverItem(date: Dayjs) {
if (this.rangeValue.length === 1) {
this.matchValues[1] = date;
}
}
confirmValue(value: Dayjs[], closeThen = true) {
this.emitValue(value);
closeThen && this.confirm.next();
}
timeChange(time: TimePickerModel) {
if (!time) {
return;
}
this.syncTime();
if (!this.rangeValue?.length) {
const date = updateDateByTimeModel(dayjs(), time);
this.rangeValue = [date, date];
this.matchValues = [...this.rangeValue];
this.startTime = this.endTime = time;
}
this.emitValue(this.rangeValue);
}
syncTime() {
if (this.showTime && !!this.rangeValue?.length) {
const startDate = this.rangeValue[0]
? updateDateByTimeModel(this.rangeValue[0], this.startTime)
: null;
const endDate = this.rangeValue[1]
? updateDateByTimeModel(this.rangeValue[1], this.endTime)
: null;
if (!this.startTime && startDate) {
this.startTime = getTimePickerModel(this.rangeValue[0]);
}
if (!this.endTime && endDate) {
this.endTime = getTimePickerModel(this.rangeValue[1]);
}
this.rangeValue = [startDate, endDate].filter(i => !!i);
}
}
}