Skip to main content

Handling events

Each element attribute which starts with an on prefix is considered by Drayman as an event. All events are fired in browser and then executed server-side (if you want to execute something insde browser, you can use Browser object).

Basic event usage#

You can use any known HTML element event when developing Drayman components. Simply add required event as an attribute and assign an async function which will be executed when event is fired:

src/components/home.tsx
export const component: DraymanComponent = async ({ forceUpdate }) => {  let text: string;
  return () => {    return (      <>        <input          oninput={async ({ value }) => {            text = value;            await forceUpdate();          }}        />        <h3>{text}</h3>      </>    );  };};

Some events provide useful data when it is fired. In example above, oninput event provides a value which is a user-typed text. You can find full list of emitted data below.

Generic data#

All configured events emit this data in addition to event-specific data:

trailing, leading

Data for keyboard events#

altKey, shiftKey, ctrlKey, metaKey, code, key, location, repeat

Data for mouse events#

altKey, shiftKey, ctrlKey, metaKey, x, y, pageX, pageY, screenX, screenY, offsetX, offsetY

Data for oninput, onchange events#

value

Data for third-party Drayman component elements#

Please refer to specific third-party element documentation to check which data is emitted.

Handling file upload events#

In addition to data object all events emit files array. This array can be used to check uploaded file info and save it to file system. It is usually used within <input type="file" /> element.

Let's for example create a component which displays directory contents and saves files to it. Before adding this component, create an uploaded directory in the root of your project.

src/components/home.tsx
import fs from "fs/promises";
export const component: DraymanComponent = async ({ forceUpdate }) => {  const uploadedDir = "./uploaded";
  return async () => {    return (      <>        <input          multiple          type="file"          oninput={async ({}, files) => {            for (const file of files) {              await fs.writeFile(                `${uploadedDir}/${file.originalname}`,                file.buffer              );            }            await forceUpdate();          }}        />        <pre>{(await fs.readdir(uploadedDir)).join("\n")}</pre>      </>    );  };};

Notice how oninput event of input element accepts files as a second parameter of event function. It is an array which is used to save files to file system using writeFile.

Configuring events#

In addition to function which will be executed on event, you can pass some configuration. Lets modify our previous example a bit:

src/components/home.tsx
export const component: DraymanComponent = async ({ forceUpdate }) => {  let text: string;
  return () => {    return (      <>        <input          oninput={[            async ({ value, trailing }) => {              text = value;              await forceUpdate();            },            { debounce: { wait: 500, trailing: true } },          ]}        />        <h3>{text}</h3>      </>    );  };};

Now we pass an array to oninput event. First element of this array is a function which needs to be executed on event. Second element - event configuration. In our case we tell to debounce our event for 500ms and execute a function on a trailing edge. In addition to value data, our event also receives trailing indicator, which will be true because function was executed on a trailing edge.

You can use a shorthand for this configuration:

src/components/home.tsx
export const component: DraymanComponent = async ({ forceUpdate }) => {  let text: string;
  return () => {    return (      <>        <input          oninput={[            async ({ value, trailing }) => {              text = value;              await forceUpdate();            },            { debounce: 500 },          ]}        />        <h3>{text}</h3>      </>    );  };};

It is also possible to configure element events globally using elementOptions

Event configuration options#

debounce#

Delays invoking event until wait milliseconds have elapsed since the last time the debounced event was invoked.

debounce accepts number (ms to delay) or an object with options:

wait#

Number of ms to delay.

trailing#

If true, invokes event on the trailing edge.

leading#

If true, invokes event on the leading edge.

src/components/home.tsx
export const component: DraymanComponent = async ({ forceUpdate }) => {  let text: string;
  return () => {    return (      <>        <h3>{text}</h3>        <p>Debounce with ms</p>        <input          value={text}          oninput={[            async ({ value }) => {              text = value;              await forceUpdate();            },            { debounce: 500 },          ]}        />        <p>Debounce on trailing edge</p>        <input          value={text}          oninput={[            async ({ value }) => {              text = value;              await forceUpdate();            },            { debounce: { wait: 500, trailing: true } },          ]}        />        <p>Debounce on leading edge</p>        <input          value={text}          oninput={[            async ({ value }) => {              text = value;              await forceUpdate();            },            { debounce: { wait: 500, leading: true } },          ]}        />      </>    );  };};