CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ngrx--schematics

Angular CLI schematics for generating NgRx state management code including actions, reducers, effects, selectors, and feature modules.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

feature-generation.mddocs/

Feature Generation

NgRx feature generation schematic that creates complete feature modules with actions, reducers, effects, and selectors in a single command. This schematic provides a convenient way to scaffold an entire state management feature with all necessary NgRx components.

Capabilities

Feature Schematic

Generates a complete NgRx feature with all related state management files and proper module registration.

# Basic feature generation
ng generate @ngrx/schematics:feature User

# Feature with API actions
ng generate @ngrx/schematics:feature User --api

# Feature with creator functions
ng generate @ngrx/schematics:feature User --creators
/**
 * Feature schematic configuration interface
 */
interface FeatureSchema {
  /** Name of the feature (typically entity or domain name) */
  name: string;
  /** Path where feature files should be generated */
  path?: string;
  /** Angular project to target */
  project?: string;
  /** Generate files without creating a folder */
  flat?: boolean;
  /** Group feature files within folders */
  group?: boolean;
  /** Module file to register feature in */
  module?: string;
  /** Path to existing reducers file */
  reducers?: string;
  /** Generate as feature state */
  feature?: boolean;
  /** Use creator functions */
  creators?: boolean;
  /** Generate API success and failure actions */
  api?: boolean;
}

Complete Feature Structure

The feature schematic generates a comprehensive set of files for state management:

src/app/user/
├── user.actions.ts        # Action definitions
├── user.reducer.ts        # Reducer with state interface
├── user.effects.ts        # Effects for side effects
├── user.selectors.ts      # Selectors for state access
└── index.ts               # Barrel exports

Usage Examples:

# Generate complete user feature
ng generate @ngrx/schematics:feature User --creators --api

# Generate product feature with custom path
ng generate @ngrx/schematics:feature Product --path=src/app/catalog --creators

# Generate feature and register in specific module
ng generate @ngrx/schematics:feature Order --module=order/order.module.ts

Generated Actions

Creates comprehensive action definitions with optional API patterns:

// Generated feature actions
import { createAction, props } from '@ngrx/store';

// Load actions
export const loadUsers = createAction('[User/API] Load Users');

export const loadUsersSuccess = createAction(
  '[User/API] Load Users Success',
  props<{ users: User[] }>()
);

export const loadUsersFailure = createAction(
  '[User/API] Load Users Failure',
  props<{ error: any }>()
);

// CRUD actions (when --api flag is used)
export const createUser = createAction(
  '[User/API] Create User',
  props<{ user: User }>()
);

export const createUserSuccess = createAction(
  '[User/API] Create User Success',
  props<{ user: User }>()
);

export const createUserFailure = createAction(
  '[User/API] Create User Failure',
  props<{ error: any }>()
);

// Selection actions
export const selectUser = createAction(
  '[User] Select User',
  props<{ userId: string }>()
);

export const clearSelection = createAction('[User] Clear Selection');

Generated Reducer

Creates a complete reducer with state interface and action handlers:

// Generated feature reducer
import { createReducer, on } from '@ngrx/store';
import * as UserActions from './user.actions';

export const userFeatureKey = 'user';

export interface UserState {
  users: User[];
  loading: boolean;
  error: string | null;
  selectedUserId: string | null;
}

export const initialState: UserState = {
  users: [],
  loading: false,
  error: null,
  selectedUserId: null
};

export const userReducer = createReducer(
  initialState,
  
  on(UserActions.loadUsers, (state) => ({
    ...state,
    loading: true,
    error: null
  })),
  
  on(UserActions.loadUsersSuccess, (state, { users }) => ({
    ...state,
    users,
    loading: false
  })),
  
  on(UserActions.loadUsersFailure, (state, { error }) => ({
    ...state,
    loading: false,
    error
  })),
  
  on(UserActions.selectUser, (state, { userId }) => ({
    ...state,
    selectedUserId: userId
  })),
  
  on(UserActions.clearSelection, (state) => ({
    ...state,
    selectedUserId: null
  }))
);

Generated Effects

Creates effects for handling side effects and API calls:

// Generated feature effects
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { catchError, map, switchMap } from 'rxjs/operators';
import { of } from 'rxjs';
import * as UserActions from './user.actions';
import { UserService } from './user.service';

@Injectable()
export class UserEffects {
  
  loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserActions.loadUsers),
      switchMap(() =>
        this.userService.getUsers().pipe(
          map(users => UserActions.loadUsersSuccess({ users })),
          catchError(error => of(UserActions.loadUsersFailure({ error })))
        )
      )
    )
  );

  createUser$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserActions.createUser),
      switchMap(({ user }) =>
        this.userService.createUser(user).pipe(
          map(createdUser => UserActions.createUserSuccess({ user: createdUser })),
          catchError(error => of(UserActions.createUserFailure({ error })))
        )
      )
    )
  );

  constructor(
    private actions$: Actions,
    private userService: UserService
  ) {}
}

Generated Selectors

Creates comprehensive selectors for accessing feature state:

// Generated feature selectors
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { UserState } from './user.reducer';

export const selectUserState = createFeatureSelector<UserState>('user');

export const selectUsers = createSelector(
  selectUserState,
  (state: UserState) => state.users
);

export const selectUsersLoading = createSelector(
  selectUserState,
  (state: UserState) => state.loading
);

export const selectUsersError = createSelector(
  selectUserState,
  (state: UserState) => state.error
);

export const selectSelectedUserId = createSelector(
  selectUserState,
  (state: UserState) => state.selectedUserId
);

export const selectSelectedUser = createSelector(
  selectUsers,
  selectSelectedUserId,
  (users, selectedId) => users.find(user => user.id === selectedId)
);

Module Integration

The feature schematic automatically registers the feature in the specified module:

// Module registration
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import * as fromUser from './user.reducer';
import { UserEffects } from './user.effects';

@NgModule({
  imports: [
    StoreModule.forFeature(fromUser.userFeatureKey, fromUser.userReducer),
    EffectsModule.forFeature([UserEffects])
  ]
})
export class UserModule {}

Barrel Exports

Creates comprehensive barrel exports for easy importing:

// Generated index.ts
export * from './user.actions';
export * from './user.reducer';
export * from './user.effects';
export * from './user.selectors';

Creator Functions Support

When using --creators flag, all generated code uses NgRx creator functions:

/**
 * Creator function patterns used in generated code
 */
interface CreatorPatterns {
  /** Actions with createAction */
  actions: 'createAction(type, props<PayloadType>())';
  /** Reducers with createReducer */
  reducers: 'createReducer(initialState, on(action, reducer))';
  /** Effects with createEffect */
  effects: 'createEffect(() => source$)';
  /** Selectors with createSelector */
  selectors: 'createSelector(input, projector)';
}

Feature Configuration

The generated feature includes proper TypeScript configuration and type safety:

// Type-safe feature configuration
export interface AppState {
  [fromUser.userFeatureKey]: fromUser.UserState;
}

// Feature key constant
export const userFeatureKey = 'user';

// State interface
export interface UserState {
  users: User[];
  loading: boolean;
  error: string | null;
  selectedUserId: string | null;
}

Testing Setup

Generated features include testing utilities and examples:

// Feature testing setup
describe('User Feature', () => {
  let store: MockStore;
  let effects: UserEffects;
  let service: jasmine.SpyObj<UserService>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        provideMockStore({ initialState }),
        UserEffects,
        {
          provide: UserService,
          useValue: jasmine.createSpyObj('UserService', ['getUsers'])
        }
      ]
    });

    store = TestBed.inject(MockStore);
    effects = TestBed.inject(UserEffects);
    service = TestBed.inject(UserService) as jasmine.SpyObj<UserService>;
  });

  it('should load users', () => {
    const users = [{ id: '1', name: 'John' }];
    store.dispatch(UserActions.loadUsers());
    
    store.select(selectUsers).subscribe(result => {
      expect(result).toEqual(users);
    });
  });
});

Performance Considerations

Generated features include performance optimizations:

// Optimized state updates
on(UserActions.updateUserSuccess, (state, { user }) => {
  const index = state.users.findIndex(u => u.id === user.id);
  if (index === -1) return state;
  
  const users = [...state.users];
  users[index] = user;
  
  return { ...state, users };
});

// Memoized selectors
export const selectUserById = (id: string) => createSelector(
  selectUsers,
  (users) => users.find(user => user.id === id)
);

docs

action-generation.md

component-store.md

container-components.md

data-services.md

effect-generation.md

entity-management.md

feature-generation.md

index.md

ngrx-push-migration.md

reducer-generation.md

selector-generation.md

store-setup.md

utility-functions.md

tile.json