CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jstree

jQuery tree plugin for creating interactive tree components with drag & drop, inline editing, checkboxes, search, and customizable node types

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

events.mddocs/

Events and Callbacks

Comprehensive guide to jsTree's event system, including core events, plugin-specific events, and custom event handling. jsTree uses jQuery's event system to provide extensive hooks for tree interactions and state changes.

Capabilities

Core Events

Fundamental events triggered during tree lifecycle and operations.

/**
 * Tree lifecycle events
 */

// Initialization events
"init.jstree": InitEvent;
"loading.jstree": LoadingEvent;
"loaded.jstree": LoadedEvent;
"ready.jstree": ReadyEvent;
"destroy.jstree": DestroyEvent;

// Rendering events
"redraw.jstree": RedrawEvent;
"refresh.jstree": RefreshEvent;

interface InitEvent {
  instance: jsTree;
}

interface LoadingEvent {
  instance: jsTree;
}

interface LoadedEvent {
  instance: jsTree;
}

interface ReadyEvent {
  instance: jsTree;
}

interface DestroyEvent {
  instance: jsTree;
}

interface RedrawEvent {
  nodes: Array<string>;
  instance: jsTree;
}

interface RefreshEvent {
  instance: jsTree;
}

Usage Examples:

// Listen for lifecycle events
$("#tree").on("init.jstree", function(e, data) {
  console.log("Tree initialized");
});

$("#tree").on("ready.jstree", function(e, data) {
  console.log("Tree is ready for interaction");
  // Safe to call tree methods here
  const tree = data.instance;
  tree.open_all();
});

$("#tree").on("destroy.jstree", function(e, data) {
  console.log("Tree destroyed, cleaning up...");
  // Cleanup code here
});

// Loading state management
$("#tree").on("loading.jstree", function(e, data) {
  $("#loading-indicator").show();
});

$("#tree").on("loaded.jstree", function(e, data) {
  $("#loading-indicator").hide();
});

Node Events

Events triggered by node-specific operations and state changes.

/**
 * Node operation events
 */

// Node state events
"open_node.jstree": NodeEvent;
"close_node.jstree": NodeEvent;
"select_node.jstree": SelectEvent;
"deselect_node.jstree": SelectEvent;
"changed.jstree": ChangedEvent;

// Node modification events
"create_node.jstree": CreateEvent;
"rename_node.jstree": RenameEvent;
"delete_node.jstree": DeleteEvent;
"move_node.jstree": MoveEvent;
"copy_node.jstree": CopyEvent;

// Node interaction events
"activate_node.jstree": ActivateEvent;
"hover_node.jstree": HoverEvent;
"dehover_node.jstree": HoverEvent;

interface NodeEvent {
  node: object;
  instance: jsTree;
}

interface SelectEvent {
  node: object;
  selected: Array<string>;
  event: Event;
  instance: jsTree;
}

interface ChangedEvent {
  selected: Array<string>;
  event: Event;
  instance: jsTree;
}

interface CreateEvent {
  node: object;
  parent: string;
  position: number;
  instance: jsTree;
}

interface RenameEvent {
  node: object;
  text: string;
  old: string;
  instance: jsTree;
}

interface DeleteEvent {
  node: object;
  parent: string;
  instance: jsTree;
}

interface MoveEvent {
  node: object;
  parent: string;
  position: number;
  old_parent: string;
  old_position: number;
  is_multi: boolean;
  old_instance: jsTree;
  new_instance: jsTree;
  instance: jsTree;
}

interface CopyEvent {
  node: object;
  original: object;
  parent: string;
  position: number;
  old_parent: string;
  old_position: number;
  is_multi: boolean;
  old_instance: jsTree;
  new_instance: jsTree;
  instance: jsTree;
}

interface ActivateEvent {
  node: object;
  event: Event;
  instance: jsTree;
}

interface HoverEvent {
  node: object;
  instance: jsTree;
}

Usage Examples:

// Node selection events
$("#tree").on("select_node.jstree", function(e, data) {
  console.log("Selected node:", data.node.text);
  console.log("All selected:", data.selected);
  
  // Update UI based on selection
  updateSelectionInfo(data.selected);
});

$("#tree").on("deselect_node.jstree", function(e, data) {
  console.log("Deselected node:", data.node.text);
  
  if (data.selected.length === 0) {
    clearSelectionInfo();
  }
});

// Node modification events
$("#tree").on("create_node.jstree", function(e, data) {
  console.log("Created node:", data.node.text, "in parent:", data.parent);
  
  // Save new node to server
  saveNodeToServer(data.node);
});

$("#tree").on("rename_node.jstree", function(e, data) {
  console.log("Renamed node from", data.old, "to", data.text);
  
  // Update server
  updateNodeOnServer(data.node.id, {text: data.text});
});

$("#tree").on("delete_node.jstree", function(e, data) {
  console.log("Deleted node:", data.node.text);
  
  // Confirm with user and update server
  if (confirm("Permanently delete this item?")) {
    deleteNodeOnServer(data.node.id);
  }
});

// Node movement events
$("#tree").on("move_node.jstree", function(e, data) {
  console.log("Moved node:", {
    node: data.node.text,
    from: data.old_parent,
    to: data.parent,
    oldPos: data.old_position,
    newPos: data.position
  });
  
  // Update server with new structure
  updateNodeParent(data.node.id, data.parent, data.position);
});

// Node state events
$("#tree").on("open_node.jstree", function(e, data) {
  console.log("Opened node:", data.node.text);
  
  // Load additional data when node opens
  if (data.node.children.length === 0) {
    loadNodeChildren(data.node.id);
  }
});

Plugin Events

Events specific to individual plugins.

/**
 * Checkbox plugin events
 */
"check_node.jstree": CheckboxEvent;
"uncheck_node.jstree": CheckboxEvent;

interface CheckboxEvent {
  node: object;
  selected: Array<string>;
  event: Event;
  instance: jsTree;
}

/**
 * Search plugin events
 */
"search.jstree": SearchEvent;
"clear_search.jstree": ClearSearchEvent;

interface SearchEvent {
  nodes: Array<string>;
  str: string;
  res: Array<object>;
  instance: jsTree;
}

interface ClearSearchEvent {
  instance: jsTree;
}

/**
 * DnD plugin events (using vakata namespace)
 */
"dnd_start.vakata": DnDEvent;
"dnd_move.vakata": DnDEvent;
"dnd_stop.vakata": DnDEvent;

interface DnDEvent {
  element: jQuery;
  target: jQuery;
  helper: jQuery;
  event?: Event;
}

/**
 * State plugin events
 */
"state_ready.jstree": StateEvent;

interface StateEvent {
  instance: jsTree;
}

Usage Examples:

// Checkbox events
$("#tree").on("check_node.jstree", function(e, data) {
  console.log("Checked:", data.node.text);
  console.log("All checked nodes:", data.selected);
  
  // Update summary
  updateCheckedSummary(data.selected);
});

$("#tree").on("uncheck_node.jstree", function(e, data) {
  console.log("Unchecked:", data.node.text);
  updateCheckedSummary(data.selected);
});

// Search events
$("#tree").on("search.jstree", function(e, data) {
  console.log(`Found ${data.nodes.length} matches for "${data.str}"`);
  $("#search-results").text(`${data.nodes.length} results`);
  
  if (data.nodes.length === 0) {
    $("#no-results").show();
  } else {
    $("#no-results").hide();
  }
});

$("#tree").on("clear_search.jstree", function(e, data) {
  $("#search-results").text("");
  $("#no-results").hide();
});

// DnD events
$(document).on("dnd_start.vakata", function(e, data) {
  console.log("Drag started");
  $("body").addClass("dragging");
});

$(document).on("dnd_stop.vakata", function(e, data) {
  console.log("Drag stopped");
  $("body").removeClass("dragging");
});

// State events
$("#tree").on("state_ready.jstree", function(e, data) {
  console.log("State restored");
  // Tree state has been restored from storage
});

Event Binding Patterns

Common patterns for binding and managing events.

/**
 * Event binding utilities and patterns
 */
interface EventBindingPatterns {
  /** Bind multiple events at once */
  bindMultiple: (events: object) => void;
  /** Bind with context */
  bindWithContext: (event: string, handler: function, context: object) => void;
  /** One-time event binding */
  bindOnce: (event: string, handler: function) => void;
  /** Conditional event binding */
  bindConditional: (event: string, condition: function, handler: function) => void;
}

Usage Examples:

// Multiple event binding
$("#tree").on({
  "select_node.jstree": function(e, data) {
    handleNodeSelection(data);
  },
  "deselect_node.jstree": function(e, data) {
    handleNodeDeselection(data);
  },
  "open_node.jstree": function(e, data) {
    handleNodeOpen(data);
  },
  "close_node.jstree": function(e, data) {
    handleNodeClose(data);
  }
});

// Event delegation for dynamic trees
$(document).on("select_node.jstree", ".dynamic-tree", function(e, data) {
  // Handle selection for any tree with class 'dynamic-tree'
  console.log("Dynamic tree selection:", data.node.text);
});

// One-time event binding
$("#tree").one("ready.jstree", function(e, data) {
  // This will only run once when tree is first ready
  initializeTreeUI(data.instance);
});

// Conditional event handling
$("#tree").on("delete_node.jstree", function(e, data) {
  // Only handle if user has permission
  if (hasDeletePermission(data.node)) {
    confirmAndDelete(data.node);
  } else {
    e.preventDefault();
    showPermissionError();
  }
});

// Event namespacing for cleanup
$("#tree").on("select_node.jstree.myapp", function(e, data) {
  handleSelection(data);
});

// Later, remove only this namespace
$("#tree").off(".myapp");

Custom Events

Creating and triggering custom events within jsTree context.

/**
 * Custom event creation and triggering
 */
interface CustomEvents {
  /** Trigger custom event */
  trigger: (event: string, data?: object) => void;
  /** Create custom event type */
  createEventType: (name: string, handler: function) => void;
}

// Custom event data structure
interface CustomEventData {
  custom: boolean;
  data: any;
  instance: jsTree;
  [key: string]: any;
}

Usage Examples:

// Define custom events
$("#tree").on("custom_validation.jstree", function(e, data) {
  console.log("Custom validation triggered:", data);
  
  // Perform custom validation logic
  const isValid = validateNodeData(data.node);
  
  if (!isValid) {
    e.preventDefault();
    showValidationError(data.node);
  }
});

// Trigger custom events
const tree = $("#tree").jstree(true);
tree.element.trigger("custom_validation.jstree", {
  node: tree.get_node("some_node"),
  validationType: "business_rules",
  timestamp: Date.now()
});

// Custom event for business logic
$("#tree").on("node_audit.jstree", function(e, data) {
  // Log node operations for audit trail
  auditLog.record({
    action: data.action,
    nodeId: data.node.id,
    userId: getCurrentUser().id,
    timestamp: new Date().toISOString()
  });
});

// Usage in tree operations
$("#tree").on("create_node.jstree", function(e, data) {
  // Trigger audit event
  $(this).trigger("node_audit.jstree", {
    action: "create",
    node: data.node
  });
});

Event Performance and Optimization

Best practices for event handling performance.

/**
 * Performance optimization patterns
 */
interface EventPerformance {
  /** Debounced event handling */
  debounce: (handler: function, delay: number) => function;
  /** Throttled event handling */
  throttle: (handler: function, limit: number) => function;
  /** Batch event processing */
  batchProcess: (events: Array<object>) => void;
}

Usage Examples:

// Debounced search
let searchTimeout;
$("#tree").on("search.jstree", function(e, data) {
  clearTimeout(searchTimeout);
  searchTimeout = setTimeout(function() {
    updateSearchAnalytics(data.str, data.nodes.length);
  }, 300);
});

// Throttled selection updates
let lastSelectionUpdate = 0;
$("#tree").on("changed.jstree", function(e, data) {
  const now = Date.now();
  if (now - lastSelectionUpdate > 100) { // Throttle to 10fps
    updateSelectionUI(data.selected);
    lastSelectionUpdate = now;
  }
});

// Batch processing for multiple operations
let pendingUpdates = [];
$("#tree").on("move_node.jstree copy_node.jstree delete_node.jstree", function(e, data) {
  pendingUpdates.push({
    event: e.type,
    data: data,
    timestamp: Date.now()
  });
  
  // Process in batches
  if (pendingUpdates.length >= 10) {
    processBatch(pendingUpdates);
    pendingUpdates = [];
  }
});

// Process remaining updates periodically
setInterval(function() {
  if (pendingUpdates.length > 0) {
    processBatch(pendingUpdates);
    pendingUpdates = [];
  }
}, 1000);

// Memory cleanup
$("#tree").on("destroy.jstree", function() {
  // Clear timeouts and intervals
  clearTimeout(searchTimeout);
  clearInterval(batchProcessor);
  
  // Remove global event listeners
  $(document).off(".tree-app");
  $(window).off(".tree-app");
});

Error Events

Events for error handling and debugging.

/**
 * Error events and handling
 */
"error.jstree": ErrorEvent;

interface ErrorEvent {
  error: string;
  plugin: string;
  id: string;
  reason: string;
  data: any;
  instance: jsTree;
}

Usage Examples:

// Global error handling
$("#tree").on("error.jstree", function(e, data) {
  console.error("jsTree error:", {
    error: data.error,
    plugin: data.plugin,
    reason: data.reason,
    data: data.data
  });
  
  // Show user-friendly error message
  showErrorNotification("An error occurred while updating the tree");
  
  // Log to error tracking service
  errorTracker.log("jstree_error", {
    error: data.error,
    plugin: data.plugin,
    reason: data.reason,
    url: window.location.href,
    userAgent: navigator.userAgent
  });
});

// Plugin-specific error handling
$("#tree").on("error.jstree", function(e, data) {
  if (data.plugin === "search") {
    $("#search-error").show().text("Search failed: " + data.reason);
  } else if (data.plugin === "core" && data.error === "load_node") {
    showRetryDialog("Failed to load tree data. Retry?", function() {
      // Retry loading
      data.instance.refresh();
    });
  }
});

Types

// Base event interface
interface TreeEvent {
  type: string;
  target: Element;
  currentTarget: Element;
  instance: jsTree;
  timeStamp: number;
}

// Event data union type
type EventData = 
  | InitEvent 
  | NodeEvent 
  | SelectEvent 
  | CreateEvent 
  | RenameEvent 
  | DeleteEvent 
  | MoveEvent 
  | CopyEvent 
  | SearchEvent 
  | CheckboxEvent 
  | ErrorEvent;

// Event handler type
type EventHandler<T = EventData> = (event: jQuery.Event, data: T) => void;

// Event binding options
interface EventBindingOptions {
  namespace?: string;
  once?: boolean;
  passive?: boolean;
  capture?: boolean;
}

docs

checkbox.md

configuration.md

contextmenu.md

core.md

dnd.md

events.md

index.md

plugins.md

search.md

tile.json