@ali7040/ng-signal-query
v0.0.2
Published
[](https://www.npmjs.com/package/@ali7040/ng-signal-query) [](https://github.com/
Readme
🎯 ng-signal-query
A powerful, type-safe querying library for Angular applications built with signals. Manage server state, infinite queries, mutations, and caching with elegance and performance.
✨ Features
- 🚀 Signal-Driven Architecture - Leverage Angular signals for reactive state management
- 🔄 Server State Management - Queries, mutations, and automatic caching
- ∞ Infinite Queries - Seamless pagination with automatic data accumulation
- 🎯 Type-Safe - Full TypeScript support with strict typing
- 🛠️ DevTools Integration - Built-in debugging component for development
- 📦 Lightweight - Minimal bundle size with zero external dependencies (except Angular & RxJS)
- 🔌 Adapter Pattern - Custom adapters for different HTTP clients
- 💾 Smart Caching - Automatic query result caching with configurable strategies
- 🌐 SSR Ready - Server-side rendering support with hydration
📦 Installation
npm install @ali7040/ng-signal-queryOr with yarn:
yarn add @ali7040/ng-signal-queryOr with pnpm:
pnpm add @ali7040/ng-signal-query🐙 GitHub Packages
You can also publish/install this package from GitHub Packages.
Publish to GitHub Packages
- Create a GitHub Personal Access Token (classic) with:
write:packagesread:packagesrepo(only if repository is private)
- Login to GitHub npm registry:
npm login --scope=@ali7040 --auth-type=legacy --registry=https://npm.pkg.github.com- Publish:
npm run release:githubInstall from GitHub Packages
npm install @ali7040/ng-signal-query --registry=https://npm.pkg.github.comRequirements
- Angular >= 21.1.0
- TypeScript >= 5.9
- RxJS >= 7.8
🚀 Quick Start
1. Import the Module
import { QueryClient } from '@ali7040/ng-signal-query';
@Component({
selector: 'app-root',
template: `
<div *ngIf="users(); else loading">
<div *ngFor="let user of users()">{{ user.name }}</div>
</div>
<ng-template #loading>Loading...</ng-template>
`,
standalone: true,
})
export class AppComponent {
private queryClient = inject(QueryClient);
users = this.queryClient.createQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json()),
});
}2. Create Queries
// Simple query
const users = this.queryClient.createQuery({
queryKey: ['users'],
queryFn: () => this.http.get('/api/users'),
staleTime: 5 * 60 * 1000, // 5 minutes
});
// Parametized query
const user = signal('1');
const userDetails = this.queryClient.createSignalQuery({
queryKey: computed(() => ['user', user()]),
queryFn: async () => this.http.get(`/api/users/${user()}`),
});3. Create Mutations
const createUser = this.queryClient.createMutation({
mutationFn: (data: User) => this.http.post('/api/users', data),
onSuccess: () => {
this.queryClient.invalidateQueries(['users']);
},
});
// Use in template
<button (click)="createUser.mutate({ name: 'John' })">
{{ createUser.status() === 'pending' ? 'Creating...' : 'Create User' }}
</button>4. Infinite Queries
const infiniteUsers = this.queryClient.createInfiniteQuery({
queryKey: ['users', 'infinite'],
queryFn: ({ pageParam = 0 }) =>
this.http.get(`/api/users?page=${pageParam}`),
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
// Load more
<button (click)="infiniteUsers.fetchNextPage()">
Load More
</button>📚 API Documentation
QueryClient
Main service for managing all queries and mutations.
// Create a query
createQuery(options: CreateQueryOptions)
// Create a signal-based query
createSignalQuery(options: CreateSignalQuery)
// Create an infinite query
createInfiniteQuery(options: CreateInfiniteQueryOptions)
// Create a mutation
createMutation(options: CreateMutationOptions)
// Invalidate queries
invalidateQueries(queryKey: QueryKey)
// Refetch queries
refetchQueries(queryKey: QueryKey)
// Clear all caches
clearCache()Query State
interface QueryState {
data: TData | null;
error: Error | null;
status: 'pending' | 'error' | 'success';
isLoading: boolean;
isError: boolean;
isSuccess: boolean;
}Mutation State
interface MutationState {
data: TData | null;
error: Error | null;
status: 'idle' | 'pending' | 'error' | 'success';
isPending: boolean;
isError: boolean;
isSuccess: boolean;
}🔧 Development
Building
npm run buildRunning Tests
npm run testRunning Examples
npm run startBrowse to http://localhost:4200
🛠️ Examples
Check the examples directory for complete working examples:
📖 DevTools
Monitor your queries and mutations in real-time:
import { SignalQueryDevtoolsComponent } from '@ali7040/ng-signal-query';
@Component({
selector: 'app-root',
template: `
<app-main></app-main>
<signal-query-devtools *ngIf="isDev"></signal-query-devtools>
`,
imports: [SignalQueryDevtoolsComponent],
})
export class AppComponent {
isDev = !environment.production;
}🚀 Live Testing
Try the library in action:
- StackBlitz Demo: [Coming Soon]
- CodeSandbox: [Coming Soon]
- Documentation: https://github.com/ali7040/ng-signal-query
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for detailed instructions.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with Angular 21.1
- Inspired by TanStack Query
- Type-safe with TypeScript 5.9
📮 Support
❤️ Sponsor
If you want to support this project, you can sponsor ongoing development:
🔗 Useful Links
Made with ❤️ by Ali
Running end-to-end tests
For end-to-end (e2e) testing, run:
ng e2eAngular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the Angular CLI Overview and Command Reference page.
