Now.js Framework Documentation

Now.js Framework Documentation

data-on

EN 11 Dec 2025 11:58

data-on

Overview

data-on binds event handlers to elements. It supports event modifiers for common patterns like preventing default behavior, key filtering, and more.

When to use:

  • Handle user interactions (clicks, inputs, etc.)
  • Respond to keyboard events
  • Manage form submissions

Why use it:

  • ✅ Declarative event binding
  • ✅ 20+ built-in modifiers
  • ✅ Automatic cleanup on element removal
  • ✅ Supports method arguments

Basic Usage

Click Handler

<button data-on="click:handleClick">Click me</button>

In your JavaScript:

function handleClick(event) {
  console.log('Button clicked!');
}

With Arguments

<button data-on="click:deleteItem(item.id)">Delete</button>
function deleteItem(id, event) {
  console.log('Delete item:', id);
}

Syntax

<element data-on="eventType.modifier1.modifier2:methodName(args)">
Part Description
eventType DOM event name (click, input, keydown, etc.)
.modifier Optional modifiers (can chain multiple)
methodName Function to call
(args) Optional arguments

Event Types

All standard DOM events are supported:

Category Events
Mouse click, dblclick, mousedown, mouseup, mousemove, mouseenter, mouseleave
Keyboard keydown, keyup, keypress
Form submit, input, change, focus, blur
Touch touchstart, touchend, touchmove
Scroll scroll, wheel
Drag drag, dragstart, dragend, drop

Modifiers Reference

Event Behavior Modifiers

Modifier Description Equivalent
.prevent Prevent default behavior event.preventDefault()
.stop Stop event propagation event.stopPropagation()
.once Handle event only once { once: true }
.capture Use capture phase { capture: true }
.self Only if target is element itself event.target === element
.trusted Only trusted events event.isTrusted

Key Modifiers

Modifier Key
.enter Enter key
.tab Tab key
.esc Escape key
.space Space bar

Mouse Button Modifiers

Modifier Button
.left Left mouse button (button 0)
.right Right mouse button (button 2)
.middle Middle mouse button (button 1)

System Key Modifiers

Modifier Key
.ctrl Control key held
.alt Alt key held
.shift Shift key held
.meta Meta/Command key held

Features

1. Basic Event Handling

<button data-on="click:save">Save</button>
<input data-on="input:handleInput">
<form data-on="submit:handleSubmit">

2. Prevent Default

<!-- Prevent form submission -->
<form data-on="submit.prevent:handleSubmit">
  <button type="submit">Submit</button>
</form>

<!-- Prevent link navigation -->
<a href="#" data-on="click.prevent:openModal">Open Modal</a>

3. Stop Propagation

<div data-on="click:closeModal">
  <div class="modal" data-on="click.stop:noop">
    <!-- Click here won't close modal -->
  </div>
</div>

4. Key Modifiers

<!-- Trigger on Enter key -->
<input data-on="keydown.enter:search">

<!-- Trigger on Escape key -->
<div data-on="keydown.esc:closeModal">

<!-- Trigger on Tab key -->
<input data-on="keydown.tab:moveToNext">

5. Modifier Combinations

<!-- Ctrl+Enter to submit -->
<textarea data-on="keydown.ctrl.enter:submit"></textarea>

<!-- Shift+Click -->
<div data-on="click.shift:selectRange"></div>

<!-- Ctrl+S to save -->
<div data-on="keydown.ctrl.s.prevent:save"></div>

6. Multiple Event Bindings

<input
  data-on="focus:onFocus, blur:onBlur, input:onInput">

7. Method Arguments

<!-- Pass data properties -->
<button data-on="click:deleteUser(user.id)">Delete</button>

<!-- Pass literal values -->
<button data-on="click:setStatus('active')">Activate</button>

<!-- Pass multiple arguments -->
<button data-on="click:updateItem(item.id, 'published')">Publish</button>

<!-- Pass index in loop -->
<div data-for="item in items">
  <template>
    <button data-on="click:selectItem(index)">Select</button>
  </template>
</div>

8. Self Modifier

<div data-on="click.self:closeSidebar">
  <!-- Only triggers when clicking the div itself, not children -->
  <button>This click won't trigger closeSidebar</button>
</div>

9. Once Modifier

<button data-on="click.once:trackFirstClick">
  Click me
</button>

Advanced Examples

Form with Validation

<form data-on="submit.prevent:handleSubmit">
  <input
    type="email"
    name="email"
    data-on="input:validateEmail, blur:validateEmail">

  <input
    type="password"
    name="password"
    data-on="keydown.enter:handleSubmit, input:validatePassword">

  <button type="submit">Login</button>
</form>
function handleSubmit(event) {
  const form = event.target;
  // Process form
}

function validateEmail(event) {
  const email = event.target.value;
  // Validate email
}

Keyboard Shortcuts

<div class="editor"
     data-on="
       keydown.ctrl.s.prevent:save,
       keydown.ctrl.z.prevent:undo,
       keydown.ctrl.shift.z.prevent:redo,
       keydown.esc:closeEditor
     ">
  <textarea data-model="content"></textarea>
</div>

Drag and Drop

<div class="dropzone"
     data-on="
       dragenter.prevent:onDragEnter,
       dragover.prevent:onDragOver,
       dragleave:onDragLeave,
       drop.prevent:onDrop
     ">
  <p>Drop files here</p>
</div>

<div class="draggable"
     draggable="true"
     data-on="dragstart:onDragStart">
  Drag me
</div>

Context Menu

<div class="item"
     data-on="contextmenu.prevent:showContextMenu">
  Right-click for options
</div>

Infinite Scroll

<div class="scroll-container"
     data-on="scroll:handleScroll">
  <div data-for="item in items">
    <template>
      <div class="item" data-text="item.name"></div>
    </template>
  </div>
  <div data-if="isLoading" class="loader">Loading...</div>
</div>
function handleScroll(event) {
  const container = event.target;
  if (container.scrollTop + container.clientHeight >= container.scrollHeight - 100) {
    loadMoreItems();
  }
}

Interactive List

<ul class="task-list" data-for="task in tasks">
  <template>
    <li data-class="completed:task.done">
      <input
        type="checkbox"
        data-checked="task.done"
        data-on="change:toggleTask(task.id)">

      <span data-text="task.title"
            data-on="dblclick:editTask(task)"></span>

      <button data-on="click.stop:deleteTask(task.id)">×</button>
    </li>
  </template>
</ul>

Touch Events

<div class="swipeable"
     data-on="
       touchstart:onTouchStart,
       touchmove.prevent:onTouchMove,
       touchend:onTouchEnd
     ">
  Swipe me
</div>

API Reference

Handler Signature

function handlerName(arg1, arg2, ..., event) {
  // Arguments passed in data-on come first
  // Event object is always the last parameter
}

Event Object

The native DOM Event object is passed as the last argument:

Property Description
event.target Element that triggered event
event.currentTarget Element with the listener
event.type Event type (click, input, etc.)
event.key Key pressed (for keyboard events)
event.button Mouse button (for mouse events)

Global vs Component Methods

// Global function
function globalHandler(event) {
  console.log('Global handler');
}
window.globalHandler = globalHandler;

// Component method (in component context)
const component = {
  methods: {
    componentHandler(event) {
      console.log('Component handler');
    }
  }
};

Common Pitfalls

⚠️ 1. Function Not Found

<!-- ❌ Function must be global or in component methods -->
<button data-on="click:localFunction">Click</button>

<!-- ✅ Make it global -->
<script>
  window.myHandler = function(e) { ... };
</script>
<button data-on="click:myHandler">Click</button>

⚠️ 2. Missing Prevent on Forms

<!-- ❌ Form will submit and reload page -->
<form data-on="submit:handleSubmit">

<!-- ✅ Prevent default submission -->
<form data-on="submit.prevent:handleSubmit">

⚠️ 3. Event Bubbling Issues

<!-- ❌ Inner click triggers outer handler too -->
<div data-on="click:closeDropdown">
  <button data-on="click:toggleDropdown">Toggle</button>
</div>

<!-- ✅ Stop propagation on inner element -->
<div data-on="click:closeDropdown">
  <button data-on="click.stop:toggleDropdown">Toggle</button>
</div>

⚠️ 4. Button Default Type

Buttons inside forms default to type="submit":

<!-- ❌ This will submit the form -->
<form>
  <button data-on="click:doSomething">Click</button>
</form>

<!-- ✅ Explicitly set type -->
<form>
  <button type="button" data-on="click:doSomething">Click</button>
</form>

Note: data-on automatically adds .stop modifier for clicks on buttons to prevent this issue.

⚠️ 5. Debouncing Rapid Events

// ❌ May fire too often
function handleScroll(e) {
  checkInfiniteScroll();
}

// ✅ Throttle/debounce manually
let scrollTimeout;
function handleScroll(e) {
  if (!scrollTimeout) {
    scrollTimeout = setTimeout(() => {
      checkInfiniteScroll();
      scrollTimeout = null;
    }, 100);
  }
}

Modifier Combinations Quick Reference

Pattern Use Case
click.prevent Links that trigger JS
submit.prevent AJAX form submission
click.stop Prevent bubbling to parent
keydown.enter.prevent Enter submits without newline
keydown.ctrl.s.prevent Custom save shortcut
click.once One-time actions
click.self Only direct clicks