Collections
Backbone.js-style Collections for managing model data
Interactive Examples
Try these examples with your saved connection. If you haven't connected yet, visit the Try It Out page first.
Basic Fetch
Fetch the first page of projects using Collections.
const projects = api.collections.project;
await projects.fetch({ limit: 5 });
console.log('Loaded:', projects.length);
console.log('Has more:', projects.hasMore);
console.log('Projects:', projects.models);
Fast ID Lookup (O(1))
Use the built-in ID index for instant lookups.
const projects = api.collections.project;
await projects.fetch({ limit: 50 });
// O(1) lookup by ID
const project = projects.get(1);
console.log('Found:', project?.name);
// Check if ID exists
console.log('Has ID 1:', projects.has(1));
console.log('Has ID 999:', projects.has(999));
Client-Side Filtering
Filter already-loaded data using where() and filter().
const projects = api.collections.project;
await projects.fetch({ limit: 50 });
// Filter by property
const utcProjects = projects.where({ timezone: 'UTC' });
// Custom filter
const recentProjects = projects.filter(p => {
const created = new Date(p.created_at);
const monthAgo = new Date();
monthAgo.setMonth(monthAgo.getMonth() - 1);
return created > monthAgo;
});
console.log('UTC projects:', utcProjects.length);
console.log('Recent projects:', recentProjects.length);
Pluck - Extract Property
Extract a specific property from all models.
const projects = api.collections.project;
await projects.fetch({ limit: 20 });
// Extract all project names
const names = projects.pluck('name');
console.log('Names:', names);
// Extract all timezones
const timezones = projects.pluck('timezone');
console.log('Timezones:', timezones);
GroupBy - Group by Property
Group models by a property value.
const projects = api.collections.project;
await projects.fetch({ limit: 50 });
// Group by timezone
const byTimezone = projects.groupBy('timezone');
Object.entries(byTimezone).forEach(([tz, projects]) => {
console.log(`${tz}: ${projects.length} projects`);
});
SortBy - Sort Collection
Sort models by a property or function.
const projects = api.collections.project;
await projects.fetch({ limit: 10 });
// Sort by name
const sorted = projects.sortBy('name');
console.log('Sorted:', sorted.map(p => p.name));
// Sort by custom function
const byNameLength = projects.sortBy(p => p.name.length);
console.log('By length:', byNameLength.map(p => p.name));
Pagination - Load More
Fetch additional pages using fetchNext().
const projects = api.collections.project;
// Fetch first page
await projects.fetch({ limit: 5 });
console.log('Page 1:', projects.length);
// Check if more pages exist
if (projects.hasMore) {
// Fetch next page (appends to collection)
await projects.fetchNext();
console.log('After page 2:', projects.length);
}
Why Collections?
Instead of making raw HTTP requests, you work with Collections that:
- Handle pagination automatically - Use
fetch(),fetchNext(), orfetchAll() - Provide fast lookups - O(1) ID-based indexing with
get(id) - Support filtering - Use
where(),filter(),find()for client-side operations - Include metadata - Track
hasMore, pagination state, and more - Offer array methods - Map, filter, reduce, and 50+ utility methods
Available Collections
Access collections through the API instance:
import { initializeSGERP } from 'sgerp-frontend-lib';
const api = initializeSGERP({ /* config */ });
// Access collections
const users = api.collections.user;
const projects = api.collections.project;
const members = api.collections.projectmember;
Currently supported collections:
user- For managing user modelsproject- For managing project modelsprojectmember- For managing project member models
Fetching Data
Collections provide three methods for fetching data:
fetch()
Fetch the first page of models:
// Fetch first 20 projects
await projects.fetch({ limit: 20 });
// Access the models
console.log('Total loaded:', projects.length);
projects.forEach(project => {
console.log(project.name);
});
fetchNext()
Fetch the next page and append to the collection:
// Fetch first page
await projects.fetch({ limit: 20 });
// Check if there are more
if (projects.hasMore) {
// Fetch and append next page
await projects.fetchNext();
console.log('Now have:', projects.length, 'projects');
}
fetchAll()
Fetch all pages automatically:
// Fetch all projects across all pages
await projects.fetchAll();
console.log('Total projects:', projects.length);
Accessing Models
Collections provide multiple ways to access models:
By ID (Index Lookup)
The fastest way to find a model by ID:
await projects.fetch({ limit: 100 });
// Get project with ID 1 (O(1) lookup)
const project = projects.get(1);
if (project) {
console.log('Found:', project.name);
}
// Check if collection has a project
if (projects.has(42)) {
console.log('Project 42 exists');
}
By Position
Access models by array index:
// Get first project
const first = projects.at(0);
// Get last project
const last = projects.at(projects.length - 1);
Direct Array Access
Access the underlying models array:
// Get all models
const allProjects = projects.models;
// Iterate
projects.forEach((project, index) => {
console.log(`${index}: ${project.name}`);
});
// Map
const names = projects.map(p => p.name);
// Filter
const activeProjects = projects.filter(p => !p.is_invalidated);
// Find
const testProject = projects.find(p => p.name.includes('test'));
Managing Collection Data
Add Models
// Add a single model
projects.add(newProject);
// Add multiple models
projects.add([project1, project2, project3]);
// Adding updates the index automatically
const added = projects.get(newProject.id); // Fast lookup
Remove Models
// Remove by ID
projects.remove(42);
// Model is removed from both array and index
console.log(projects.has(42)); // false
Reset Collection
// Replace all models with new ones
projects.reset([project1, project2]);
// Clear the collection
projects.clear();
console.log(projects.length); // 0
Pagination Metadata
Access pagination information:
await projects.fetch({ limit: 20 });
// Check if there are more pages
console.log('Has more:', projects.hasMore);
// Access full metadata
console.log('Meta:', projects.meta);
// {
// has_more: true,
// next: "/api/v2/...",
// next_offset: 20
// }
Complete Example
import { initializeSGERP } from 'sgerp-frontend-lib';
const api = initializeSGERP({
activeConnection: 'admin@staging',
connections: {
'admin@staging': {
id: 'admin@staging',
environment: 'staging',
user: 'admin',
password: 'your-password',
baseUrl: 'https://sgerp-stage.d.gcdev.swatrider.com',
},
},
});
// Access collection
const projects = api.collections.project;
// Fetch first page
await projects.fetch({ limit: 50 });
console.log(`Loaded ${projects.length} projects`);
// Quick lookup by ID
const project = projects.get(1);
if (project) {
console.log('Project 1:', project.name);
}
// Iterate through all
projects.forEach((project, index) => {
console.log(`${index + 1}. ${project.name} (${project.timezone})`);
});
// Load more pages manually
while (projects.hasMore) {
console.log('Loading next page...');
await projects.fetchNext();
}
console.log(`Total projects loaded: ${projects.length}`);
// Or load all at once
const allProjects = api.collections.project;
await allProjects.fetchAll();
console.log(`All projects: ${allProjects.length}`);
// Filter and map
const testProjects = allProjects
.filter(p => p.name.toLowerCase().includes('test'))
.map(p => ({
id: p.id,
name: p.name,
}));
console.log('Test projects:', testProjects);
API Filtering vs Client Filtering
Use API Filters (Recommended)
When searching for specific records, use API filters to reduce data transfer:
const users = api.collections.user;
// ✅ Good - Fetch only matching records from server
await users.fetch({ username: 'admin' } as any);
const user = users.first();
Use Client Filters
When working with already-loaded data or complex conditions:
const users = api.collections.user;
await users.fetch({ limit: 100 });
// ✅ Good - Data already loaded, filter in memory
const activeStaff = users.filter(u => u.is_active && u.is_staff);
Underscore.js-Style Methods (Client-Side)
Collections include powerful underscore.js-style methods for data manipulation:
Property Extraction
const projects = api.collections.project;
await projects.fetch({ limit: 100 });
// Extract all names
const names = projects.pluck('name');
// ['Project A', 'Project B', 'Project C']
// Extract all timezones
const timezones = projects.pluck('timezone');
Filtering & Finding (Client-Side)
// Find all projects with a specific timezone (client-side filter)
const utcProjects = projects.where({ timezone: 'UTC' });
// Find the first project with a specific timezone (client-side)
const firstUtc = projects.findWhere({ timezone: 'UTC' });
// Reject invalidated projects (client-side)
const active = projects.reject(p => p.is_invalidated);
Note: These filter already-loaded data. For server-side filtering, use API filters in fetch().
Sorting & Grouping
// Sort by name
const sorted = projects.sortBy('name');
// Sort by custom function
const byLength = projects.sortBy(p => p.name.length);
// Group by timezone
const byTimezone = projects.groupBy('timezone');
// { 'UTC': [...], 'America/New_York': [...] }
// Count by timezone
const counts = projects.countBy('timezone');
// { 'UTC': 10, 'America/New_York': 5 }
// Index by name for fast lookup
const byName = projects.indexBy('name');
// { 'Project A': {...}, 'Project B': {...} }
Collection Utilities
// Split into active and inactive
const [active, inactive] = projects.partition(p => !p.is_invalidated);
// Get random project(s)
const random = projects.sample(); // One random
const randomThree = projects.sample(3); // Three random
// Shuffle all projects
const shuffled = projects.shuffle();
// Get first/last
const first = projects.first();
const firstFive = projects.first(5);
const last = projects.last();
// Exclude specific IDs
const filtered = projects.without(1, 2, 3);
// Get min/max
const oldest = projects.min('created_at');
const newest = projects.max('created_at');
Testing & Checking
// Check if empty
if (projects.isEmpty()) {
console.log('No projects');
}
// Test all
const allActive = projects.every(p => !p.is_invalidated);
// Test any
const hasUtc = projects.some(p => p.timezone === 'UTC');
// Contains
const hasTest = projects.contains(p => p.name.includes('test'));
Advanced Operations
// Reduce to a value
const totalProjects = projects.reduce((sum, p) => sum + 1, 0);
// Get unique (remove duplicates)
const unique = projects.uniq();
// Initial/Rest (slice operations)
const allButLast = projects.initial(1);
const allButFirst = projects.rest(1);
Collection Methods Reference
Data Access
models- Get all models arraylength- Number of models in collectionget(id)- Get model by ID (O(1) lookup)at(index)- Get model at array indexhas(id)- Check if model exists by IDtoArray()- Convert to plain arraytoJSON()- Convert to JSON
Basic Iteration
forEach(callback)- Iterate over modelsmap(callback)- Map over modelsfilter(callback)- Filter modelsfind(callback)- Find first matching model
Underscore.js-Style Methods
pluck(key)- Extract property from all modelswhere(properties)- Filter by matching propertiesfindWhere(properties)- Find first by matching propertiessortBy(iteratee)- Sort by property or functiongroupBy(iteratee)- Group by property or functioncountBy(iteratee)- Count by property or functionindexBy(iteratee)- Index by property or functionpartition(predicate)- Split into [matches, non-matches]sample(n?)- Get random model(s)shuffle()- Shuffle modelsfirst(n?)- Get first n modelslast(n?)- Get last n modelsinitial(n)- All except last nrest(n)- All except first nwithout(...ids)- Exclude models by IDreject(predicate)- Opposite of filterevery(predicate)- Test if all passsome(predicate)- Test if any passcontains(predicate)- Check if any matchmax(iteratee)- Find max by property/functionmin(iteratee)- Find min by property/functionreduce(callback, initial)- Reduce to valueuniq()- Remove duplicatesisEmpty()- Check if emptysize()- Get collection size
Data Management
add(model | models)- Add model(s) to collectionremove(id)- Remove model by IDreset(models)- Replace all modelsclear()- Remove all models
Fetching
fetch(params, config)- Fetch first pagefetchNext(config)- Fetch and append next pagefetchAll(config)- Fetch all pages
Pagination
hasMore- Boolean indicating if more pages existmeta- Full pagination metadata