Skip to main content

Custom input element with 2 ways data-binding

· 2 min read
Kirill Vasin

It is also possible to combine your custom input element with traditional dynamics. For instance you want to create multiple input fields, which are synchronised with each other or using some equation.

You need a WLJS Function with update methods defined. One can generate those on-fly for each input element within a WLX script

.wlx

CustomInput[sym_, OptionsPattern[]] := Module[{
Label = OptionValue["Label"],
Ev = OptionValue["Event"],
Pattern = OptionValue["Pattern"],
Handler
},

With[{Template =
<div class="mt-2 flex">
<div style="width: 7rem" class="flex shrink-0 items-center rounded-l-md bg-white px-3 text-base text-gray-500 outline outline-1 -outline-offset-1 outline-gray-300 sm:text-sm/6"><Label/></div>
<input type="number" step="1" class="-ml-px block w-full grow rounded-r-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6" placeholder="0.0"/>
<script type="module">
core['<Handler/>'] = async (args, env) => {
const input = env.element.getElementsByTagName('input')[0];


const data = await interpretate(args[0], env);
input.value = +data.toFixed(4);
env.local.input = input;

input.addEventListener('change', () => {

console.warn(input.value);
env.local.skip = true;
server.kernel.emitt('<Ev/>', input.value, '<Pattern/>');
});
}

core['<Handler/>'].update = async (args, env) => {
if (env.local.skip) {
env.local.skip = false;
return;
}

console.log('Update');
env.local.input.value = +(await interpretate(args[0], env)).toFixed(4);
}

core['<Handler/>'].destroy = () => {
delete core['<Handler/>'];
}

core['<Handler/>'].virtual = true;
</script>
</div>
},
HTMLView[Template, Epilog->(Handler[sym])]
]
]

Options[CustomInput] = {"Label"->"", "Event"->"", "Pattern"->"Default"};

what happens here:

  1. we define a template for our custom input field
  2. we define a support script with a generated Handler function, which reads and updates this input field
  3. we pack in into HTMLView, which calls our Handler on a provided argument after this component has been mounted

Let's see it in action