Skip to content

Ext JS Data Package — Models, Stores, Proxies, and Data Binding

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Ext JS Data Package. We cover key concepts, practical examples, and best practices to help you master this topic.

Ext JS data package provides a complete data management layer with Models (data schema), Stores (data collections), Proxies (server communication), and associated data binding to UI components.

What You'll Learn

  • Defining Models with fields, types, and validators
  • Working with Stores for client-side data management
  • Configuring Proxies for REST API communication
  • Sorting, filtering, and grouping data
  • Binding Stores to grids, forms, and charts

Why It Matters

Separating data logic from UI components makes applications maintainable and testable. The data package handles CRUD operations, data synchronization, and client-side Caching, so your UI components focus on presentation.

Real-World Use

An order management system where Orders are Models, an OrderStore loads from a REST API with pagination, and multiple grids and forms bind to the same Store — ensuring data consistency across the UI.

Data Architecture

flowchart LR
    A[Model] --> B[Store]
    B --> C[Proxy]
    C --> D[Server]
    D --> C
    C --> B
    B --> E[Grid]
    B --> F[Form]
    B --> G[Chart]
    style B fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px

Defining Models

Ext.define('MyApp.model.Product', {
  extend: 'Ext.data.Model',
  fields: [
    { name: 'id', type: 'int' },
    { name: 'name', type: 'string' },
    { name: 'price', type: 'float' },
    { name: 'category', type: 'string' },
    { name: 'inStock', type: 'boolean', defaultValue: true },
    { name: 'createdAt', type: 'date', dateFormat: 'Y-m-d' },
    { name: 'rating', type: 'float', persist: false } // Not saved to server
  ],
  validators: {
    name: { type: 'presence', message: 'Product name is required' },
    price: [
      { type: 'presence', message: 'Price is required' },
      { type: 'range', min: 0.01, message: 'Price must be positive' }
    ]
  }
});

// Create model instance
var product = Ext.create('MyApp.model.Product', {
  name: 'Laptop',
  price: 999.99,
  category: 'Electronics',
  inStock: true
});

console.log(product.get('name'));  // Output: Laptop
console.log(product.get('price')); // Output: 999.99

Expected output: Models define the data schema with typed fields, default values, and validation rules. Instances use get/set methods.

Working with Stores

Ext.define('MyApp.store.Products', {
  extend: 'Ext.data.Store',
  model: 'MyApp.model.Product',
  autoLoad: true,
  pageSize: 20,

  proxy: {
    type: 'ajax',
    url: '/api/products',
    reader: {
      type: 'json',
      rootProperty: 'data',
      totalProperty: 'total'
    },
    writer: {
      type: 'json',
      writeAllFields: true
    }
  },

  sorters: [{
    property: 'name',
    direction: 'ASC'
  }],

  filters: [{
    property: 'inStock',
    value: true
  }]
});

// Using the store
var store = Ext.create('MyApp.store.Products');
store.load(function(records, operation, success) {
  console.log('Loaded ' + records.length + ' products');
});

CRUD Operations

// Create
var product = Ext.create('MyApp.model.Product', {
  name: 'New Product',
  price: 49.99
});
store.add(product);
store.sync(); // Saves to server via proxy

// Read
store.load({
  params: { category: 'Electronics' },
  callback: function(records) {
    records.forEach(function(r) {
      console.log(r.get('name'));
    });
  }
});

// Update
var first = store.first();
first.set('price', 39.99);
first.save(); // Or store.sync()

// Delete
store.remove(first);
store.sync();

Sorting and Filtering

// Client-side sorting
store.sort('price', 'DESC');
store.sort([
  { property: 'category', direction: 'ASC' },
  { property: 'price', direction: 'DESC' }
]);

// Client-side filtering
store.filter('inStock', true);
store.filter([
  { property: 'category', value: 'Electronics' },
  { property: 'price', operator: 'lt', value: 100 }
]);

// Clear filters
store.clearFilter();
store.filterBy(function(record) {
  return record.get('price') > 50 && record.get('rating') >= 4;
});

// Get filtered records
var filtered = store.getFilteredRecords();

Proxies and Readers

// AJAX Proxy
Ext.create('Ext.data.Store', {
  proxy: {
    type: 'ajax',
    url: '/api/data',
    reader: 'json',
    writer: 'json'
  }
});

// REST Proxy
Ext.create('Ext.data.Store', {
  proxy: {
    type: 'rest',
    url: '/api/users',
    format: 'json',
    reader: {
      type: 'json',
      rootProperty: 'data'
    },
    writer: {
      type: 'json',
      writeAllFields: false
    }
  }
});

// Local Storage Proxy
Ext.create('Ext.data.Store', {
  proxy: {
    type: 'localstorage',
    id: 'myLocalStore'
  }
});

// Memory Proxy
Ext.create('Ext.data.Store', {
  data: [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
  ],
  proxy: {
    type: 'memory',
    reader: 'json'
  }
});

Associations

Ext.define('MyApp.model.Order', {
  extend: 'Ext.data.Model',
  fields: ['id', 'date', 'customerId'],
  hasMany: {
    model: 'MyApp.model.OrderItem',
    name: 'items',
    foreignKey: 'orderId'
  },
  belongsTo: {
    model: 'MyApp.model.Customer',
    name: 'customer',
    foreignKey: 'customerId'
  }
});

// Load associated data
order.items().load(function(items) {
  items.forEach(function(item) {
    console.log(item.get('productName'), item.get('quantity'));
  });
});

Common Mistakes

  1. Forgetting to set rootProperty in reader - JSON responses need a rootProperty that matches the data array key. Without it, Ext JS cannot find the records.

  2. Not calling sync() after modifications - Adding, updating, or removing records modifies the Store locally. Call sync() to persist changes to the server.

  3. Using autoLoad without error handling - autoLoad fires immediately. Handle errors with a load listener or callback.

  4. Model field type mismatches - Stores may reject records with wrong field types. Ensure server data types match Model field type definitions.

  5. Not using pageSize for large datasets - Loading thousands of records at once slows rendering. Use pagination with pageSize and server-side paging.

Practice Questions

  1. What are the three core classes of the Ext JS data package?
  2. How do you save changes made to a Store to the server?
  3. What is the difference between sorters and filters?
  4. How does a REST proxy determine the URL for each CRUD operation?
  5. What is the purpose of the rootProperty in a reader?

Challenge: Build a product catalog with a Store connected to a REST API, a Grid panel that displays products with sorting and filtering, and a Form panel that creates and edits products. All CRUD operations should sync with the server.

FAQ

Can a Store use multiple Proxies?

No, each Store has one Proxy. For multiple data sources, use multiple Stores or switch the proxy at runtime.

How do I handle nested JSON data?

Use associations (hasMany, belongsTo) and configure the reader with the appropriate rootProperty for nested data structures.

What is the difference between load and reload?

load() loads data for the first time. reload() re-loads with the same parameters. Both use the proxy to fetch data.

Can I use WebSockets with Ext JS data package?

Yes, implement a custom proxy that uses WebSocket instead of HTTP. Ext JS proxies are extensible.

How does Ext JS handle record IDs?

Each record must have a unique idProperty (default: 'id'). The Store uses IDs to track, update, and remove records.

Mini Project

Build an order management system with: Customer and Order models with associations, a Store with REST proxy for each, a grid that displays customer orders, and a detail panel that shows order items with inline editing.

What's Next

Data needs display. Learn how Ext JS Grid panels visualize Store data with columns, editors, and advanced features.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro