craftAsyncMethods
Creates async method definitions for use within a craft store, enabling reactive management of asynchronous operations.
Import
typescript
import { craftAsyncMethods } from '@ng-angular-stack/craft';Introduction
craftAsyncMethods integrates multiple asyncMethod() instances into a craft store by:
- Registering async methods as a group with automatic state tracking
- Generating prefixed
setmethods for each async method (e.g.,setMethodName) - Exposing async method state signals (value, status, error, isLoading)
- Supporting both method-based and source-based async method triggering
- Managing async methods with identifiers for parallel execution
- Enabling insertions for extending functionality (persistence, etc.)
Naming Convention
- Async methods are accessible as:
store.methodName - Trigger methods are prefixed:
store.setMethodName(args) - Source-based async methods (bound to sources) do not expose
setmethods
Difference from Mutations
- Async Methods: General-purpose async operations without automatic query coordination
- Mutations: Server data modifications with built-in query synchronization patterns
Use Cases
- Debounced operations: Search, validation, autosave with delay
- Background tasks: Processing, computation without blocking UI
- Third-party APIs: External service calls with status tracking
- Polling: Periodic checks or updates
- Cancellable operations: Long-running tasks with abort capability
Context Access
- Sources: Bind async methods to sources for automatic execution
- Queries: Access query state for conditional logic
- States: Read and react to state changes
- Injections: Access Angular services and dependencies
Store Integration
- Async method state accessible as:
store.methodName.value(),store.methodName.status() - Trigger async methods:
store.setMethodName(args) - With identifier:
store.methodName.select(id)for individual instances - Other craft entries can access async methods for coordination
Signature
ts
function craftAsyncMethods<Context, StoreConfig, AsyncMethods>(
asyncMethodsFactory: (context: CraftFactoryEntries<Context>) => AsyncMethods,
): CraftAsyncMethodsOutputs<Context, StoreConfig, AsyncMethods>;Parameters
asyncMethodsFactory
Factory function that receives the craft context and returns a record of async methods. Has access to all other craft entries (sources, queries, states, injections) defined before it.
Return Value
A craft factory utility that integrates async methods into the store with:
store.methodName: Async method state and signalsstore.setMethodName(args): Method to trigger the async operation (for method-based async methods)- Full type safety for async method parameters and results
Examples
Basic method-based async method
ts
const { injectCraft } = craft(
{ name: '', providedIn: 'root' },
craftAsyncMethods(() => ({
delay: asyncMethod({
method: (delay: number) => delay,
loader: async ({ params }) => {
await new Promise((resolve) => setTimeout(resolve, 500)); // Simulate delay
return 'done';
},
}),
})),
);
const store = injectCraft();
// Trigger manually
store.setDelay(500);
// Track state
console.log(store.delay.status()); // 'loading'
console.log(store.delay.isLoading()); // true
// After completion
console.log(store.delay.status()); // 'resolved'
console.log(store.delay.value()); // 'done'
console.log(store.delay.hasValue()); // trueSource-based async method for automatic execution
ts
const delaySource = source<number>();
const { injectCraft } = craft(
{ name: '', providedIn: 'root' },
craftAsyncMethods(() => ({
delay: asyncMethod({
method: afterRecomputation(delaySource, (term) => term),
loader: async ({ params }) => {
// Debounce at source level
await new Promise((resolve) => setTimeout(resolve, 300));
return 'done';
},
}),
})),
);
const store = injectCraft();
// Triggers automatically when source emits
delaySource.set(500);
// -> delay executes automatically
// No manual method, only source
console.log(store.delay.source); // ReadonlySource<number>
console.log(store.delay.status()); // Current stateAsync method with identifier for parallel operations
ts
const { injectCraft } = craft(
{ name: '', providedIn: 'root' },
craftAsyncMethods(() => ({
delayById: asyncMethod({
method: (id: string) => id,
identifier: (id) => id,
loader: async () => {
await new Promise((resolve) => setTimeout(resolve, 300));
return 'done'; // Simulate delay
},
}),
})),
);
const store = injectCraft();
// Execute multiple operations in parallel
store.setDelayById('id1');
store.setDelayById('id2');
store.setDelayById('id3');
// Access individual states
const delay1 = store.delayById.select('id1');
console.log(delay1?.status()); // 'loading' or 'resolved'
console.log(delay1?.value()); // Result for id1
const delay2 = store.delayById.select('id2');
console.log(delay2?.status()); // Independent stateCalling async js native API
ts
const { injectCraft } = craft(
{ name: '', providedIn: 'root' },
craftAsyncMethods(() => ({
shareContent: asyncMethod(
{
method: (payload: { title: string; url: string }) => payload,
loader: async ({ params }) => {
return navigator.share(params);
},
},
({ resource }) => ({
isMenuOpen: computed(() => resource.status() === 'loading'),
}),
),
})),
);
const store = injectCraft();
// Trigger shareContent
store.setShareContent({ title: 'Hello AI!', url: 'https://example.com' });
console.log(store.shareContent.isMenuOpen()); // true while loadingCraft Utilities
Links to all craft utilities implemented in libs/core/src/lib: