Skip to content

Commit

Permalink
fix(core): Textfield with initial value has change detection proble…
Browse files Browse the repository at this point in the history
…ms with `filler` (#9375)
  • Loading branch information
nsbarsukov authored Oct 8, 2024
1 parent b20f6bf commit 8217c90
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 6 deletions.
6 changes: 2 additions & 4 deletions projects/core/components/textfield/select.directive.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {CommonModule} from '@angular/common';
import {ChangeDetectionStrategy, Component, inject, Input} from '@angular/core';
import {NgControl} from '@angular/forms';
import {WA_NAVIGATOR} from '@ng-web-apis/common';
import {TuiNativeValidator} from '@taiga-ui/cdk/directives/native-validator';
import {tuiProvide} from '@taiga-ui/cdk/utils/miscellaneous';
Expand Down Expand Up @@ -34,13 +33,12 @@ import {TuiTextfieldBase, TuiTextfieldDirective} from './textfield.directive';
})
export class TuiSelect<T> extends TuiTextfieldBase<T> {
private readonly nav = inject(WA_NAVIGATOR);
private readonly control = inject(NgControl);

@Input()
public placeholder = '';

public override setValue(value: T): void {
this.control.control?.setValue(value);
this.control?.control?.setValue(value);
this.el.dispatchEvent(new Event('input', {bubbles: true}));
}

Expand All @@ -51,7 +49,7 @@ export class TuiSelect<T> extends TuiTextfieldBase<T> {
}

protected get value(): string {
return this.textfield.stringify(this.control.value ?? '');
return this.textfield.stringify(this.control?.value ?? '');
}

protected async onCopy(): Promise<void> {
Expand Down
11 changes: 9 additions & 2 deletions projects/core/components/textfield/textfield.directive.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type {OnChanges} from '@angular/core';
import {computed, Directive, inject, Input, signal} from '@angular/core';
import {toSignal} from '@angular/core/rxjs-interop';
import {NgControl} from '@angular/forms';
import {TuiNativeValidator} from '@taiga-ui/cdk/directives/native-validator';
import {tuiControlValue} from '@taiga-ui/cdk/observables';
import {tuiInjectElement} from '@taiga-ui/cdk/utils/dom';
import {
TuiAppearance,
Expand All @@ -11,7 +13,7 @@ import {
tuiAppearanceState,
} from '@taiga-ui/core/directives/appearance';
import type {TuiInteractiveState} from '@taiga-ui/core/types';
import {fromEvent} from 'rxjs';
import {fromEvent, map, merge, switchMap, timer} from 'rxjs';

import {TuiTextfieldComponent} from './textfield.component';
import {TUI_TEXTFIELD_OPTIONS} from './textfield.options';
Expand All @@ -21,6 +23,7 @@ export class TuiTextfieldBase<T> implements OnChanges {
// TODO: refactor to signal inputs after Angular update
private readonly focused = signal<boolean | null>(null);

protected readonly control = inject(NgControl, {optional: true});
protected readonly a = tuiAppearance(inject(TUI_TEXTFIELD_OPTIONS).appearance);
protected readonly s = tuiAppearanceState(null);
protected readonly m = tuiAppearanceMode(this.mode);
Expand All @@ -39,7 +42,11 @@ export class TuiTextfieldBase<T> implements OnChanges {
public invalid: boolean | null = null;

public nativeValue = toSignal(
fromEvent(this.el, 'input', () => this.el.value),
merge(
fromEvent(this.el, 'input'),
timer(0) // https://github.com/angular/angular/issues/54418
.pipe(switchMap(() => tuiControlValue(this.control))),
).pipe(map(() => this.el.value)),
{initialValue: this.el.value},
);

Expand Down
73 changes: 73 additions & 0 deletions projects/demo-cypress/src/tests/textfield.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {TUI_ANIMATIONS_SPEED, TuiRoot, TuiTextfield} from '@taiga-ui/core';

@Component({
standalone: true,
imports: [FormsModule, TuiRoot, TuiTextfield],
template: `
<tui-root>
<tui-textfield [filler]="filler">
<input
tuiTextfield
[(ngModel)]="initialValue"
/>
</tui-textfield>
</tui-root>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [{provide: TUI_ANIMATIONS_SPEED, useValue: 0}],
})
export class TestTextfield {
@Input()
public initialValue = '';

@Input()
public filler = '';
}

describe('Textfield', () => {
describe('[filler] property', () => {
beforeEach(() => cy.viewport(200, 150));

describe('with initial value', () => {
['2', '23', '23:', '23:5', '23:59'].forEach((initialValue) => {
it(initialValue, () => {
cy.mount(TestTextfield, {
componentProperties: {
initialValue,
filler: 'HH:MM',
},
});

cy.get('input[tuiTextfield]').focus();
cy.get('tui-textfield').compareSnapshot(
`[filler]-initial-value_${initialValue}`,
);
});
});
});

describe('user types new value', () => {
beforeEach(() => {
cy.mount(TestTextfield, {
componentProperties: {
filler: 'HH:MM',
},
});

cy.get('input[tuiTextfield]').focus();
});

['2', '23', '23:', '23:5', '23:59'].forEach((value) => {
it(value, () => {
cy.get('input[tuiTextfield]').type(value);

cy.get('tui-textfield').compareSnapshot(
`[filler]-user-types_${value}`,
);
});
});
});
});
});

0 comments on commit 8217c90

Please sign in to comment.