Skip to content

x🔛click Directive ​

The x:on:click directive is used to bind click event handlers to HTML elements.

Basic Usage ​

Syntax ​

html
<!-- Without parameters -->
<button x:on:click="methodName">Click</button>

<!-- With parameters -->
<button x:on:click="methodName(arg1, arg2)">Click</button>

<!-- Event object -->
<button x:on:click="handleClick($event)">Click</button>

<!-- Element reference -->
<button x:on:click="handleClick($target)">Click</button>

Special Parameters ​

$event - Event Object ​

typescript
@Widget({
  selector: '.event-widget',
  template: '<button x:on:click="handleClick($event)">Click</button>'
})
export class EventWidget {
  handleClick(event: MouseEvent): void {
    console.log('Click position:', event.clientX, event.clientY);
    event.preventDefault();
    event.stopPropagation();
  }
}

$target - Event Target ​

typescript
@Widget({
  selector: '.target-widget',
  template: '<button x:on:click="handleClick($target)">Click</button>'
})
export class TargetWidget {
  handleClick(target: HTMLElement): void {
    console.log('Clicked element:', target.tagName);
    target.classList.add('clicked');
  }
}

$element - Bound Element ​

typescript
@Widget({
  selector: '.element-widget',
  template: '<button x:on:click="handleClick($element)">Click</button>'
})
export class ElementWidget {
  handleClick(element: HTMLElement): void {
    console.log('Bound element:', element);
  }
}

Examples ​

Passing Parameters ​

typescript
@Widget({
  selector: '.params-widget',
  template: `
    <div>
      <button x:on:click="addItem('Apple')">Add Apple</button>
      <button x:on:click="addItem('Pear')">Add Pear</button>
      <button x:on:click="setCount(10)">Set to 10</button>
      <ul>
        <template x:for="item in items">
          <li x:text="item">-</li>
        </template>
      </ul>
    </div>
  `
})
export class ParamsWidget {
  @xproperty()
  items: string[] = [];
  
  @xproperty()
  count: number = 0;
  
  addItem(item: string): void {
    this.items.push(item);
  }
  
  setCount(value: number): void {
    this.count = value;
  }
}

Parameter with Property ​

typescript
@Widget({
  selector: '.dynamic-params-widget',
  template: `
    <div>
      <input type="text" x:model="newItem">
      <button x:on:click="addItem(newItem)">Add</button>
      <button x:on:click="updateMessage(userName)">Update</button>
    </div>
  `
})
export class DynamicParamsWidget {
  @xproperty()
  newItem: string = '';
  
  @xproperty()
  userName: string = 'User';
  
  @xproperty()
  items: string[] = [];
  
  addItem(item: string): void {
    if (item.trim()) {
      this.items.push(item);
      this.newItem = '';
    }
  }
  
  updateMessage(name: string): void {
    console.log('Hello,', name);
  }
}

Event Details ​

typescript
@Widget({
  selector: '.event-details-widget',
  template: `
    <div>
      <button x:on:click="showDetails($event)">Show Details</button>
      <p x:text="eventInfo">-</p>
    </div>
  `
})
export class EventDetailsWidget {
  @xproperty()
  eventInfo: string = '';
  
  showDetails(event: MouseEvent): void {
    this.eventInfo = `
      X: ${event.clientX}, 
      Y: ${event.clientY}, 
      Button: ${event.button},
      Ctrl: ${event.ctrlKey ? 'Yes' : 'No'}
    `;
  }
}

Usage Inside Loop ​

typescript
@Widget({
  selector: '.list-widget',
  template: `
    <div>
      <template x:for="(item, index) in items">
        <div>
          <span x:text="item.name">-</span>
          <button x:on:click="editItem(index)">Edit</button>
          <button x:on:click="deleteItem(index)">Delete</button>
        </div>
      </template>
    </div>
  `
})
export class ListWidget {
  @xproperty()
  items: Array<{name: string}> = [
    { name: 'Item 1' },
    { name: 'Item 2' }
  ];
  
  editItem(index: number): void {
    console.log('Editing:', this.items[index]);
  }
  
  deleteItem(index: number): void {
    this.items.splice(index, 1);
  }
}

Toggle Example ​

typescript
@Widget({
  selector: '.toggle-widget',
  template: `
    <div>
      <button x:on:click="toggle">
        <span x:text="isActive ? 'Close' : 'Open'">-</span>
      </button>
      <div x:if="isActive">
        <p>Content is visible</p>
      </div>
    </div>
  `
})
export class ToggleWidget {
  @xproperty()
  isActive: boolean = false;
  
  toggle(): void {
    this.isActive = !this.isActive;
  }
}

Form Operations ​

typescript
@Widget({
  selector: '.form-widget',
  template: `
    <form>
      <input type="text" x:model="username">
      <input type="password" x:model="password">
      <button type="button" x:on:click="handleSubmit($event)">
        Submit
      </button>
      <button type="button" x:on:click="handleReset">
        Reset
      </button>
    </form>
  `
})
export class FormWidget {
  @xproperty()
  username: string = '';
  
  @xproperty()
  password: string = '';
  
  handleSubmit(event: Event): void {
    event.preventDefault();
    console.log('Submitting form:', {
      username: this.username,
      password: this.password
    });
  }
  
  handleReset(): void {
    this.username = '';
    this.password = '';
  }
}

Multiple Parameters ​

typescript
@Widget({
  selector: '.multi-params-widget',
  template: `
    <button x:on:click="createUser('Ahmet', 25, true)">
      Create User
    </button>
    <button x:on:click="logData($event, userName, userAge)">
      Log
    </button>
  `
})
export class MultiParamsWidget {
  @xproperty()
  userName: string = 'Test';
  
  @xproperty()
  userAge: number = 30;
  
  createUser(name: string, age: number, isActive: boolean): void {
    console.log('Created:', { name, age, isActive });
  }
  
  logData(event: Event, name: string, age: number): void {
    console.log('Event:', event);
    console.log('Data:', { name, age });
  }
}

Visual Feedback ​

Click events are automatically marked with CSS classes:

typescript
@Widget({
  selector: '.feedback-widget',
  template: '<button x:on:click="handleClick">Click</button>',
  styles: [`
    button.xcon-clickable {
      cursor: pointer;
    }
    button.xcon-clicked {
      transform: scale(0.95);
      transition: transform 0.15s;
    }
  `]
})
export class FeedbackWidget {
  handleClick(): void {
    console.log('Clicked!');
  }
}

Automatic classes:

  • xcon-clickable: Added during element setup
  • xcon-clicked: Added for 150ms during click

Nested Method Calls ​

typescript
class UserService {
  save(data: any): void {
    console.log('Saving:', data);
  }
}

@Widget({
  selector: '.service-widget',
  template: '<button x:on:click="userService.save(userData)">Save</button>'
})
export class ServiceWidget {
  @xproperty()
  userService = new UserService();
  
  @xproperty()
  userData = { name: 'Test' };
}

Best Practices ​

✅ Correct ​

typescript
// Simple and clear method names
handleClick(): void { }
onSubmit(): void { }
deleteItem(id: number): void { }

// Use event when needed
handleClick(event: MouseEvent): void {
  event.preventDefault();
}

❌ Wrong ​

html
<!-- Complex logic in template -->
<button x:on:click="items.filter(i => i.active).length > 0 ? save() : cancel()">
  Click
</button>

<!-- Use method instead -->
typescript
// Correct solution
handleClick(): void {
  const hasActive = this.items.some(i => i.active);
  if (hasActive) {
    this.save();
  } else {
    this.cancel();
  }
}

Summary ​

  • Simple syntax: x:on:click="methodName"
  • Parameter support: Values and expressions can be passed
  • Special parameters: $event, $target, $element
  • Visual feedback: Automatic CSS classes
  • Loop compatible: Can be used inside x:for
  • Type-safe: Full support with TypeScript
  • Event control: preventDefault, stopPropagation can be used