klenium
klenium

Reputation: 2607

Reset button erases sub-component input's value

I separated a special input-row, since it is often used, so it's better to create a new component to handle all of its stuff separately. The problem is that when I press on a reset button, the text input's value that is located inside the new component isn't changed back to its original value, it's just removed. I guess it's because the input's value is dynamically wired to the component's input parameter, and the actual input field doesn't have value="constant text" attribute.

The page's HTML:

<form>
    <h3 class="form-group-caption"
        >Mappaútvonalak
        <input type="reset" class="ml-3 btn btn-light" value="Visszaállítás" />
    </h3>
    <app-stateful-text-input
        label="FRM"
        inputValue="A:\Temp"
        inputType="text"
        apiPath="/api/frm"
    ></app-stateful-text-input>

The component's HTML contains some wrapper elements, and:

<input
    type="{{inputType}}"
    class="form-control form-control-lg"
    id="input-{{label}}"
    value="{{inputValue}}"
    (keypress)='onInputChanged($event)'
/>

For one input, I could write a resetInputs() method, and call it when the reset button is pressed. However, there're a lot of instances of this new component, in multiple pages, anywhere inside forms. If I'd need to maintain references to all of them, just to be able call a method in that sub-component, I'd lose the key point of separating them.

Is there any simple solution to this situation?

Upvotes: 0

Views: 363

Answers (2)

klenium
klenium

Reputation: 2607

I could make this automatic by adding a reset event listener to the container <form>, at that time I overwrite the value attribute with the stored one.

However, it's still ugly, this requires additional JS. I'd love a "native solution" where the reset button could do what it wants to.

export class StatefulInputComponent implements OnInit {
    @Input() inputValue: string;
    @ViewChild('inputField', {static: true}) inputField: ElementRef;
    defaultValue: string;
    ngOnInit() {
        this.defaultValue = this.inputValue;
        let element = this.inputField.nativeElement as HTMLElement;
        do {
            element = element.parentElement;
        } while (element != null && element.tagName !== 'FORM');
        if (element == null) {
            throw new Error('<app-stateful-input> must be placed inside a <form>!');
        }
        const form = element as HTMLFormElement;
        form.addEventListener('reset', (event: Event) => {
            const input = this.inputField.nativeElement as HTMLInputElement;
            input.value = this.defaultValue;
            event.preventDefault();
        });
    }
}

Upvotes: 0

Benjamin O. P.
Benjamin O. P.

Reputation: 106

You could set a default value in the Input component and use it with a resetInputs() method, as you suggest, in the parent component.

<app-stateful-text-input
        label="FRM"
        defaultValue="A:\Temp"
        inputType="text"
        apiPath="/api/frm"
    ></app-stateful-text-input>


@Component({
  selector: 'app-stateful-text-input',
  template: `...`
})
export class StatefulTextInputComponent implements OnInit {
  @Input() 
  public defaultValue: string;

  public inputValue: string;

  public ngOnInit(): void {
      this.inputValue = this.defaultValue;
  }
}

In your parent component you can iterate in all the children custom input and set the old value when resetting.


@Component({
  selector: 'app-form-component',
  template: `...`
})
class FormComponent {
  @ViewChildren(StatefulTextInputComponent) statefulTextInputs: QueryList<StatefulTextInputComponent>;
  ...

  public resetInputs(): void {
     this.statefulTextInputs.forEach((item: StatefulTextInputComponent) => item.inputValue = item.defaultValue);
  }

  ...
}

Upvotes: 1

Related Questions