Angular binding seems broken on HTML <input> element's 'value' property, how to fix/workaround...

Discussão em 'Angular' iniciado por user2771324, Fevereiro 4, 2025.

  1. user2771324

    user2771324 Guest

    It seems that angular refuses to update <input>.value if it is same as the previous bound value.
    How to workaround this problem?

    The example below can run on https://angular.dev/playground.
    The example is meant to post-processes <input> value:

    • Removes trailing slash on Enter;
    • Restores previous value on Esc;

    However, it doesn't work in angular:

    1. Let initial value be abc;
    2. Type abc/// and Enter, input value is not updated to abc;
    3. Type zzz and Esc, input value is not restored to abc;

    import {Component, computed, signal} from '@angular/core';
    import {bootstrapApplication} from '@angular/platform-browser';

    @Component({
    selector: 'myinput',
    template: `
    @let d = currentData();
    <div style="display: flex;">
    <pre>state: </pre>
    <pre>{{ d.state }}</pre>
    </div>
    <input #el type="text" value="{{d.value}}" [attr.v]="d.value" (keyup)="keypress($event)" (blur)="blur(el)">
    `,
    })
    export class MyInput {
    refresh = signal<void>(undefined, { equal: () => false });
    data = { state: 'init', value: 'init' };
    console = globalThis.console;

    currentData = computed(() => {
    this.refresh();
    return this.data;
    });
    keypress(kev: KeyboardEvent) {
    const elem = kev.target! as HTMLInputElement;
    if (kev.key === 'Escape') {
    return this.cancel(elem);
    } else if (kev.key === 'Enter') {
    this.data = { state: 'change', value: elem.value.split('/')[0] };
    } else return;
    console.log(`change:`, this.data);
    this.update();
    }
    cancel(elem: HTMLInputElement) {
    this.data = { state: 'cancel', value: this.data.value };
    console.log(`cancel:`, this.data);
    this.update();
    }
    blur(elem: HTMLInputElement) { /* return this.cancel(elem); */ }
    update() {
    let defer = false;
    // elem.blur();
    if (defer) {
    setTimeout(() => this.refresh.set(undefined), 0);
    } else {
    this.refresh.set(undefined);
    }
    }
    }

    @Component({
    selector: 'app-root',
    imports: [ MyInput ],
    template: `
    <myinput />
    `,
    })
    export class PlaygroundComponent {}

    bootstrapApplication(PlaygroundComponent);

    Continue reading...

Compartilhe esta Página