Events

In Stratox, you only need to memorize one function for binding events: bind. This function works by binding a view instance to an event, making it straightforward to modify the view's component properties. It automatically refreshes the component with the updated data, ensuring the UI stays in sync with your application state.

Creating an Event

In the example below, when the user clicks the "Increment +" button, a new value is added to the props object, and the view is automatically refreshed to reflect the change.

export default function Increment(props, container, helper, context) {
  const clickEvent = this.bind((props, view, item, event) => {
    props.increment += 1;
  });

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <header class="mb">
          <h2 class="headline-2">${props.increment > 0 ? "Incremented" : props.title}</h2>
          <p>Has been incremented <strong>${props.increment}</strong> times!</p>
        </header>
        <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
      </div>
    </article>
  `;
}

Manual Updates and Refreshes

You can disable automatic updates and refreshes by setting the second argument of bind to false. This allows you to manually control when a view or its components should refresh.

// Bind function to add a new item to the list
const handleAddList = this.bind((props, view, item, event) => {
  props.increment += 1;
  // Manually update and refresh the view
  view.update();
}, false);

This flexibility gives you full control over your app’s performance, allowing you to refresh components only when necessary.


Why Not Always Refresh the View?

Refreshing the entire view isn't always desirable. For example, if you bind an oninput event to a text field, you wouldn't want the whole view to refresh each time a user types. Instead, you want the text field's value to update without re-rendering the entire view.

Here’s how to handle this scenario:

const inputEvent = this.bind((props, view, item, event) => {
  props.value = event.target.value;
}, false);

A complete example:

export default function Increment(props, container, helper, context) {
  // Bind onclick event with refresh enabled
  const clickEvent = this.bind((props, view, item, event) => {
    props.increment += 1;
  });

  // Bind oninput event with refresh disabled
  const inputEvent = this.bind((props, view, item, event) => {
    props.value = event.target.value;
  }, false);

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <header class="mb">
          <h2 class="headline-2">${props.increment > 0 ? "Incremented" : props.title}</h2>
          <p>Has been incremented <strong>${props.increment}</strong> times!</p>
        </header>

        <div class="mb">
          <label>Title</label>
          <input type="text" oninput="${inputEvent}" value="${props.value ?? ""}">
        </div>

        <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
      </div>
    </article>
  `;
}

Choosing What View to Bind

By using this with the bind function, you can access the current component. This means you can also bind events to child components or specific parts of the layout.

Here’s an example:

function IncrementUp(props, container, helper, context) {
  return `
    <header class="mb">
      <h2 class="headline-2">${props.increment > 0 ? "Incremented" : props.title}</h2>
      <p>Has been incremented <strong>${props.increment}</strong> times!</p>
    </header>
  `;
}

export default function Increment(props, container, helper, context) {
  const { view, item, output: IncrementBlock } = this.block(IncrementUp, props);
  
  // Bind an event to the child view
  const clickEvent = view.bind((props, view, item, event) => {
    props.increment += 1;
  });

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        ${IncrementBlock}
        <div class="mb">
          <label>Title</label>
          <input type="text" value="">
        </div>
        <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
      </div>
    </article>
  `;
}

What’s cool is that in this example, only the IncrementUp component will refresh when the event is triggered, even though the button controlling the event is outside the IncrementUp component. This allows for efficient updates while maintaining precise control over the layout.

Last updated