From 1ac4207bcc8ba012136163bc6db754c4d4bba43f Mon Sep 17 00:00:00 2001 From: Nikita Barsukov Date: Fri, 27 Sep 2024 17:00:00 +0300 Subject: [PATCH 1/2] fix(core): `Textfield` has change detection problems for `[filler]` --- .../textfield/textfield.component.ts | 41 +++++++++++-------- .../textfield/textfield.directive.ts | 7 ++++ .../textfield/textfield.template.html | 4 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/projects/core/components/textfield/textfield.component.ts b/projects/core/components/textfield/textfield.component.ts index 890242bf6404..fbee0b568338 100644 --- a/projects/core/components/textfield/textfield.component.ts +++ b/projects/core/components/textfield/textfield.component.ts @@ -8,6 +8,7 @@ import { forwardRef, inject, Input, + signal, ViewChild, ViewContainerRef, ViewEncapsulation, @@ -65,6 +66,8 @@ import {TuiWithTextfieldDropdown} from './textfield-dropdown.directive'; }, }) export class TuiTextfieldComponent implements TuiDataListHost { + // TODO: refactor to signal inputs after Angular update + private readonly filler = signal(''); private readonly autoId = tuiInjectId(); private readonly el = tuiInjectElement(); private readonly open = tuiDropdownOpen(); @@ -81,6 +84,21 @@ export class TuiTextfieldComponent implements TuiDataListHost { protected readonly icons = inject(TUI_COMMON_ICONS); + protected computedFiller = computed(() => { + const value = this.directive?.nativeValue() || ''; + const filledValue = value + this.filler().slice(value.length); + + return filledValue.length > value.length ? filledValue : ''; + }); + + protected showFiller = computed(() => + Boolean( + this.focused() && + this.computedFiller() && + (this.directive?.nativeValue() || !this.input?.nativeElement.placeholder), + ), + ); + @ViewChild('vcr', {read: ViewContainerRef, static: true}) public readonly vcr?: ViewContainerRef; @@ -90,9 +108,6 @@ export class TuiTextfieldComponent implements TuiDataListHost { }) public readonly input?: ElementRef; - @Input() - public filler = ''; - @Input() public stringify: TuiStringHandler = String; @@ -102,6 +117,11 @@ export class TuiTextfieldComponent implements TuiDataListHost { public readonly focused = computed(() => this.open() || this.focusedIn()); public readonly options = inject(TUI_TEXTFIELD_OPTIONS); + @Input('filler') + public set fillerSetter(filler: string) { + this.filler.set(filler); + } + public get id(): string { return this.input?.nativeElement.id || this.autoId; } @@ -115,21 +135,6 @@ export class TuiTextfieldComponent implements TuiDataListHost { this.open.set(false); } - protected get computedFiller(): string { - const value = this.input?.nativeElement.value || ''; - const filler = value + this.filler.slice(value.length); - - return filler.length > value.length ? filler : ''; - } - - protected get showFiller(): boolean { - return ( - this.focused() && - !!this.computedFiller && - (!!this.input?.nativeElement.value || !this.input?.nativeElement.placeholder) - ); - } - protected get hasLabel(): boolean { return Boolean(this.label?.nativeElement?.childNodes.length); } diff --git a/projects/core/components/textfield/textfield.directive.ts b/projects/core/components/textfield/textfield.directive.ts index aca8aeaf038b..175b0ffc72ee 100644 --- a/projects/core/components/textfield/textfield.directive.ts +++ b/projects/core/components/textfield/textfield.directive.ts @@ -1,4 +1,5 @@ import {computed, Directive, inject, Input, type OnChanges, signal} from '@angular/core'; +import {toSignal} from '@angular/core/rxjs-interop'; import {TuiNativeValidator} from '@taiga-ui/cdk/directives/native-validator'; import {tuiInjectElement} from '@taiga-ui/cdk/utils/dom'; import { @@ -9,6 +10,7 @@ import { tuiAppearanceState, } from '@taiga-ui/core/directives/appearance'; import type {TuiInteractiveState} from '@taiga-ui/core/types'; +import {fromEvent} from 'rxjs'; import {TuiTextfieldComponent} from './textfield.component'; import {TUI_TEXTFIELD_OPTIONS} from './textfield.options'; @@ -35,6 +37,11 @@ export class TuiTextfieldBase implements OnChanges { @Input() public invalid: boolean | null = null; + public nativeValue = toSignal( + fromEvent(this.el, 'input', () => this.el.value), + {initialValue: this.el.value}, + ); + @Input('focused') public set focusedSetter(focused: boolean | null) { this.focused.set(focused); diff --git a/projects/core/components/textfield/textfield.template.html b/projects/core/components/textfield/textfield.template.html index 4ba5580fe24d..aba2f6b964ca 100644 --- a/projects/core/components/textfield/textfield.template.html +++ b/projects/core/components/textfield/textfield.template.html @@ -28,9 +28,9 @@ From 82e523cfa858a116df0c87835714ed7a1c41bccf Mon Sep 17 00:00:00 2001 From: Nikita Barsukov Date: Mon, 30 Sep 2024 12:25:19 +0300 Subject: [PATCH 2/2] refactor: code review fix --- .../core/components/textfield/textfield.component.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/projects/core/components/textfield/textfield.component.ts b/projects/core/components/textfield/textfield.component.ts index fbee0b568338..ba624786e2a8 100644 --- a/projects/core/components/textfield/textfield.component.ts +++ b/projects/core/components/textfield/textfield.component.ts @@ -91,12 +91,11 @@ export class TuiTextfieldComponent implements TuiDataListHost { return filledValue.length > value.length ? filledValue : ''; }); - protected showFiller = computed(() => - Boolean( + protected showFiller = computed( + () => this.focused() && - this.computedFiller() && - (this.directive?.nativeValue() || !this.input?.nativeElement.placeholder), - ), + !!this.computedFiller() && + (!!this.directive?.nativeValue() || !this.input?.nativeElement.placeholder), ); @ViewChild('vcr', {read: ViewContainerRef, static: true})