{"id":"6ca9af51-09cc-4d0b-9ec0-08fccc3b7058","shortId":"L8TaCB","kind":"skill","title":"angular-state-management","tagline":"Master modern Angular state management with Signals, NgRx, and RxJS. Use when setting up global state, managing component stores, choosing between state solutions, or migrating from legacy patterns.","description":"# Angular State Management\n\nComprehensive guide to modern Angular state management patterns, from Signal-based local state to global stores and server state synchronization.\n\n## When to Use This Skill\n\n- Setting up global state management in Angular\n- Choosing between Signals, NgRx, or Akita\n- Managing component-level stores\n- Implementing optimistic updates\n- Debugging state-related issues\n- Migrating from legacy state patterns\n\n## Do Not Use This Skill When\n\n- The task is unrelated to Angular state management\n- You need React state management → use `react-state-management`\n\n---\n\n## Core Concepts\n\n### State Categories\n\n| Type             | Description                  | Solutions             |\n| ---------------- | ---------------------------- | --------------------- |\n| **Local State**  | Component-specific, UI state | Signals, `signal()`   |\n| **Shared State** | Between related components   | Signal services       |\n| **Global State** | App-wide, complex            | NgRx, Akita, Elf      |\n| **Server State** | Remote data, caching         | NgRx Query, RxAngular |\n| **URL State**    | Route parameters             | ActivatedRoute        |\n| **Form State**   | Input values, validation     | Reactive Forms        |\n\n### Selection Criteria\n\n```\nSmall app, simple state → Signal Services\nMedium app, moderate state → Component Stores\nLarge app, complex state → NgRx Store\nHeavy server interaction → NgRx Query + Signal Services\nReal-time updates → RxAngular + Signals\n```\n\n---\n\n## Quick Start: Signal-Based State\n\n### Pattern 1: Simple Signal Service\n\n```typescript\n// services/counter.service.ts\nimport { Injectable, signal, computed } from \"@angular/core\";\n\n@Injectable({ providedIn: \"root\" })\nexport class CounterService {\n  // Private writable signals\n  private _count = signal(0);\n\n  // Public read-only\n  readonly count = this._count.asReadonly();\n  readonly doubled = computed(() => this._count() * 2);\n  readonly isPositive = computed(() => this._count() > 0);\n\n  increment() {\n    this._count.update((v) => v + 1);\n  }\n\n  decrement() {\n    this._count.update((v) => v - 1);\n  }\n\n  reset() {\n    this._count.set(0);\n  }\n}\n\n// Usage in component\n@Component({\n  template: `\n    <p>Count: {{ counter.count() }}</p>\n    <p>Doubled: {{ counter.doubled() }}</p>\n    <button (click)=\"counter.increment()\">+</button>\n  `,\n})\nexport class CounterComponent {\n  counter = inject(CounterService);\n}\n```\n\n### Pattern 2: Feature Signal Store\n\n```typescript\n// stores/user.store.ts\nimport { Injectable, signal, computed, inject } from \"@angular/core\";\nimport { HttpClient } from \"@angular/common/http\";\nimport { toSignal } from \"@angular/core/rxjs-interop\";\n\ninterface User {\n  id: string;\n  name: string;\n  email: string;\n}\n\ninterface UserState {\n  user: User | null;\n  loading: boolean;\n  error: string | null;\n}\n\n@Injectable({ providedIn: \"root\" })\nexport class UserStore {\n  private http = inject(HttpClient);\n\n  // State signals\n  private _user = signal<User | null>(null);\n  private _loading = signal(false);\n  private _error = signal<string | null>(null);\n\n  // Selectors (read-only computed)\n  readonly user = computed(() => this._user());\n  readonly loading = computed(() => this._loading());\n  readonly error = computed(() => this._error());\n  readonly isAuthenticated = computed(() => this._user() !== null);\n  readonly displayName = computed(() => this._user()?.name ?? \"Guest\");\n\n  // Actions\n  async loadUser(id: string) {\n    this._loading.set(true);\n    this._error.set(null);\n\n    try {\n      const user = await fetch(`/api/users/${id}`).then((r) => r.json());\n      this._user.set(user);\n    } catch (e) {\n      this._error.set(\"Failed to load user\");\n    } finally {\n      this._loading.set(false);\n    }\n  }\n\n  updateUser(updates: Partial<User>) {\n    this._user.update((user) => (user ? { ...user, ...updates } : null));\n  }\n\n  logout() {\n    this._user.set(null);\n    this._error.set(null);\n  }\n}\n```\n\n### Pattern 3: SignalStore (NgRx Signals)\n\n```typescript\n// stores/products.store.ts\nimport {\n  signalStore,\n  withState,\n  withMethods,\n  withComputed,\n  patchState,\n} from \"@ngrx/signals\";\nimport { inject } from \"@angular/core\";\nimport { ProductService } from \"./product.service\";\n\ninterface ProductState {\n  products: Product[];\n  loading: boolean;\n  filter: string;\n}\n\nconst initialState: ProductState = {\n  products: [],\n  loading: false,\n  filter: \"\",\n};\n\nexport const ProductStore = signalStore(\n  { providedIn: \"root\" },\n\n  withState(initialState),\n\n  withComputed((store) => ({\n    filteredProducts: computed(() => {\n      const filter = store.filter().toLowerCase();\n      return store\n        .products()\n        .filter((p) => p.name.toLowerCase().includes(filter));\n    }),\n    totalCount: computed(() => store.products().length),\n  })),\n\n  withMethods((store, productService = inject(ProductService)) => ({\n    async loadProducts() {\n      patchState(store, { loading: true });\n\n      try {\n        const products = await productService.getAll();\n        patchState(store, { products, loading: false });\n      } catch {\n        patchState(store, { loading: false });\n      }\n    },\n\n    setFilter(filter: string) {\n      patchState(store, { filter });\n    },\n\n    addProduct(product: Product) {\n      patchState(store, ({ products }) => ({\n        products: [...products, product],\n      }));\n    },\n  })),\n);\n\n// Usage\n@Component({\n  template: `\n    <input (input)=\"store.setFilter($event.target.value)\" />\n    @if (store.loading()) {\n      <app-spinner />\n    } @else {\n      @for (product of store.filteredProducts(); track product.id) {\n        <app-product-card [product]=\"product\" />\n      }\n    }\n  `,\n})\nexport class ProductListComponent {\n  store = inject(ProductStore);\n\n  ngOnInit() {\n    this.store.loadProducts();\n  }\n}\n```\n\n---\n\n## NgRx Store (Global State)\n\n### Setup\n\n```typescript\n// store/app.state.ts\nimport { ActionReducerMap } from \"@ngrx/store\";\n\nexport interface AppState {\n  user: UserState;\n  cart: CartState;\n}\n\nexport const reducers: ActionReducerMap<AppState> = {\n  user: userReducer,\n  cart: cartReducer,\n};\n\n// main.ts\nbootstrapApplication(AppComponent, {\n  providers: [\n    provideStore(reducers),\n    provideEffects([UserEffects, CartEffects]),\n    provideStoreDevtools({ maxAge: 25 }),\n  ],\n});\n```\n\n### Feature Slice Pattern\n\n```typescript\n// store/user/user.actions.ts\nimport { createActionGroup, props, emptyProps } from \"@ngrx/store\";\n\nexport const UserActions = createActionGroup({\n  source: \"User\",\n  events: {\n    \"Load User\": props<{ userId: string }>(),\n    \"Load User Success\": props<{ user: User }>(),\n    \"Load User Failure\": props<{ error: string }>(),\n    \"Update User\": props<{ updates: Partial<User> }>(),\n    Logout: emptyProps(),\n  },\n});\n```\n\n```typescript\n// store/user/user.reducer.ts\nimport { createReducer, on } from \"@ngrx/store\";\nimport { UserActions } from \"./user.actions\";\n\nexport interface UserState {\n  user: User | null;\n  loading: boolean;\n  error: string | null;\n}\n\nconst initialState: UserState = {\n  user: null,\n  loading: false,\n  error: null,\n};\n\nexport const userReducer = createReducer(\n  initialState,\n\n  on(UserActions.loadUser, (state) => ({\n    ...state,\n    loading: true,\n    error: null,\n  })),\n\n  on(UserActions.loadUserSuccess, (state, { user }) => ({\n    ...state,\n    user,\n    loading: false,\n  })),\n\n  on(UserActions.loadUserFailure, (state, { error }) => ({\n    ...state,\n    loading: false,\n    error,\n  })),\n\n  on(UserActions.logout, () => initialState),\n);\n```\n\n```typescript\n// store/user/user.selectors.ts\nimport { createFeatureSelector, createSelector } from \"@ngrx/store\";\nimport { UserState } from \"./user.reducer\";\n\nexport const selectUserState = createFeatureSelector<UserState>(\"user\");\n\nexport const selectUser = createSelector(\n  selectUserState,\n  (state) => state.user,\n);\n\nexport const selectUserLoading = createSelector(\n  selectUserState,\n  (state) => state.loading,\n);\n\nexport const selectIsAuthenticated = createSelector(\n  selectUser,\n  (user) => user !== null,\n);\n```\n\n```typescript\n// store/user/user.effects.ts\nimport { Injectable, inject } from \"@angular/core\";\nimport { Actions, createEffect, ofType } from \"@ngrx/effects\";\nimport { switchMap, map, catchError, of } from \"rxjs\";\n\n@Injectable()\nexport class UserEffects {\n  private actions$ = inject(Actions);\n  private userService = inject(UserService);\n\n  loadUser$ = createEffect(() =>\n    this.actions$.pipe(\n      ofType(UserActions.loadUser),\n      switchMap(({ userId }) =>\n        this.userService.getUser(userId).pipe(\n          map((user) => UserActions.loadUserSuccess({ user })),\n          catchError((error) =>\n            of(UserActions.loadUserFailure({ error: error.message })),\n          ),\n        ),\n      ),\n    ),\n  );\n}\n```\n\n### Component Usage\n\n```typescript\n@Component({\n  template: `\n    @if (loading()) {\n      <app-spinner />\n    } @else if (user(); as user) {\n      <h1>Welcome, {{ user.name }}</h1>\n      <button (click)=\"logout()\">Logout</button>\n    }\n  `,\n})\nexport class HeaderComponent {\n  private store = inject(Store);\n\n  user = this.store.selectSignal(selectUser);\n  loading = this.store.selectSignal(selectUserLoading);\n\n  logout() {\n    this.store.dispatch(UserActions.logout());\n  }\n}\n```\n\n---\n\n## RxJS-Based Patterns\n\n### Component Store (Local Feature State)\n\n```typescript\n// stores/todo.store.ts\nimport { Injectable } from \"@angular/core\";\nimport { ComponentStore } from \"@ngrx/component-store\";\nimport { switchMap, tap, catchError, EMPTY } from \"rxjs\";\n\ninterface TodoState {\n  todos: Todo[];\n  loading: boolean;\n}\n\n@Injectable()\nexport class TodoStore extends ComponentStore<TodoState> {\n  constructor(private todoService: TodoService) {\n    super({ todos: [], loading: false });\n  }\n\n  // Selectors\n  readonly todos$ = this.select((state) => state.todos);\n  readonly loading$ = this.select((state) => state.loading);\n  readonly completedCount$ = this.select(\n    this.todos$,\n    (todos) => todos.filter((t) => t.completed).length,\n  );\n\n  // Updaters\n  readonly addTodo = this.updater((state, todo: Todo) => ({\n    ...state,\n    todos: [...state.todos, todo],\n  }));\n\n  readonly toggleTodo = this.updater((state, id: string) => ({\n    ...state,\n    todos: state.todos.map((t) =>\n      t.id === id ? { ...t, completed: !t.completed } : t,\n    ),\n  }));\n\n  // Effects\n  readonly loadTodos = this.effect<void>((trigger$) =>\n    trigger$.pipe(\n      tap(() => this.patchState({ loading: true })),\n      switchMap(() =>\n        this.todoService.getAll().pipe(\n          tap({\n            next: (todos) => this.patchState({ todos, loading: false }),\n            error: () => this.patchState({ loading: false }),\n          }),\n          catchError(() => EMPTY),\n        ),\n      ),\n    ),\n  );\n}\n```\n\n---\n\n## Server State with Signals\n\n### HTTP + Signals Pattern\n\n```typescript\n// services/api.service.ts\nimport { Injectable, signal, inject } from \"@angular/core\";\nimport { HttpClient } from \"@angular/common/http\";\nimport { toSignal } from \"@angular/core/rxjs-interop\";\n\ninterface ApiState<T> {\n  data: T | null;\n  loading: boolean;\n  error: string | null;\n}\n\n@Injectable({ providedIn: \"root\" })\nexport class ProductApiService {\n  private http = inject(HttpClient);\n\n  private _state = signal<ApiState<Product[]>>({\n    data: null,\n    loading: false,\n    error: null,\n  });\n\n  readonly products = computed(() => this._state().data ?? []);\n  readonly loading = computed(() => this._state().loading);\n  readonly error = computed(() => this._state().error);\n\n  async fetchProducts(): Promise<void> {\n    this._state.update((s) => ({ ...s, loading: true, error: null }));\n\n    try {\n      const data = await firstValueFrom(\n        this.http.get<Product[]>(\"/api/products\"),\n      );\n      this._state.update((s) => ({ ...s, data, loading: false }));\n    } catch (e) {\n      this._state.update((s) => ({\n        ...s,\n        loading: false,\n        error: \"Failed to fetch products\",\n      }));\n    }\n  }\n\n  // Optimistic update\n  async deleteProduct(id: string): Promise<void> {\n    const previousData = this._state().data;\n\n    // Optimistically remove\n    this._state.update((s) => ({\n      ...s,\n      data: s.data?.filter((p) => p.id !== id) ?? null,\n    }));\n\n    try {\n      await firstValueFrom(this.http.delete(`/api/products/${id}`));\n    } catch {\n      // Rollback on error\n      this._state.update((s) => ({ ...s, data: previousData }));\n    }\n  }\n}\n```\n\n---\n\n## Best Practices\n\n### Do's\n\n| Practice                           | Why                                |\n| ---------------------------------- | ---------------------------------- |\n| Use Signals for local state        | Simple, reactive, no subscriptions |\n| Use `computed()` for derived data  | Auto-updates, memoized             |\n| Colocate state with feature        | Easier to maintain                 |\n| Use NgRx for complex flows         | Actions, effects, devtools         |\n| Prefer `inject()` over constructor | Cleaner, works in factories        |\n\n### Don'ts\n\n| Anti-Pattern                      | Instead                                               |\n| --------------------------------- | ----------------------------------------------------- |\n| Store derived data                | Use `computed()`                                      |\n| Mutate signals directly           | Use `set()` or `update()`                             |\n| Over-globalize state              | Keep local when possible                              |\n| Mix RxJS and Signals chaotically  | Choose primary, bridge with `toSignal`/`toObservable` |\n| Subscribe in components for state | Use template with signals                             |\n\n---\n\n## Migration Path\n\n### From BehaviorSubject to Signals\n\n```typescript\n// Before: RxJS-based\n@Injectable({ providedIn: \"root\" })\nexport class OldUserService {\n  private userSubject = new BehaviorSubject<User | null>(null);\n  user$ = this.userSubject.asObservable();\n\n  setUser(user: User) {\n    this.userSubject.next(user);\n  }\n}\n\n// After: Signal-based\n@Injectable({ providedIn: \"root\" })\nexport class UserService {\n  private _user = signal<User | null>(null);\n  readonly user = this._user.asReadonly();\n\n  setUser(user: User) {\n    this._user.set(user);\n  }\n}\n```\n\n### Bridging Signals and RxJS\n\n```typescript\nimport { toSignal, toObservable } from '@angular/core/rxjs-interop';\n\n// Observable → Signal\n@Component({...})\nexport class ExampleComponent {\n  private route = inject(ActivatedRoute);\n\n  // Convert Observable to Signal\n  userId = toSignal(\n    this.route.params.pipe(map(p => p['id'])),\n    { initialValue: '' }\n  );\n}\n\n// Signal → Observable\nexport class DataService {\n  private filter = signal('');\n\n  // Convert Signal to Observable\n  filter$ = toObservable(this.filter);\n\n  filteredData$ = this.filter$.pipe(\n    debounceTime(300),\n    switchMap(filter => this.http.get(`/api/data?q=${filter}`))\n  );\n}\n```\n\n---\n\n## Resources\n\n- [Angular Signals Guide](https://angular.dev/guide/signals)\n- [NgRx Documentation](https://ngrx.io/)\n- [NgRx SignalStore](https://ngrx.io/guide/signals)\n- [RxAngular](https://www.rx-angular.io/)\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["angular","state","management","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding"],"capabilities":["skill","source-sickn33","skill-angular-state-management","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/angular-state-management","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34964 github stars · SKILL.md body (15,419 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-25T00:50:26.057Z","embedding":null,"createdAt":"2026-04-18T21:30:58.943Z","updatedAt":"2026-04-25T00:50:26.057Z","lastSeenAt":"2026-04-25T00:50:26.057Z","tsv":"'/)':1308,1317 '/api/data':1294 '/api/products':1034,1080 '/api/users':392 '/guide/signals)':1303,1313 '/product.service':445 '/user.actions':650 '/user.reducer':713 '0':233,250,263 '1':209,255,260 '2':245,283 '25':597 '3':424 '300':1290 'action':378,749,766,768,1127 'actionreducermap':568,581 'activatedrout':161,1258 'addproduct':521 'addtodo':896 'akita':74,147 'angular':2,7,33,40,68,104,1298 'angular-state-manag':1 'angular.dev':1302 'angular.dev/guide/signals)':1301 'angular/common/http':299,966 'angular/core':220,295,441,747,842,962 'angular/core/rxjs-interop':303,970,1248 'anti':1141 'anti-pattern':1140 'apist':972,994 'app':143,172,178,184,547 'app-product-card':546 'app-wid':142 'appcompon':588 'appstat':573 'ask':1351 'async':379,494,1017,1055 'auto':1112 'auto-upd':1111 'await':390,503,1030,1077 'base':47,206,830,1194,1218 'behaviorsubject':1187,1204 'best':1091 'boolean':318,451,658,859,977 'bootstrapappl':587 'boundari':1359 'bridg':1171,1239 'button':273,808 'cach':153 'card':549 'cart':576,584 'carteffect':594 'cartreduc':585 'cartstat':577 'catch':399,510,1041,1082 'catcherror':757,788,850,946 'categori':120 'chaotic':1168 'choos':24,69,1169 'clarif':1353 'class':225,277,326,553,763,813,862,985,1199,1223,1253,1274 'cleaner':1134 'clear':1326 'click':274,809 'coloc':1115 'complet':918 'completedcount':886 'complex':145,185,1125 'compon':22,77,127,137,181,266,267,531,794,797,832,1177,1251 'component-level':76 'component-specif':126 'componentstor':844,865 'comprehens':36 'comput':218,243,248,292,354,357,361,365,369,374,472,486,1004,1009,1014,1107,1148 'concept':118 'const':388,454,462,473,501,579,610,662,672,715,720,727,734,1028,1060 'constructor':866,1133 'convert':1259,1279 'core':117 'count':231,239,269 'counter':279 'counter.count':270 'counter.doubled':272 'counter.increment':275 'countercompon':278 'counterservic':226,281 'createactiongroup':604,612 'createeffect':750,774 'createfeatureselector':706,717 'createreduc':643,674 'createselector':707,722,729,736 'criteria':170,1362 'data':152,973,996,1006,1029,1038,1063,1069,1089,1110,1146 'dataservic':1275 'debouncetim':1289 'debug':83 'decrement':256 'deleteproduct':1056 'deriv':1109,1145 'describ':1330 'descript':122 'devtool':1129 'direct':1151 'displaynam':373 'document':1305 'doubl':242,271 'e':400,1042 'easier':1119 'effect':921,1128 'elf':148 'els':539,801 'email':310 'empti':851,947 'emptyprop':606,639 'environ':1342 'environment-specif':1341 'error':319,345,364,631,659,669,682,695,699,789,792,942,978,1000,1013,1016,1025,1048,1085 'error.message':793 'event':615 'event.target.value':536 'examplecompon':1254 'expert':1347 'export':224,276,325,461,552,571,578,609,651,671,714,719,726,733,762,812,861,984,1198,1222,1252,1273 'extend':864 'factori':1137 'fail':402,1049 'failur':629 'fals':343,408,459,509,514,668,691,698,873,941,945,999,1040,1047 'featur':284,598,835,1118 'fetch':391,1051 'fetchproduct':1018 'filter':452,460,474,480,484,516,520,1071,1277,1283,1292,1296 'filtereddata':1286 'filteredproduct':471 'final':406 'firstvaluefrom':1031,1078 'flow':1126 'form':162,168 'global':19,51,64,140,562,1158 'guest':377 'guid':37,1300 'headercompon':814 'heavi':189 'http':329,952,988 'httpclient':297,331,964,990 'id':306,381,393,909,916,1057,1074,1081,1269 'implement':80 'import':215,289,296,300,430,438,442,567,603,642,647,705,710,743,748,754,839,843,847,957,963,967,1244 'includ':483 'increment':251 'initialst':455,468,663,675,702 'initialvalu':1270 'inject':216,221,280,290,293,322,330,439,492,556,744,745,761,767,771,817,840,860,958,960,981,989,1131,1195,1219,1257 'input':164,533,534,1356 'instead':1143 'interact':191 'interfac':304,312,446,572,652,854,971 'isauthent':368 'isposit':247 'issu':87 'keep':1160 'larg':183 'legaci':31,90 'length':488,893 'level':78 'limit':1318 'load':317,341,360,404,450,458,498,508,513,616,621,627,657,667,680,690,697,800,822,858,872,881,930,940,944,976,998,1008,1011,1023,1039,1046 'loadproduct':495 'loadtodo':923 'loadus':380,773 'local':48,124,834,1100,1161 'logout':418,638,810,811,825 'main.ts':586 'maintain':1121 'manag':4,9,21,35,42,66,75,106,111,116 'map':756,784,1266 'master':5 'match':1327 'maxag':596 'medium':177 'memoiz':1114 'migrat':29,88,1184 'miss':1364 'mix':1164 'moder':179 'modern':6,39 'mutat':1149 'name':308,376 'need':108 'new':1203 'next':936 'ngoninit':558 'ngrx':12,72,146,154,187,192,426,560,1123,1304,1309 'ngrx.io':1307,1312 'ngrx.io/)':1306 'ngrx.io/guide/signals)':1311 'ngrx/component-store':846 'ngrx/effects':753 'ngrx/signals':437 'ngrx/store':570,608,646,709 'null':316,321,338,339,348,349,371,386,417,420,422,656,661,666,670,683,740,975,980,997,1001,1026,1075,1206,1207,1229,1230 'observ':1249,1260,1272,1282 'oftyp':751,777 'olduserservic':1200 'optimist':81,1053,1064 'output':1336 'over-glob':1156 'p':481,1072,1267,1268 'p.id':1073 'p.name.tolowercase':482 'paramet':160 'partial':411,637 'patchstat':435,496,505,511,518,524 'path':1185 'pattern':32,43,92,208,282,423,600,831,954,1142 'permiss':1357 'pipe':776,783,927,934,1288 'possibl':1163 'practic':1092,1095 'prefer':1130 'previousdata':1061,1090 'primari':1170 'privat':227,230,328,334,340,344,765,769,815,867,987,991,1201,1225,1255,1276 'product':448,449,457,479,502,507,522,523,526,527,528,529,541,548,550,551,995,1003,1033,1052 'product.id':545 'productapiservic':986 'productlistcompon':554 'productservic':443,491,493 'productservice.getall':504 'productst':447,456 'productstor':463,557 'promis':1019,1059 'prop':605,618,624,630,635 'provid':589 'providedin':222,323,465,982,1196,1220 'provideeffect':592 'providestor':590 'providestoredevtool':595 'public':234 'q':1295 'queri':155,193 'quick':202 'r':395 'r.json':396 'react':109,114 'react-state-manag':113 'reactiv':167,1103 'read':236,352 'read-on':235,351 'readon':238,241,246,355,359,363,367,372,875,880,885,895,905,922,1002,1007,1012,1231 'real':197 'real-tim':196 'reduc':580,591 'relat':86,136 'remot':151 'remov':1065 'requir':1355 'reset':261 'resourc':1297 'return':477 'review':1348 'rollback':1083 'root':223,324,466,983,1197,1221 'rout':159,1256 'rxangular':156,200,1314 'rxjs':14,760,829,853,1165,1193,1242 'rxjs-base':828,1192 's.data':1070 'safeti':1358 'scope':1329 'select':169 'selectisauthent':735 'selector':350,874 'selectus':721,737,821 'selectuserload':728,824 'selectuserst':716,723,730 'server':54,149,190,948 'servic':139,176,195,212 'services/api.service.ts':956 'services/counter.service.ts':214 'set':17,62,1153 'setfilt':515 'setup':564 'setus':1210,1234 'share':133 'signal':11,46,71,131,132,138,175,194,201,205,211,217,229,232,285,291,333,336,342,346,427,951,953,959,993,1098,1150,1167,1183,1189,1217,1227,1240,1250,1262,1271,1278,1280,1299 'signal-bas':45,204,1216 'signalstor':425,431,464,1310 'simpl':173,210,1102 'skill':61,97,1321 'skill-angular-state-management' 'slice':599 'small':171 'solut':27,123 'sourc':613 'source-sickn33' 'specif':128,1343 'start':203 'state':3,8,20,26,34,41,49,55,65,85,91,105,110,115,119,125,130,134,141,150,158,163,174,180,186,207,332,563,678,679,686,688,694,696,724,731,836,878,883,898,901,908,911,949,992,1101,1116,1159,1179 'state-rel':84 'state.loading':732,884 'state.todos':879,903 'state.todos.map':913 'state.user':725 'stop':1349 'store':23,52,79,182,188,286,470,478,490,497,506,512,519,525,555,561,816,818,833,1144 'store.filter':475 'store.filteredproducts':543 'store.loading':538 'store.products':487 'store.setfilter':535 'store/app.state.ts':566 'store/user/user.actions.ts':602 'store/user/user.effects.ts':742 'store/user/user.reducer.ts':641 'store/user/user.selectors.ts':704 'stores/products.store.ts':429 'stores/todo.store.ts':838 'stores/user.store.ts':288 'string':307,309,311,320,347,382,453,517,620,632,660,910,979,1058 'subscrib':1175 'subscript':1105 'substitut':1339 'success':623,1361 'super':870 'switchmap':755,779,848,932,1291 'synchron':56 't.completed':892,919 't.id':915 'tap':849,928,935 'task':100,1325 'templat':268,532,798,1181 'test':1345 'this._count':244,249 'this._count.asreadonly':240 'this._count.set':262 'this._count.update':252,257 'this._error':366 'this._error.set':385,401,421 'this._loading':362 'this._loading.set':383,407 'this._state':1005,1010,1015,1062 'this._state.update':1020,1035,1043,1066,1086 'this._user':358,370,375 'this._user.asreadonly':1233 'this._user.set':397,419,1237 'this._user.update':412 'this.actions':775 'this.effect':924 'this.filter':1285,1287 'this.http.delete':1079 'this.http.get':1032,1293 'this.patchstate':929,938,943 'this.route.params.pipe':1265 'this.select':877,882,887 'this.store.dispatch':826 'this.store.loadproducts':559 'this.store.selectsignal':820,823 'this.todos':888 'this.todoservice.getall':933 'this.updater':897,907 'this.userservice.getuser':781 'this.usersubject.asobservable':1209 'this.usersubject.next':1213 'time':198 'todo':856,857,871,876,889,899,900,902,904,912,937,939 'todos.filter':890 'todoservic':868,869 'todost':855 'todostor':863 'toggletodo':906 'tolowercas':476 'toobserv':1174,1246,1284 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'tosign':301,968,1173,1245,1264 'totalcount':485 'track':544 'treat':1334 'tri':387,500,1027,1076 'trigger':925,926 'true':384,499,681,931,1024 'ts':1139 'type':121 'typescript':213,287,428,565,601,640,703,741,796,837,955,1190,1243 'ui':129 'unrel':102 'updat':82,199,410,416,633,636,894,1054,1113,1155 'updateus':409 'url':157 'usag':264,530,795 'use':15,59,95,112,1097,1106,1122,1147,1152,1180,1319 'user':305,314,315,335,337,356,389,398,405,413,414,415,574,582,614,617,622,625,626,628,634,654,655,665,687,689,718,738,739,785,787,803,805,819,1205,1208,1211,1212,1214,1226,1228,1232,1235,1236,1238 'user.name':807 'useract':611,648 'useractions.loaduser':677,778 'useractions.loaduserfailure':693,791 'useractions.loadusersuccess':685,786 'useractions.logout':701,827 'usereffect':593,764 'userid':619,780,782,1263 'userreduc':583,673 'userservic':770,772,1224 'userst':313,575,653,664,711 'userstor':327 'usersubject':1202 'v':253,254,258,259 'valid':166,1344 'valu':165 'welcom':806 'wide':144 'withcomput':434,469 'withmethod':433,489 'withstat':432,467 'work':1135 'writabl':228 'www.rx-angular.io':1316 'www.rx-angular.io/)':1315","prices":[{"id":"30ab356f-6458-47bb-b036-6515f9e49c54","listingId":"6ca9af51-09cc-4d0b-9ec0-08fccc3b7058","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:30:58.943Z"}],"sources":[{"listingId":"6ca9af51-09cc-4d0b-9ec0-08fccc3b7058","source":"github","sourceId":"sickn33/antigravity-awesome-skills/angular-state-management","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/angular-state-management","isPrimary":false,"firstSeenAt":"2026-04-18T21:30:58.943Z","lastSeenAt":"2026-04-25T00:50:26.057Z"}],"details":{"listingId":"6ca9af51-09cc-4d0b-9ec0-08fccc3b7058","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"angular-state-management","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34964,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-24T06:41:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"356c54ae364001d951e633cb446072b484a541fd","skill_md_path":"skills/angular-state-management/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/angular-state-management"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"angular-state-management","description":"Master modern Angular state management with Signals, NgRx, and RxJS. Use when setting up global state, managing component stores, choosing between state solutions, or migrating from legacy patterns."},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/angular-state-management"},"updatedAt":"2026-04-25T00:50:26.057Z"}}