Skip to content

Cancelable text input

Karsten Schmidt edited this page Apr 18, 2018 · 3 revisions

(See general info in cookbook intro)

This higher-order textfield component sources its value from a preconfigured app state view and triggers an event to store value changes. Each time the input element is being focused we record the current value, which is then being restored if the user types Esc and thereby cancels any edits made. Pressing Enter triggers element.blur().

export function cancelableInput(ctx: AppContext, view: IView<string | number>, eventID: string) {
    let prev: string;
    attribs = {
        ...ctx.ui.input,
        type: "text",
        onfocus: (e) => (prev = view.deref()),
        oninput: (e) => ctx.bus.dispatch([eventID, e.target.value]),
        onkeydown: (e: KeyboardEvent) => {
            switch (e.key) {
                case "Escape":
                    ctx.bus.dispatch([eventID, prev]);
                    (<HTMLElement>e.target).blur();
                    break;
                case "Enter":
                    ctx.bus.dispatch([eventID, (<HTMLInputElement>e.target).value]);
                    (<HTMLInputElement>e.target).blur();
                    break;
                default:
            }
        }
    };
    return () => ["input", {...attribs, value: view.deref()}];
}

Usage example

function labeledInput(ctx: AppContext, view: IView<string | number>, label: string) {
    const name = cancelableInput(ctx, ctx.views.name, "set-name");
    return () => ["div", ["label", ctx.ui.label, label], name];
}

function demoForm(ctx: AppContext) {
    const firstName = labeledInput(ctx, ctx.views.firstName, "First name");
    const surname = labeledInput(ctx, ctx.views.surname, "Surname");
    return () => ["div", firstName, surname];
}