Why does the form input value is inconsistent when disabled?

133 views Asked by At

I am currently working on an Angular input component in StorybookJS. The problem that I am facing is that when I type a value (e.g., hello) in the control panel in storybook js and click disabled to true, the input text gets disabled displaying the text "hello" and the text remains disabled as expected and returns to normal when disabled is false. And this is the correct behavior.

But, when I am actually typing in the input itself (e.g., hello11) and repeat the similar steps, when I click disabled to true, the value in the input will be changed and seen as "hello" instead of "hello11". So there is some inconsistency in the output of value when actually typing a value in the text input itself and disabling it.

Here is what I have:

In input-test.component.html:

<input 
  type="text"
  [(ngModel)]="value"
  [disabled]="disabled"
  (input)="updateValue($event)"
/>

In input-test.component.ts:

import { Component, Input, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-input-test',
  templateUrl: './input-test.component.html',
  styleUrls: ['./input-test.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => InputTestComponent),
      multi: true,
    },
  ],
})
export class InputTestComponent implements ControlValueAccessor  {
  @Input() value: string = '';
  @Input() disabled: boolean = false;
  /**
   * @ignore
   */
  onChange: any = () => {};
  /**
   * @ignore
   */
  onTouch: any = () => {};

  writeValue(value: any): void {
    this.value = value;
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }
  updateValue(event: Event): void {
    const newValue = (event.target as HTMLInputElement).value;
    this.value = newValue;
    this.onChange(this.value);
    this.onTouch(this.value);
  }
}

In InputTest.stories.ts:

import { FormsModule, ReactiveFormsModule, FormBuilder } from '@angular/forms';
import { InputTestComponent } from 'src/app/input-test/input-test.component';
import { Meta, StoryObj } from '@storybook/angular';
import { moduleMetadata } from '@storybook/angular';

const meta: Meta<InputTestComponent> = {
  component: InputTestComponent,
  title: 'Basic Components/InputTestComponent',
  tags: ['autodocs'],
  decorators: [
    moduleMetadata({
      declarations: [InputTestComponent],
      imports: [FormsModule, ReactiveFormsModule],
    }),
  ],
  args: {},
  render: (args: InputTestComponent) => ({
    props: {
      ...args,
    },
  }),
  argTypes: {},
};
export default meta;

type Story = StoryObj<InputTestComponent>;

const createFormGroup = (value: string, disabled: boolean) => {
  const fb = new FormBuilder();
  return fb.group({
    name: [{value: value, disabled: disabled}],
  });
};

export const Default: Story = {
  args: {
    value: 'default',
    disabled: false,
  },
  render: (args) => ({
    props: {
      ...args,
      form: createFormGroup(args.value, args.disabled),
    },
    template: `
        <form [formGroup]="form">
          <app-input-test formControlName="name" [(ngModel)]="value" [disabled]="disabled"></app-input-test>  
        </form>
        <div>Name: {{ form.get('name').value }}</div>
      `,
  }),
};

Can someone help me with this? Thank you!

1

There are 1 answers

0
Eliseo On
  1. value is NOT an @Input else a simple variable.
  2. You needn't change the variable this.value in your function updateValue
  3. disabledis NOT an @Input
  4. You need implements the method [setDisabledState]