Recipe: a form
Lay the form out in XML and bind each input to a ref. bind:value, bind:selected and bind:checked on a plain ref name are two way, so typed values land in your refs with no code. See Bindings and events.
ts
import { Component, Controller, DEFAULT_STAGE, Ref, Screen, TemplateRegistry } from "willowui";
const TEMPLATE: string = `
<Panel layout="vbox" spacing="10" padding="20">
<Label text="New character" fontSize="20" />
<TwoColumnLayout leftWidth="110" gap="12" rowSpacing="8">
<Label text="Name" />
<TextInput bind:value="name" width="220" placeholder="Hero" />
<Label text="Class" />
<Select options="Warrior,Mage,Rogue" size="220,32" bind:selected="classIndex" />
<Label text="Hardcore" />
<Checkbox text="One life only" bind:checked="hardcore" />
</TwoColumnLayout>
<Button text="Create" on:click="create" bind:enabled="name != ''" />
<Label bind:text="status" />
</Panel>`;
const CLASSES: string[] = ["Warrior", "Mage", "Rogue"];
class NewCharacter implements Controller {
name: Ref<string> = new Ref<string>("");
classIndex: Ref<int> = new Ref<int>(0);
hardcore: Ref<boolean> = new Ref<boolean>(false);
status: Ref<string> = new Ref<string>("");
onCreate(screen: Screen): void {
const reg: TemplateRegistry = new TemplateRegistry();
reg.registerXML("form", TEMPLATE);
const root: Component = reg.instantiate("form", this, screen);
screen.add(root);
}
onUpdate(dt: float): void {}
onDispose(): void {}
lookupRef(path: string): any {
if (path == "name") { return this.name; }
if (path == "classIndex") { return this.classIndex; }
if (path == "hardcore") { return this.hardcore; }
if (path == "status") { return this.status; }
return null;
}
callMethod(method: string): boolean {
if (method == "create") {
const mode: string = this.hardcore.peek() ? " (hardcore)" : "";
this.status.set("Created " + this.name.peek() + " the " + CLASSES[this.classIndex.peek()] + mode);
return true;
}
return false;
}
}
DEFAULT_STAGE.setScene(engine.root2d);
DEFAULT_STAGE.add(new Screen().withController(new NewCharacter()));
App.onFrame((dt: float): void => { DEFAULT_STAGE.update(dt); });Notes:
bind:enabled="name != ''"disables the button while the name is empty. Two strings compare as text (see Expressions).- Validation messages fit an
InputField(setValidationState,setValidationMessage) instead of a bareTextInput.