Modern reactivity with Angular signals for Google Antigravity IDE
# Angular Signals Complete Guide for Google Antigravity
Master Angular signals for fine-grained reactivity with Google Antigravity IDE. This comprehensive guide covers signal creation, computed values, effects, signal-based inputs, and migration patterns from RxJS observables to the new signals API for optimal change detection performance.
## Configuration
Configure your Antigravity environment for Angular signals:
```typescript
// .antigravity/angular.ts
export const angularConfig = {
version: "17+",
features: {
signals: true,
zonelessChangeDetection: true,
deferredViews: true
},
patterns: ["signal", "computed", "effect", "linkedSignal"]
};
```
## Basic Signal Patterns
Create and use reactive signals:
```typescript
import { Component, signal, computed, effect } from "@angular/core";
@Component({
selector: "app-counter",
standalone: true,
template: `
<div class="counter">
<button (click)="decrement()">-</button>
<span>{{ count() }}</span>
<button (click)="increment()">+</button>
<p>Double: {{ doubled() }}</p>
</div>
`
})
export class CounterComponent {
count = signal(0);
doubled = computed(() => this.count() * 2);
constructor() {
effect(() => {
console.log("Count changed:", this.count());
});
}
increment() {
this.count.update(c => c + 1);
}
decrement() {
this.count.update(c => c - 1);
}
}
```
## Signal-Based Inputs
Use signals for component inputs:
```typescript
import { Component, input, computed } from "@angular/core";
@Component({
selector: "app-user-card",
standalone: true,
template: `
<div class="user-card">
<h2>{{ user().name }}</h2>
<p>{{ user().email }}</p>
<span class="initials">{{ initials() }}</span>
</div>
`
})
export class UserCardComponent {
user = input.required<User>();
showEmail = input(true);
initials = computed(() => {
const name = this.user().name;
return name.split(" ").map(n => n[0]).join("");
});
}
```
## Two-Way Binding with Model
Implement two-way binding with model signals:
```typescript
import { Component, model, output } from "@angular/core";
@Component({
selector: "app-search-input",
standalone: true,
template: `
<div class="search">
<input
type="text"
[value]="query()"
(input)="onInput($event)"
placeholder="Search..."
/>
<button (click)="clear()">Clear</button>
</div>
`
})
export class SearchInputComponent {
query = model("");
search = output<string>();
onInput(event: Event) {
const value = (event.target as HTMLInputElement).value;
this.query.set(value);
}
clear() {
this.query.set("");
}
submit() {
this.search.emit(this.query());
}
}
```
## Linked Signals Pattern
Create dependent signals with linkedSignal:
```typescript
import { Component, signal, linkedSignal } from "@angular/core";
@Component({
selector: "app-form",
standalone: true,
template: `
<form>
<select (change)="onCountryChange($event)">
<option *ngFor="let c of countries()" [value]="c.code">
{{ c.name }}
</option>
</select>
<select>
<option *ngFor="let c of cities()" [value]="c">
{{ c }}
</option>
</select>
</form>
`
})
export class FormComponent {
countries = signal([
{ code: "US", name: "United States" },
{ code: "UK", name: "United Kingdom" }
]);
selectedCountry = signal("US");
cities = linkedSignal(() => {
const country = this.selectedCountry();
return this.getCitiesForCountry(country);
});
onCountryChange(event: Event) {
const code = (event.target as HTMLSelectElement).value;
this.selectedCountry.set(code);
}
private getCitiesForCountry(code: string): string[] {
const cityMap: Record<string, string[]> = {
US: ["New York", "Los Angeles", "Chicago"],
UK: ["London", "Manchester", "Birmingham"]
};
return cityMap[code] || [];
}
}
```
## Resource Pattern for Async Data
Handle async data with resource:
```typescript
import { Component, resource, signal } from "@angular/core";
@Component({
selector: "app-user-list",
standalone: true,
template: `
@if (users.isLoading()) {
<div class="loading">Loading...</div>
}
@if (users.error()) {
<div class="error">{{ users.error().message }}</div>
}
@if (users.value()) {
<ul>
@for (user of users.value(); track user.id) {
<li>{{ user.name }}</li>
}
</ul>
}
`
})
export class UserListComponent {
page = signal(1);
users = resource({
request: () => ({ page: this.page() }),
loader: async ({ request, abortSignal }) => {
const response = await fetch(
`/api/users?page=${request.page}`,
{ signal: abortSignal }
);
return response.json();
}
});
nextPage() {
this.page.update(p => p + 1);
}
}
```
## Best Practices
Follow these guidelines for Angular signals:
1. **Use signals for local state** - Replace simple component state
2. **Prefer computed** - Derive values instead of manual updates
3. **Effects for side effects** - Keep effects focused
4. **Signal inputs** - Type-safe component communication
5. **Avoid signal in templates** - Minimize function calls
6. **Migrate incrementally** - Signals work alongside RxJS
Google Antigravity IDE provides intelligent signal suggestions and automatic RxJS to signals migration patterns.This Angular prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their angular implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For Angular projects, consider mentioning your framework version, coding style, and any specific libraries you're using.