ngssm-data
April 8, 2026 ยท View on GitHub
A comprehensive Angular library for managing remote and computed data with built-in caching, state management, and dependency handling. Part of the ng-simple-state-management framework.
Overview
ngssm-data provides a robust abstraction layer for handling asynchronous data operations in Angular applications. It integrates seamlessly with the ngssm-store for centralized state management and offers powerful features like:
- Data Source Registration: Define and register data sources with automatic state management
- Caching with TTL: Automatic cache invalidation based on configurable lifetime
- Dependency Management: Automatically load dependent data sources in the correct order
- Data Linking: Establish relationships between data sources with automatic reloading
- Additional Properties: Load supplementary data independently (e.g., row details in tables)
- Parameter Management: Handle dynamic parameters for data loading with validation
- Signal Integration: Convert data sources to Angular Signals for reactive UI updates
- Auto-Reload Functionality: Built-in components and directives for automatic data refresh
- Post-Loading Actions: Execute custom logic after data loads
- Scoped Data Sources: Register data sources with component lifecycle management
Installation
npm install ngssm-data
Peer Dependencies
@angular/core>= 20.0.0@angular/common>= 20.0.0ngssm-store>= 18.0.0luxon>= 3.4.4
Core Concepts
Data Source
A NgssmDataSource<TData, TParameter, TAdditionalProperty> defines how to fetch and manage a piece of data:
interface NgssmDataSource<TData = unknown, TParameter = unknown, TAdditionalProperty = unknown> {
key: string; // Unique identifier
dataLifetimeInSeconds?: number; // Cache TTL
dataLoadingFunc: NgssmDataLoading<TData, TParameter>; // Main data loader
additionalPropertyLoadingFunc?: NgssmAdditionalPropertyLoading<TAdditionalProperty>;
initialParameter?: TParameter; // Parameter passed on first load
initialParameterInvalid?: boolean; // Flag to mark initial parameter as invalid
linkedToDataSource?: string; // Reload when this source updates
linkedDataSources?: string[]; // Sources to reload when this updates
dependsOnDataSource?: string; // Load this first before loading current source
}
Data Loading Function
A function that retrieves data from a remote service or computes it locally:
type NgssmDataLoading<TData = unknown, TParameter = unknown> = (
state: State,
dataSourceKey: string,
parameter?: TParameter
) => Observable<TData>;
Data Source Value
The state representation of loaded data:
interface NgssmDataSourceValue<TData = unknown, TParameter = unknown> {
value?: TData; // The actual data
status: NgssmDataSourceValueStatus; // 'NOT_LOADED' | 'LOADING' | 'LOADED' | 'LOAD_ERROR'
parameter?: TParameter; // Current parameter
parameterInvalid?: boolean; // Whether parameter is valid
lastLoad?: DateTime; // When data was last loaded
loadError?: Error; // Load error if status is LOAD_ERROR
additionalProperties?: Record<string, unknown>; // Additional loaded properties
}
Setup
Global Provider
Initialize ngssm-data with automatic effect management and data source registration:
import { provideNgssmData } from 'ngssm-data';
bootstrapApplication(AppComponent, {
providers: [
provideNgssmStore(),
provideNgssmData(),
]
});
Register Data Sources
Register data sources using the provideNgssmDataSource helper function:
import { provideNgssmDataSource } from 'ngssm-data';
const usersLoader: NgssmDataLoading<User[]> = (state, key, parameter) =>
inject(UserService).getUsers(parameter);
const userDetailsLoader: NgssmDataLoading<UserDetail> = (state, key, userId) =>
inject(UserService).getUserDetails(userId);
bootstrapApplication(AppComponent, {
providers: [
provideNgssmStore(),
provideNgssmData(),
provideNgssmDataSource('users', usersLoader, { dataLifetimeInSeconds: 300 }),
provideNgssmDataSource('user-details', userDetailsLoader, { initialParameter: 'default-user-id' })
]
});
The provideNgssmDataSource function accepts:
key: Unique identifier for the data sourceloadingFunc: Function that retrieves the dataoptions: Optional configuration including:dataLifetimeInSeconds: Cache TTLinitialParameter: Parameter used on first loadinitialParameterInvalid: Mark initial parameter as invalidlinkedToDataSource: Reload when another source updateslinkedDataSources: Sources to reload when this updatesdependsOnDataSource: Load this source first before loading currentadditionalPropertyLoadingFunc: Function to load additional propertiesonLoaded: Callback run after successful value load (in DI context)onLoadError: Callback run after failed load (in DI context)
Callback example
provideNgssmDataSource('users', usersLoader, {
onLoaded: (state, key, parameter, value) => {
const audit = inject(AuditService);
audit.trackLoadSuccess(key, parameter, value);
},
onLoadError: (state, key, parameter, error) => {
const audit = inject(AuditService);
audit.trackLoadFailure(key, parameter, error);
}
});
Usage
Loading Data
Dispatch actions to load data sources:
import { Store } from 'ngssm-store';
import { NgssmLoadDataSourceValueAction } from 'ngssm-data';
export class MyComponent implements OnInit {
private store = inject(Store);
ngOnInit() {
this.store.dispatchAction(
new NgssmLoadDataSourceValueAction('users')
);
}
}
Accessing Data via Signals
Convert data source state to reactive signals:
import { dataSourceToSignal } from 'ngssm-data';
export class MyComponent {
private usersSignal = dataSourceToSignal<User[]>('users');
protected users = this.usersSignal.value;
// Access specific properties
protected usersStatus = dataSourceToSignal('users', { type: 'status' }).value;
protected usersParameter = dataSourceToSignal('users', { type: 'parameter' }).value;
}
Scoped Data Sources
Register data sources with component lifecycle:
import { NgssmScopedDataSourceDirective } from 'ngssm-data';
@Component({
selector: 'app-user-list',
template: `<div [ngssmScopedDataSource]="dataSource">...</div>`,
imports: [NgssmScopedDataSourceDirective]
})
export class UserListComponent {
protected dataSource: NgssmDataSource = {
key: 'users',
dataLoadingFunc: () => inject(UserService).getUsers()
};
}
Auto-Reload
Use the auto-reload component for automatic periodic refresh:
import { NgssmAutoReloadComponent } from 'ngssm-data';
@Component({
template: `
<ngssm-auto-reload
[key]="'users'"
[intervalSeconds]="60">
</ngssm-auto-reload>
`,
imports: [NgssmAutoReloadComponent]
})
export class MyComponent {}
Setting Parameters
Update data source parameters for dynamic loading:
import { NgssmSetDataSourceParameterAction } from 'ngssm-data';
this.store.dispatchAction(
new NgssmSetDataSourceParameterAction('users', { page: 2, limit: 20 })
);
Loading Additional Properties
Load supplementary data independently:
import { NgssmLoadDataSourceAdditionalPropertyValueAction } from 'ngssm-data';
this.store.dispatchAction(
new NgssmLoadDataSourceAdditionalPropertyValueAction('users', 'user-roles')
);
Checking Load Status
Use the status pipe to check loading state:
import { isNgssmDataSourceValueStatusPipe } from 'ngssm-data';
@Component({
template: `
<div *ngIf="(usersSignal.value | isNgssmDataSourceValueStatus: 'LOADED')">
Users loaded
</div>
`
})
export class MyComponent {}
Advanced Features
Data Dependencies
Automatically load dependent data sources:
const dataSources: NgssmDataSource[] = [
{
key: 'users',
dataLoadingFunc: () => inject(UserService).getUsers()
},
{
key: 'user-roles',
dependsOnDataSource: 'users', // Load 'users' first
dataLoadingFunc: () => inject(RoleService).getRoles()
}
];
Data Linking
Automatically reload related data sources:
const dataSources: NgssmDataSource[] = [
{
key: 'users',
dataLoadingFunc: () => inject(UserService).getUsers(),
linkedDataSources: ['user-stats'] // Reload stats when users change
},
{
key: 'user-stats',
dataLoadingFunc: () => inject(StatsService).getUserStats()
}
];
Post-Loading Actions
Execute custom logic after data loads:
import { POST_LOADING_ACTIONS } from 'ngssm-data';
bootstrapApplication(AppComponent, {
providers: [
{
provide: POST_LOADING_ACTIONS,
useValue: {
'users': [
(state: State, dataSourceKey: string) => {
// Custom logic after 'users' loads
console.log('Users data loaded');
}
]
},
multi: true
}
]
});
Actions
Common actions for data management:
NgssmLoadDataSourceValueAction(key, parameter?)- Load dataNgssmSetDataSourceParameterAction(key, parameter)- Update parameterNgssmSetDataSourceParameterValidityAction(key, valid)- Mark parameter validityNgssmLoadDataSourceAdditionalPropertyValueAction(key, property)- Load additional propertyNgssmClearDataSourceValueAction(key)- Clear cached dataNgssmRegisterDataSourceAction(dataSource)- Register single sourceNgssmRegisterDataSourcesAction(dataSources)- Register multiple sourcesNgssmUnregisterDataSourceAction(key)- Unregister source
API Reference
Selectors
// Select entire data state
selectNgssmDataState(state: State): NgssmDataState
// Select specific data source value
selectNgssmDataSourceValue<T>(state: State, key: string): NgssmDataSourceValue<T> | undefined
// Select value only
selectNgssmDataSourceValue(state).value
// Select status only
selectNgssmDataSourceValue(state).status
// Select parameter
selectNgssmDataSourceValue(state).parameter
Components & Directives
NgssmAutoReloadComponent- Automatic periodic data reloadNgssmDataReloadButtonComponent- Manual reload button with loading stateNgssmScopedDataSourceDirective- Register data sources with component lifecycle
Utilities
dataSourceToSignal(key, options?)- Convert to Signal for reactive updatespostLoadingActionExecutor- Execute post-load hooksdataSourcesLinker- Manage data source relationships
Best Practices
- Use TTL for Caching: Set
dataLifetimeInSecondsfor frequently accessed data to reduce API calls - Type Your Data: Always provide generic types for
NgssmDataSource<TData, TParameter> - Leverage Signals: Use
dataSourceToSignalfor reactive components instead of subscriptions - Dependency Resolution: Use
dependsOnDataSourceto ensure proper load order - Scoped Registration: Use
NgssmScopedDataSourceDirectivefor component-specific data sources - Error Handling: Monitor the
LOAD_ERRORstatus and implement retry logic - Parameter Validation: Use
NgssmSetDataSourceParameterValidityActionbefore loading with new parameters
Dependencies
- Built on ngssm-store for state management
- Uses Luxon for datetime handling
- Integrates with Angular's dependency injection and Signal system
License
MIT