or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

ajax.mdanimations.mdcss-styling.mddata-storage.mddom-manipulation.mddom-traversal.mdevents.mdforms.mdindex.mdutilities.md
tile.json

data-storage.mddocs/

Data Storage

Client-side data storage system for associating arbitrary data with DOM elements safely and efficiently. jQuery's data system provides a clean interface for storing and retrieving data without polluting the DOM or causing memory leaks.

Capabilities

Element Data Storage

Store and retrieve arbitrary data associated with DOM elements using jQuery's internal data system.

/**
 * Store data associated with DOM elements
 * @param key - Data key or object of key/value pairs
 * @param value - Data value to store
 * @returns jQuery object for chaining (when setting) or stored value (when getting)
 */
data(key: string): any;
data(key: string, value: any): jQuery;
data(obj: object): jQuery;
data(): object;

/**
 * Remove stored data from elements
 * @param key - Optional specific key to remove, or space-separated keys
 * @returns jQuery object for chaining
 */
removeData(key?: string): jQuery;

Usage Examples:

// Store single value
$('#element').data('user-id', 123);
$('#element').data('preferences', { theme: 'dark', lang: 'en' });

// Store multiple values at once
$('#element').data({
  'status': 'active',
  'priority': 'high',
  'created': new Date()
});

// Retrieve single value
const userId = $('#element').data('user-id'); // 123
const prefs = $('#element').data('preferences'); // { theme: 'dark', lang: 'en' }

// Retrieve all data
const allData = $('#element').data();
console.log(allData); // { user-id: 123, preferences: {...}, status: 'active', ... }

// Remove specific data
$('#element').removeData('user-id');

// Remove multiple keys
$('#element').removeData('status priority');

// Remove all data
$('#element').removeData();

// Data persistence across operations
$('.item').each(function(index) {
  $(this).data('index', index);
  $(this).data('original-class', this.className);
});

// Later retrieve and use data
$('.item').click(function() {
  const index = $(this).data('index');
  const originalClass = $(this).data('original-class');
  console.log('Item', index, 'clicked, original class:', originalClass);
});

HTML5 Data Attributes

Automatic integration with HTML5 data-* attributes with type conversion and camelCase normalization.

// HTML5 data attributes are automatically accessible via .data()
// data-user-name becomes accessible as 'userName' or 'user-name'
// Values are automatically parsed (JSON, numbers, booleans)

Usage Examples:

<!-- HTML with data attributes -->
<div id="product" 
     data-product-id="123"
     data-price="29.99"
     data-available="true"
     data-tags='["electronics", "gadget"]'
     data-metadata='{"brand": "TechCo", "model": "X1"}'>
  Product Info
</div>
// Access data attributes
const productId = $('#product').data('product-id');     // 123 (number)
const productId2 = $('#product').data('productId');     // 123 (camelCase access)
const price = $('#product').data('price');              // 29.99 (number)
const available = $('#product').data('available');      // true (boolean)
const tags = $('#product').data('tags');                // ["electronics", "gadget"] (array)
const metadata = $('#product').data('metadata');        // {brand: "TechCo", model: "X1"} (object)

// Set data attributes (updates both data store and DOM attribute)
$('#product').data('product-id', 456);
// HTML becomes: data-product-id="456"

// Complex data structures
$('#product').data('user-settings', {
  notifications: true,
  theme: 'dark',
  languages: ['en', 'es']
});

// Retrieve all data including HTML5 attributes
const allProductData = $('#product').data();
console.log(allProductData);
// { productId: 123, price: 29.99, available: true, tags: [...], metadata: {...} }

Static Data Methods

Direct data manipulation on DOM elements without jQuery objects.

/**
 * Store data directly on DOM element
 * @param element - DOM element to store data on
 * @param key - Data key or object of key/value pairs
 * @param value - Optional data value
 * @returns Stored value or undefined
 */
$.data(element: Element, key: string): any;
$.data(element: Element, key: string, value: any): any;
$.data(element: Element, obj: object): any;

/**
 * Remove data directly from DOM element
 * @param element - DOM element to remove data from
 * @param key - Optional specific key to remove
 */
$.removeData(element: Element, key?: string): void;

/**
 * Check if DOM element has associated jQuery data
 * @param element - DOM element to check
 * @returns true if element has data, false otherwise
 */
$.hasData(element: Element): boolean;

Usage Examples:

// Direct element data manipulation
const element = document.getElementById('myDiv');

// Store data
$.data(element, 'timestamp', Date.now());
$.data(element, 'config', { active: true, mode: 'edit' });

// Retrieve data
const timestamp = $.data(element, 'timestamp');
const config = $.data(element, 'config');

// Check for data
if ($.hasData(element)) {
  console.log('Element has associated data');
}

// Remove data
$.removeData(element, 'timestamp');
$.removeData(element); // Remove all data

// Useful for non-jQuery DOM manipulation
function attachBehavior(element, behavior) {
  $.data(element, 'behavior', behavior);
  element.addEventListener('click', function() {
    const behaviorData = $.data(element, 'behavior');
    behaviorData.execute();
  });
}

// Clean up data before removing elements
function cleanRemoveElement(element) {
  if ($.hasData(element)) {
    $.removeData(element);
  }
  element.parentNode.removeChild(element);
}

Data Storage Patterns

Configuration Storage

Store configuration and settings data with elements.

Usage Examples:

// Widget configuration
$('.widget').each(function() {
  const $widget = $(this);
  const config = {
    autoRefresh: $widget.hasClass('auto-refresh'),
    refreshInterval: parseInt($widget.attr('data-refresh')) || 5000,
    apiEndpoint: $widget.attr('data-api') || '/api/default'
  };
  
  $widget.data('config', config);
});

// Use configuration later
$('.widget').on('init', function() {
  const config = $(this).data('config');
  if (config.autoRefresh) {
    setInterval(() => {
      refreshWidget(this, config.apiEndpoint);
    }, config.refreshInterval);
  }
});

// Form field validation rules
$('input[data-validation]').each(function() {
  const $input = $(this);
  const rules = $input.attr('data-validation').split('|');
  
  $input.data('validation-rules', rules.map(rule => {
    const [name, param] = rule.split(':');
    return { name, param };
  }));
});

State Management

Track element states and application data.

Usage Examples:

// Track element states
$('.toggle-button').click(function() {
  const $btn = $(this);
  const isExpanded = $btn.data('expanded') || false;
  
  $btn.data('expanded', !isExpanded);
  $btn.attr('aria-expanded', !isExpanded);
  $btn.toggleClass('expanded', !isExpanded);
  
  if (!isExpanded) {
    $btn.next('.collapsible').slideDown();
  } else {
    $btn.next('.collapsible').slideUp();
  }
});

// Form interaction tracking
$('form input, form select, form textarea').on('change', function() {
  const $form = $(this).closest('form');
  let changeCount = $form.data('change-count') || 0;
  $form.data('change-count', ++changeCount);
  
  if (changeCount === 1) {
    $form.data('original-state', $form.serialize());
  }
  
  $form.toggleClass('modified', changeCount > 0);
});

// Check for unsaved changes
$(window).on('beforeunload', function() {
  let hasChanges = false;
  $('form.modified').each(function() {
    if ($(this).data('change-count') > 0) {
      hasChanges = true;
      return false;
    }
  });
  
  if (hasChanges) {
    return 'You have unsaved changes. Are you sure you want to leave?';
  }
});

Caching and Performance

Cache expensive computations and API responses.

Usage Examples:

// Cache computed values
function getElementDimensions($element) {
  let dimensions = $element.data('cached-dimensions');
  
  if (!dimensions) {
    dimensions = {
      width: $element.width(),
      height: $element.height(),
      offset: $element.offset(),
      computed: Date.now()
    };
    $element.data('cached-dimensions', dimensions);
  }
  
  return dimensions;
}

// Cache API responses
function loadUserData(userId) {
  const $userContainer = $('#user-' + userId);
  let userData = $userContainer.data('user-data');
  
  if (!userData) {
    return $.get('/api/users/' + userId).done(function(data) {
      $userContainer.data('user-data', {
        ...data,
        cached: Date.now()
      });
      return data;
    });
  }
  
  // Return cached data as resolved promise
  return $.Deferred().resolve(userData).promise();
}

// Cache invalidation
function invalidateUserCache(userId) {
  $('#user-' + userId).removeData('user-data');
}

// Lazy loading with data caching
$('.lazy-load').on('inview', function() {
  const $element = $(this);
  if ($element.data('loaded')) return;
  
  const url = $element.data('src');
  $element.load(url, function() {
    $element.data('loaded', true);
    $element.data('load-time', Date.now());
  });
});

Component Data Binding

Implement data binding patterns for interactive components.

Usage Examples:

// Simple data binding
function bindData($element, data) {
  $element.data('bound-data', data);
  
  // Update display
  updateDisplay($element);
  
  // Set up watchers
  $element.on('data-change', function(e, key, newValue) {
    const boundData = $element.data('bound-data');
    boundData[key] = newValue;
    updateDisplay($element);
  });
}

function updateDisplay($element) {
  const data = $element.data('bound-data');
  $element.find('[data-bind]').each(function() {
    const key = $(this).attr('data-bind');
    if (data.hasOwnProperty(key)) {
      $(this).text(data[key]);
    }
  });
}

// Usage
const userData = { name: 'John Doe', email: 'john@example.com' };
bindData($('#user-profile'), userData);

// Trigger data change
$('#name-input').on('input', function() {
  const newName = $(this).val();
  $('#user-profile').trigger('data-change', ['name', newName]);
});

// Component factory with data storage
function createCounter($element, initialValue = 0) {
  $element.data('counter-value', initialValue);
  
  $element.html(`
    <button class="decrement">-</button>
    <span class="value">${initialValue}</span>
    <button class="increment">+</button>
  `);
  
  $element.on('click', '.increment', function() {
    let value = $element.data('counter-value');
    $element.data('counter-value', ++value);
    $element.find('.value').text(value);
    $element.trigger('counter:change', [value]);
  });
  
  $element.on('click', '.decrement', function() {
    let value = $element.data('counter-value');
    $element.data('counter-value', --value);
    $element.find('.value').text(value);
    $element.trigger('counter:change', [value]);
  });
  
  return $element;
}

// Create counter components
createCounter($('#counter1'), 5);
createCounter($('#counter2'), 10);

Memory Management

jQuery's data system automatically handles memory cleanup, but understanding the patterns helps optimize performance.

Usage Examples:

// Automatic cleanup when elements are removed via jQuery
$('#temporary-element').data('large-object', { /* large data */ });
$('#temporary-element').remove(); // Data is automatically cleaned up

// Manual cleanup for better control
function cleanupComponent($component) {
  // Clear timers stored in data
  const timers = $component.data('timers') || [];
  timers.forEach(clearInterval);
  
  // Clear event handlers
  $component.off('.component');
  
  // Remove all data
  $component.removeData();
}

// Efficient data sharing between elements
const sharedConfig = { theme: 'dark', locale: 'en' };
$('.component').data('shared-config', sharedConfig); // Same object reference

// Avoid storing DOM elements in data to prevent circular references
// Instead of:
// $element.data('related-element', $otherElement);
// Use:
$element.data('related-element-id', $otherElement.attr('id'));