Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/manthanank/angular-signals
Angular Signals Examples
https://github.com/manthanank/angular-signals
angular signals
Last synced: about 6 hours ago
JSON representation
Angular Signals Examples
- Host: GitHub
- URL: https://github.com/manthanank/angular-signals
- Owner: manthanank
- License: mit
- Created: 2024-04-21T08:16:32.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2024-10-21T17:11:08.000Z (18 days ago)
- Last Synced: 2024-10-22T05:01:33.172Z (17 days ago)
- Topics: angular, signals
- Homepage:
- Size: 214 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Angular Signals
Angular Signals is a powerful system that provides detailed monitoring of state usage within an application, enabling the framework to efficiently optimize rendering updates.
## Table of Contents
- [Simple Example of Angular Signals in Action](#simple-example-of-angular-signals-in-action)
- [In Standalone Components](#in-standalone-components)
- [In Non Standalone Components](#in-non-standalone-components)## Simple Example of Angular Signals in Action
Here are two examples of Angular Signals in action. The first example uses Angular Signals, while the second example does not. Both examples have a counter that increments and decrements, and a log that displays the actions taken. The difference between the two examples is that the first example uses Angular Signals to manage the state, while the second example uses the default Angular change detection.
Example is created in two ways:
1. [In Standalone Components](#in-standalone-components)
2. [In Non Standalone Components](#in-non-standalone-components)## In Standalone Components
Code for the examples below can be found in the branch `with-standalone-components`.
Demo: [Angular Signals](https://amazing-gecko-07a618.netlify.app)
Project Structure:
```text
├── public/
│ |── favicon.ico
├── src/
│ ├── app/
│ │ ├── home/
│ │ │ ├── home.component.html
| | | ├── home.component.spec.ts
│ │ │ ├── home.component.ts
│ │ │ └── home.component.scss
│ │ ├── navbar/
│ │ │ ├── navbar.component.html
| | | ├── navbar.component.spec.ts
│ │ │ ├── navbar.component.ts
│ │ │ └── navbar.component.scss
│ │ ├── with-signals/
│ │ │ ├── with-signals.component.html
| | | ├── with-signals.component.spec.ts
│ │ │ ├── with-signals.component.ts
│ │ │ └── with-signals.component.scss
│ │ ├── without-signals/
│ │ │ ├── without-signals.component.html
| | | ├── without-signals.component.spec.ts
│ │ │ ├── without-signals.component.ts
│ │ │ └── without-signals.component.scss
│ │ ├── app.component.html
│ │ └── app.component.ts
| | └── app.component.spec.ts
| | └── app.component.scss
| | └── app.config.ts
| | └── app.routes.ts
│ ├── index.html
│ ├── main.ts
│ └── styles.scss
├── .editorconfig
├── .gitignore
├── angular.json
├── package.json
├── package-lock.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.spec.json
└── README.md
```Here is the code for the above project structure:
In `app.component.ts`:
```typescript
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { NavbarComponent } from './navbar/navbar.component';
import { HomeComponent } from './home/home.component';@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, NavbarComponent, HomeComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
})
export class AppComponent {}
```In `app.component.html`:
```html
```
In `app.config.ts`:
```typescript
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
],
};
```In `app.routes.ts`:
```typescript
import { Routes } from '@angular/router';export const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{
path: 'home',
loadComponent: () =>
import('./home/home.component').then((m) => m.HomeComponent),
},
{
path: 'with-signal',
loadComponent: () =>
import('./with-signals/with-signals.component').then(
(m) => m.WithSignalsComponent
),
},
{
path: 'without-signal',
loadComponent: () =>
import('./without-signals/without-signals.component').then(
(m) => m.WithoutSignalsComponent
),
},
];
```In `navbar.component.ts`:
```typescript
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive } from '@angular/router';@Component({
selector: 'app-navbar',
standalone: true,
imports: [RouterLink, RouterLinkActive],
templateUrl: './navbar.component.html',
styleUrl: './navbar.component.scss',
})
export class NavbarComponent {}
```In `navbar.component.html`:
```html
Home
With Signal Example
Without Signal Example```
In `navbar.component.scss`:
```scss
nav {
display: flex;
justify-content: center;
margin-top: 20px;
gap: 20px;a {
color: #fff;
text-decoration: none;
padding: 10px 15px;
border-radius: 5px;
// background-color: #333;
transition: background-color 0.3s;&:hover {
background-color: #555;
}
}.active {
background-color: #555;
}
}
```In `home.component.html`:
```html
Welcome to the Angular Signals Examples!
This is a collection of examples that demonstrate how to use Angular Signals.
To get started, click on one of the examples in the navigation bar.
If you have any questions or feedback, please feel free to reach out to me on Twitter at @manthan_ank.
Enjoy!
```In `home.component.scss`:
```scss
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 5rem;h1 {
color: #f0eef5;
text-align: center;
}p {
color: #f0eef5;
text-align: center;
}img {
display: block;
margin: 0 auto;
}a {
color: #f0eef5;
text-decoration: underline;
}
}
```In `home.component.ts`:
```typescript
import { Component } from '@angular/core';@Component({
selector: 'app-home',
standalone: true,
imports: [],
templateUrl: './home.component.html',
styleUrl: './home.component.scss',
})
export class HomeComponent {}
```In `with-signals.component.ts`:
```typescript
import { Component, computed, effect, signal } from '@angular/core';@Component({
selector: 'app-with-signals',
standalone: true,
imports: [],
templateUrl: './with-signals.component.html',
styleUrl: './with-signals.component.scss',
})
export class WithSignalsComponent {
actions = signal([]);
counter = signal(0);
doubleCounter = computed(() => this.counter() * 2);constructor() {
effect(() => console.log(this.counter()));
}increment() {
// this.counter.update((oldCounter) => oldCounter + 1);
this.counter.set(this.counter() + 1);
// this.actions.mutate((oldActions) => oldActions.push('INCREMENT'));
this.actions.set([...this.actions(), 'INCREMENT']);
}decrement() {
this.counter.update((oldCounter) => oldCounter - 1);
this.actions.update((oldActions) => [...oldActions, 'DECREMENT']);
}
}
```In `with-signals.component.html`:
```html
Signals
Counter: {{ doubleCounter() }}
Decrement
Increment
Action Log
@for (action of actions(); track $index) {
- {{ action }}
}
```In `without-signals.component.ts`:
```typescript
import { Component } from '@angular/core';@Component({
selector: 'app-without-signals',
standalone: true,
imports: [],
templateUrl: './without-signals.component.html',
styleUrl: './without-signals.component.scss',
})
export class WithoutSignalsComponent {
actions: string[] = [];
counter = 0;increment() {
this.counter++;
this.actions.push('INCREMENT');
}decrement() {
this.counter--;
this.actions.push('DECREMENT');
}
}
```In `without-signals.component.html`:
```html
Default (Automatic Change Detection)
Counter: {{ counter }}
Decrement
Increment
Action Log
@for (action of actions; track $index) {
- {{ action }}
}
```In `styles.scss`:
```scss
* {
box-sizing: border-box;
}html {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}body {
margin: 0;
background-color: #131216;
color: #f0eef5;
}h1,
h2 {
text-align: center;
}#counter {
margin: 3rem auto;
max-width: 40rem;
text-align: center;
}#counter-output {
font-size: 2rem;
padding: 0.5rem 1.5rem;
color: #a292d0;
}#counter-btns {
display: flex;
justify-content: center;
gap: 2rem;
}button {
padding: 0.5rem 1.5rem;
border: none;
border-radius: 4px;
background-color: #a688ff;
color: #070312;
font-size: 1.2rem;
cursor: pointer;
}button:hover {
background-color: #8e8eff;
}#log {
text-align: center;
list-style: none;
margin: 3rem 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 1rem;
}
```## In Non Standalone Components
Code for the examples below can be found in the branch `without-standalone-components`.
Demo: [Angular Signals](https://vocal-valkyrie-2b9d38.netlify.app)
Project Structure:
```text
├── public/
│ |── favicon.ico
├── src/
│ ├── app/
│ │ ├── home/
│ │ │ ├── home.component.html
| | | ├── home.component.spec.ts
│ │ │ ├── home.component.ts
│ │ │ └── home.component.scss
│ │ ├── navbar/
│ │ │ ├── navbar.component.html
| | | ├── navbar.component.spec.ts
│ │ │ ├── navbar.component.ts
│ │ │ └── navbar.component.scss
│ │ ├── with-signals/
│ │ │ ├── with-signals.component.html
| | | ├── with-signals.component.spec.ts
│ │ │ ├── with-signals.component.ts
│ │ │ └── with-signals.component.scss
│ │ ├── without-signals/
│ │ │ ├── without-signals.component.html
| | | ├── without-signals.component.spec.ts
│ │ │ ├── without-signals.component.ts
│ │ │ └── without-signals.component.scss
│ │ ├── app.component.html
│ │ └── app.component.ts
| | └── app.component.scss
| | └── app.component.spec.ts
| | └── app.module.ts
| | └── app.routing.module.ts
│ ├── index.html
│ ├── main.ts
│ └── styles.scss
├── .editorconfig
├── .gitignore
├── angular.json
├── package.json
├── package-lock.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.spec.json
└── README.md
```Here is the code for the above project structure:
In `app.component.ts`:
```typescript
import { Component } from '@angular/core';@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
})
export class AppComponent {}
```In `app.component.html`:
```html
```
In `app.module.ts`:
```typescript
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NavbarComponent } from './navbar/navbar.component';@NgModule({
declarations: [
AppComponent,
NavbarComponent,
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
```In `app.routing.module.ts`:
```typescript
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{
path: 'home',
loadChildren: () => import('./home/home.module').then((m) => m.HomeModule),
},
{
path: 'with-signal',
loadChildren: () =>
import('./with-signals/with-signals.module').then(
(m) => m.WithSignalsModule
),
},
{
path: 'without-signal',
loadChildren: () =>
import('./without-signals/without-signals.module').then(
(m) => m.WithoutSignalsModule
),
},
];@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
```In `navbar.component.ts`:
```typescript
import { Component } from '@angular/core';@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrl: './navbar.component.scss',
})
export class NavbarComponent {}
```In `navbar.component.html`:
```html
Home
With Signal Example
Without Signal Example```
In `navbar.component.scss`:
```scss
nav {
display: flex;
justify-content: center;
margin-top: 20px;
gap: 20px;a {
color: #fff;
text-decoration: none;
padding: 10px 15px;
border-radius: 5px;
// background-color: #333;
transition: background-color 0.3s;&:hover {
background-color: #555;
}
}.active {
background-color: #555;
}
}
```In `home-routing.module.ts`:
```typescript
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home.component';const routes: Routes = [{ path: '', component: HomeComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class HomeRoutingModule {}
```In `home.component.html`:
```html
Welcome to the Angular Signals Examples!
This is a collection of examples that demonstrate how to use Angular Signals.
To get started, click on one of the examples in the navigation bar.
If you have any questions or feedback, please feel free to reach out to me on Twitter at @manthan_ank.
Enjoy!
```In `home.component.scss`:
```scss
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 5rem;h1 {
color: #f0eef5;
text-align: center;
}p {
color: #f0eef5;
text-align: center;
}img {
display: block;
margin: 0 auto;
}a {
color: #f0eef5;
text-decoration: underline;
}
}
```In `home.component.ts`:
```typescript
import { Component } from '@angular/core';@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrl: './home.component.scss',
})
export class HomeComponent {}
```In `home.module.ts`:
```typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HomeComponent } from './home.component';
import { HomeRoutingModule } from './home-routing.module';@NgModule({
declarations: [HomeComponent],
imports: [CommonModule, HomeRoutingModule]
})
export class HomeModule { }
```In `with-signals-routing.module.ts`:
```typescript
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { WithSignalsComponent } from './with-signals.component';const routes: Routes = [{ path: '', component: WithSignalsComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class WithSignalsRoutingModule {}
```In `with-signals.module.ts`:
```typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WithSignalsComponent } from './with-signals.component';
import { WithSignalsRoutingModule } from './with-signals-routing.module';@NgModule({
declarations: [WithSignalsComponent],
imports: [CommonModule, WithSignalsRoutingModule],
})
export class WithSignalsModule {}
```In `with-signals.component.ts`:
```typescript
import { Component, computed, effect, signal } from '@angular/core';@Component({
selector: 'app-with-signals',
templateUrl: './with-signals.component.html',
styleUrl: './with-signals.component.scss',
})
export class WithSignalsComponent {
actions = signal([]);
counter = signal(0);
doubleCounter = computed(() => this.counter() * 2);constructor() {
effect(() => console.log(this.counter()));
}increment() {
// this.counter.update((oldCounter) => oldCounter + 1);
this.counter.set(this.counter() + 1);
// this.actions.mutate((oldActions) => oldActions.push('INCREMENT'));
this.actions.set([...this.actions(), 'INCREMENT']);
}decrement() {
this.counter.update((oldCounter) => oldCounter - 1);
this.actions.update((oldActions) => [...oldActions, 'DECREMENT']);
}
}
```In `with-signals.component.html`:
```html
Signals
Counter: {{ doubleCounter() }}
Decrement
Increment
Action Log
@for (action of actions(); track $index) {
- {{ action }}
}
```In `without-signals-routing.module.ts`:
```typescript
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { WithoutSignalsComponent } from './without-signals.component';const routes: Routes = [
{ path: '', component: WithoutSignalsComponent },
];@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class WithoutSignalsRoutingModule { }
```In `without-signals.module.ts`:
```typescript
// without-signals.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WithoutSignalsComponent } from './without-signals.component';
import { WithoutSignalsRoutingModule } from './without-signals-routing.module';@NgModule({
declarations: [WithoutSignalsComponent],
imports: [CommonModule, WithoutSignalsRoutingModule],
})
export class WithoutSignalsModule {}
```In `without-signals.component.ts`:
```typescript
import { Component } from '@angular/core';@Component({
selector: 'app-without-signals',
templateUrl: './without-signals.component.html',
styleUrl: './without-signals.component.scss',
})
export class WithoutSignalsComponent {
actions: string[] = [];
counter = 0;increment() {
this.counter++;
this.actions.push('INCREMENT');
}decrement() {
this.counter--;
this.actions.push('DECREMENT');
}
}
```In `without-signals.component.html`:
```html
Default (Automatic Change Detection)
Counter: {{ counter }}
Decrement
Increment
Action Log
@for (action of actions; track $index) {
- {{ action }}
}
```In `styles.scss`:
```scss
* {
box-sizing: border-box;
}html {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}body {
margin: 0;
background-color: #131216;
color: #f0eef5;
}h1,
h2 {
text-align: center;
}#counter {
margin: 3rem auto;
max-width: 40rem;
text-align: center;
}#counter-output {
font-size: 2rem;
padding: 0.5rem 1.5rem;
color: #a292d0;
}#counter-btns {
display: flex;
justify-content: center;
gap: 2rem;
}button {
padding: 0.5rem 1.5rem;
border: none;
border-radius: 4px;
background-color: #a688ff;
color: #070312;
font-size: 1.2rem;
cursor: pointer;
}button:hover {
background-color: #8e8eff;
}#log {
text-align: center;
list-style: none;
margin: 3rem 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 1rem;
}
```## Conclusion
Angular Signals is a powerful system that provides detailed monitoring of state usage within an application, enabling the framework to efficiently optimize rendering updates. By using Angular Signals, developers can create more efficient and performant applications that are easier to maintain and scale.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgements
- [Angular](https://angular.io/)
- [Maximilian Schwarzmüller](https://www.udemy.com/user/maximilian-schwarzmuller/)
- [Udemy](https://www.udemy.com/)
- [Netlify](https://www.netlify.com/)
- [Angular - The Complete Guide (2024 Edition)](https://www.udemy.com/course-dashboard-redirect/?course_id=756150)This projects were created as part of the Angular - The Complete Guide (2024 Edition) course by Maximilian Schwarzmüller on Udemy.