NotesApp version 0.0.0
This project has been migrated to Angular 21 with standalone components and Signal Store for state management.
NotesApp is a demo note managing application that demonstrates modern Angular development practices including:
- Angular 21 with standalone components (no NgModules)
- Angular Material for UI components
- Tailwind CSS for utility-first styling
- Native CSS Animations for smooth transitions (replacing deprecated Angular animations)
- Angular Signal Forms for reactive form handling
- TypeScript 5.9 for type safety
- RxJS 7.8 for reactive programming
- NgRx Signal Store for signal-based state management
- Facade Pattern for clean API abstraction
- Express and json-server for the REST API backend
The application was originally based on NgRx (with NgRx Data) but has been modernized to use NgRx Signal Store, Angular's new signal-based state management solution.
- ✅ Angular 21 - Latest Angular version with standalone components
- ✅ Signal Store - Modern signal-based state management (replacing NgRx Store)
- ✅ Standalone Components - No NgModules, all components are standalone by default
- ✅ Signal-based APIs - Using
input(),output(), andviewChild()signals - ✅ Angular Signal Forms - Modern reactive forms with signal-based validation
- ✅ Tailwind CSS - Utility-first CSS framework for rapid UI development
- ✅ Native CSS Animations - Using CSS Grid transitions instead of deprecated Angular animations
- ✅ Facade Pattern - Clean API layer for components to interact with stores
- ✅ TypeScript 5.9 - Latest TypeScript features
- ✅ Angular Material 21 - Material Design components
- ✅ Signal-based Reactivity - No async pipes needed, direct signal access
- ✅ Modern Dependency Injection - Using
inject()function instead of constructor injection
This project requires Node.js version 20.19.0, 22.12.0, or 24.0.0+.
To check your Node.js version:
node -vIf you need to update Node.js, we recommend using a node version manager:
- Windows: nvm-windows
- macOS/Linux: nvm
Install the Angular CLI globally:
npm install -g @angular/cliVerify installation:
ng version- Clone the repository:
git clone https://github.com/vtsitlak/notes-app.git
cd notes-app- Install dependencies:
npm installIf you encounter peer dependency conflicts, you may need to use:
npm install --legacy-peer-depsIn one terminal, start the REST API server:
npm run serverThis starts a Node.js Express server with json-server at http://localhost:3000.
In another terminal, start the Angular development server:
npm startThe application will be available at http://localhost:4200.
The npm start command uses a proxy configuration (proxy.json) to forward API requests to the backend server.
src/app/
├── app.component.ts # Root component (standalone)
├── app.config.ts # Application configuration (providers)
├── app.routes.ts # Route definitions
├── auth/
│ ├── store/
│ │ ├── auth.store.ts # Signal Store for authentication
│ │ ├── auth.service.ts # Authentication HTTP service
│ │ └── auth.facade.ts # Facade for auth store
│ ├── auth.guard.ts # Route guard using AuthFacade
│ ├── login/ # Login component (uses Signal Forms)
│ └── model/ # User model
└── notes/
├── store/
│ ├── notes.store.ts # Signal Store for notes
│ ├── notes-http.service.ts # HTTP service for notes
│ └── notes.facade.ts # Facade for notes store
├── home/ # Home component (standalone)
├── notes-table-list/ # Notes table component (uses signal inputs/outputs)
├── edit-note-dialog/ # Edit note dialog (uses Signal Forms)
├── shared/ # Shared utilities
└── model/ # Note model
All components are standalone by default (no standalone: true needed in Angular 21). Each component imports its own dependencies:
@Component({
selector: 'app-example',
imports: [MatButton, MatIcon],
// ...
})Components use modern signal-based APIs instead of decorators:
export class ExampleComponent {
// Signal inputs/outputs instead of @Input/@Output
data = input<string>();
change = output<void>();
// Signal viewChild instead of @ViewChild
paginator = viewChild(MatPaginator);
// inject() instead of constructor injection
private service = inject(ExampleService);
}Forms use Angular's new Signal Forms API:
import { form, FormField, required } from '@angular/forms/signals';
loginModel = signal({ email: '', password: '' });
loginForm = form(this.loginModel, (schemaPath) => {
required(schemaPath.email, { message: 'Email is required' });
required(schemaPath.password, { message: 'Password is required' });
});The application uses NgRx Signal Store for state management with a Facade Pattern for clean API abstraction:
- Manages user authentication state
- Methods:
login(),logout(),setUser() - Computed signals:
isLoggedIn(),isLoggedOut() - Accessed via
AuthFacadein components
- Manages notes collection
- Methods:
loadAll(),update(),add(),delete() - Computed signals:
importantNotes() - State signals:
notes(),loading(),loaded() - Accessed via
NotesFacadein components
Facades provide a clean API layer for components:
// Components use facades instead of accessing stores directly
export class NotesFacade {
private readonly store = inject(NotesStore);
readonly notes = this.store.notes;
readonly loading = this.store.loading;
loadAll(): void {
this.store.loadAll();
}
delete(noteId: string | number): void {
this.store.delete(noteId);
}
}The app.config.ts file contains all application-level providers:
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideAnimations(),
provideHttpClient()
]
};The application uses Tailwind CSS for utility-first styling:
- Tailwind CSS 4.0 - Modern utility-first CSS framework
- PostCSS - CSS processing with Tailwind plugin
- Material Integration - Tailwind configured to work alongside Angular Material
- Native CSS Animations - CSS Grid-based transitions for smooth animations
Styles are primarily applied using Tailwind utility classes in templates, with minimal component-specific SCSS for Material overrides.
The main.ts file bootstraps the application:
bootstrapApplication(AppComponent, appConfig)
.catch(err => console.error(err));ng buildng build --configuration productionBuild artifacts will be stored in the dist/ directory.
Run unit tests via Karma:
npm test
# or
ng testThe project includes comprehensive unit tests for all components, services, facades, and guards:
-
Component Tests: All components have corresponding
.spec.tsfiles using Angular 21 testing patternsapp.component.spec.ts- Root component testsauth/login/login.component.spec.ts- Login component with Signal Forms testsnotes/home/home.component.spec.ts- Home component testsnotes/notes-table-list/notes-table-list.component.spec.ts- Notes table component testsnotes/edit-note-dialog/edit-note-dialog.component.spec.ts- Edit dialog component tests
-
Service Tests: HTTP services are tested with
HttpTestingControllerauth/store/auth.service.spec.ts- Authentication service testsnotes/store/notes-http.service.spec.ts- Notes HTTP service tests
-
Facade Tests: Facades are tested with spy objects
auth/store/auth.facade.spec.ts- Auth facade testsnotes/store/notes.facade.spec.ts- Notes facade tests
-
Guard Tests: Route guards are tested
auth/auth.guard.spec.ts- Authentication guard tests
All tests use:
TestBed.configureTestingModulewith standalone component importsprovideRouter()andprovideAnimations()for providers- Jasmine spy objects for mocking dependencies
- Signal-based testing patterns for Angular 21
Run e2e tests:
npm run e2e
# or
ng e2e@angular/core: ^21.0.0@angular/router: ^21.0.0@angular/material: ^21.0.0@angular/forms: ^21.0.0 (includes Signal Forms)@ngrx/signals: ^21.0.1rxjs: ^7.8.1typescript: ~5.9.0zone.js: ^0.15.0
@angular/cli: ^21.0.0@angular-devkit/build-angular: ^21.0.0tailwindcss: ^4.0.0@tailwindcss/postcss: ^4.0.0postcss: ^8.4.47autoprefixer: ^10.4.20karma: ^6.4.4karma-coverage: ^2.2.1karma-jasmine: ^5.1.0karma-jasmine-html-reporter: ^2.1.0karma-chrome-launcher: ^3.2.0jasmine-core: ^5.4.0@types/jasmine: ^5.1.4
This project was migrated from:
- Angular 8 → Angular 21
- NgModules → Standalone Components
- NgRx Store → NgRx Signal Store
- Observables with async pipe → Signals
- Reactive Forms → Signal Forms
- @Input/@Output → input()/output()
- @ViewChild → viewChild()
- Constructor injection → inject()
- Angular Animations → Native CSS Animations
- Custom CSS → Tailwind CSS
- Removed NgModules: All
@NgModuledecorators removed, components are now standalone by default - Signal Store: Replaced NgRx Store/Effects with Signal Store for simpler, signal-based state management
- Facade Pattern: Introduced facades (
AuthFacade,NotesFacade) for clean API abstraction - Signal-based APIs: Migrated to
input(),output(), andviewChild()signals - Signal Forms: Replaced Reactive Forms with Angular Signal Forms
- Dependency Injection: Using
inject()function instead of constructor injection - Native CSS Animations: Replaced deprecated Angular animations with CSS Grid-based transitions
- Tailwind CSS: Integrated Tailwind CSS 4.0 for utility-first styling
- Direct Signal Access: Components access state directly via signals instead of observables
- Simplified Configuration: Removed NgRx Store, Effects, Router Store, and Entity Data providers
- Modern Control Flow: Using
@if,@forinstead of*ngIf,*ngFor - CRUD Operations: Added delete functionality to complete CRUD operations
If you see errors about Node.js version, ensure you're using Node.js 20.19.0, 22.12.0, or 24.0.0+.
If installation fails due to peer dependencies:
npm install --legacy-peer-depsIf port 4200 is already in use:
ng serve --port 4201- Angular Documentation
- NgRx Signals Documentation
- Angular Material Documentation
- Angular CLI Documentation
This project is for educational purposes.