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

selector-generation.mddocs/

Selector Generation

NgRx selector generation schematic that creates memoized selector functions for efficiently accessing and computing derived state from the NgRx store. Selectors provide optimized, composable ways to extract and transform state data with automatic memoization.

Capabilities

Selector Schematic

Generates NgRx selectors using createSelector() with proper state typing and memoization.

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

# Feature selector generation
ng generate @ngrx/schematics:selector User --feature

# Grouped selectors
ng generate @ngrx/schematics:selector User --group
/**
 * Selector schematic configuration interface
 */
interface SelectorSchema {
  /** Name of the selector (typically entity or feature name) */
  name: string;
  /** Path where selector files should be generated */
  path?: string;
  /** Angular project to target */
  project?: string;
  /** Generate files without creating a folder */
  flat?: boolean;
  /** Group selector files within folders */
  group?: boolean;
  /** Generate as feature selector */
  feature?: boolean;
}

Basic Selector Generation

Creates selector functions with proper state access and derived computations.

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

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

// Base selectors
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
);

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

export const selectActiveUsers = createSelector(
  selectUsers,
  (users) => users.filter(user => user.active)
);

export const selectUserCount = createSelector(
  selectUsers,
  (users) => users.length
);

export const selectUsersLoadingState = createSelector(
  selectUsersLoading,
  selectUsersError,
  (loading, error) => ({
    loading,
    error,
    loaded: !loading && !error
  })
);

Usage Examples:

# Generate user selectors
ng generate @ngrx/schematics:selector User --feature

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

# Generate grouped selectors
ng generate @ngrx/schematics:selector Order --group --feature

Feature State Selectors

Selectors for accessing feature-specific state slices.

/**
 * Feature selector pattern for modular state access
 */
interface FeatureSelectorPattern {
  /** Root feature selector */
  featureSelector: 'createFeatureSelector<FeatureState>(featureKey)';
  /** Property selectors from feature state */
  propertySelectors: 'createSelector(featureSelector, state => state.property)';
  /** Derived selectors combining multiple properties */
  derivedSelectors: 'createSelector(selector1, selector2, (val1, val2) => computation)';
}
// Feature selector example
export const selectAppState = createFeatureSelector<AppState>('app');

export const selectUserFeature = createSelector(
  selectAppState,
  (state: AppState) => state.user
);

export const selectProductFeature = createSelector(
  selectAppState,  
  (state: AppState) => state.product
);

// Cross-feature selectors
export const selectUserProducts = createSelector(
  selectUsers,
  selectProducts,
  selectSelectedUserId,
  (users, products, selectedUserId) => {
    const selectedUser = users.find(user => user.id === selectedUserId);
    return selectedUser 
      ? products.filter(product => product.userId === selectedUser.id)
      : [];
  }
);

Entity Selectors

Specialized selectors for working with normalized entity state.

// Entity selector patterns
import { createEntityAdapter, EntityState } from '@ngrx/entity';

export interface UserEntityState extends EntityState<User> {
  selectedUserId: string | null;
  loading: boolean;
  error: string | null;
}

export const userAdapter = createEntityAdapter<User>();

// Entity selectors from adapter
export const {
  selectIds: selectUserIds,
  selectEntities: selectUserEntities,
  selectAll: selectAllUsers,
  selectTotal: selectUserTotal
} = userAdapter.getSelectors(selectUserState);

// Custom entity selectors
export const selectUserById = (id: string) => createSelector(
  selectUserEntities,
  (entities) => entities[id]
);

export const selectUsersByStatus = (status: UserStatus) => createSelector(
  selectAllUsers,
  (users) => users.filter(user => user.status === status)
);

Complex Derived Selectors

Advanced selectors that perform computations and transformations.

// Complex derived selectors
export const selectUserStatistics = createSelector(
  selectAllUsers,
  (users) => ({
    total: users.length,
    active: users.filter(user => user.active).length,
    inactive: users.filter(user => !user.active).length,
    byRole: users.reduce((acc, user) => {
      acc[user.role] = (acc[user.role] || 0) + 1;
      return acc;
    }, {} as Record<string, number>)
  })
);

export const selectSortedUsers = createSelector(
  selectAllUsers,
  (users) => users.slice().sort((a, b) => a.name.localeCompare(b.name))
);

export const selectFilteredUsers = (filter: UserFilter) => createSelector(
  selectAllUsers,
  (users) => users.filter(user => {
    if (filter.name && !user.name.toLowerCase().includes(filter.name.toLowerCase())) {
      return false;
    }
    if (filter.role && user.role !== filter.role) {
      return false;
    }
    if (filter.active !== undefined && user.active !== filter.active) {
      return false;
    }
    return true;
  })
);

export const selectPaginatedUsers = createSelector(
  selectSortedUsers,
  (users, props: { page: number; pageSize: number }) => {
    const start = props.page * props.pageSize;
    const end = start + props.pageSize;
    return {
      data: users.slice(start, end),
      total: users.length,
      page: props.page,
      pageSize: props.pageSize,
      totalPages: Math.ceil(users.length / props.pageSize)
    };
  }
);

Parameterized Selectors

Selectors that accept parameters for dynamic data access.

/**
 * Parameterized selector patterns
 */
interface ParameterizedSelectorPatterns {
  /** Selector with props parameter */
  withProps: 'createSelector(selector, (state, props) => computation)';
  /** Factory function returning selector */
  factory: '(param) => createSelector(selector, state => computation)';
  /** Memoized parameter selector */
  memoized: 'createSelector([selector], param => createSelector(...))';
}
// Parameterized selectors
export const selectUserById = createSelector(
  selectUserEntities,
  (entities, props: { id: string }) => entities[props.id]
);

export const selectUsersByRole = (role: UserRole) => createSelector(
  selectAllUsers,
  (users) => users.filter(user => user.role === role)
);

// Memoized parameter selectors
const selectUsersByRoleMemoized = (() => {
  const cache = new Map();
  return (role: UserRole) => {
    if (!cache.has(role)) {
      cache.set(role, createSelector(
        selectAllUsers,
        (users) => users.filter(user => user.role === role)
      ));
    }
    return cache.get(role);
  };
})();

Selector Testing

Generated selectors include comprehensive testing support.

// Selector testing examples
describe('User Selectors', () => {
  const initialState: UserState = {
    users: [
      { id: '1', name: 'John', active: true, role: 'admin' },
      { id: '2', name: 'Jane', active: false, role: 'user' }
    ],
    loading: false,
    error: null,
    selectedUserId: '1'
  };

  it('should select users', () => {
    const result = selectUsers.projector(initialState);
    expect(result).toEqual(initialState.users);
  });

  it('should select active users', () => {
    const result = selectActiveUsers.projector(initialState.users);
    expect(result).toEqual([{ id: '1', name: 'John', active: true, role: 'admin' }]);
  });

  it('should select user count', () => {
    const result = selectUserCount.projector(initialState.users);
    expect(result).toBe(2);
  });

  it('should select selected user', () => {
    const result = selectSelectedUser.projector(
      initialState.users,
      initialState.selectedUserId
    );
    expect(result).toEqual({ id: '1', name: 'John', active: true, role: 'admin' });
  });
});

Performance Optimizations

Generated selectors include memoization and performance best practices.

/**
 * Selector performance optimization patterns
 */
interface SelectorOptimizations {
  /** Memoization for expensive computations */
  memoization: 'createSelector automatically memoizes results';
  /** Shallow equality checking */
  shallowEqual: 'Selectors use reference equality by default';
  /** Custom equality functions */
  customEquality: 'createSelector(inputs, projector, equalityFn)';
  /** Reselect optimization */
  reselectPattern: 'Compose selectors to minimize recalculation';
}
// Performance-optimized selectors
import { isEqual } from 'lodash-es';

// Custom equality for deep object comparison
export const selectUserPreferences = createSelector(
  selectUserState,
  (state: UserState) => state.preferences,
  {
    memoizeOptions: {
      equalityCheck: isEqual
    }
  }
);

// Optimized composition
export const selectUserDashboard = createSelector(
  selectUsers,
  selectUsersLoading,
  selectUsersError,
  selectUserStatistics,
  (users, loading, error, statistics) => ({
    users: users.slice(0, 10), // Limit for performance
    loading,
    error,
    statistics,
    hasMore: users.length > 10
  })
);

Router Selectors

Selectors that integrate with Angular Router state.

// Router integration selectors
import { getRouterSelectors } from '@ngrx/router-store';

export const {
  selectCurrentRoute,
  selectRouteParams,
  selectRouteData,
  selectUrl
} = getRouterSelectors();

export const selectUserIdFromRoute = createSelector(
  selectRouteParams,
  (params) => params['id']
);

export const selectCurrentUser = createSelector(
  selectUsers,
  selectUserIdFromRoute,
  (users, userId) => users.find(user => user.id === userId)
);

Selector Composition

Patterns for composing complex selectors from simpler ones.

// Selector composition patterns
export const selectUserListViewModel = createSelector(
  selectUsers,
  selectUsersLoading,
  selectUsersError,
  selectSelectedUserId,
  selectUserStatistics,
  (users, loading, error, selectedId, statistics) => ({
    users,
    loading,
    error,
    selectedId,
    statistics,
    isEmpty: users.length === 0,
    hasSelection: selectedId !== null,
    selectedUser: users.find(user => user.id === selectedId)
  })
);

export const selectUserFormViewModel = createSelector(
  selectSelectedUser,
  selectUsersLoading,
  selectUsersError,
  (user, loading, error) => ({
    user,
    isEditing: user !== undefined,
    isLoading: loading,
    error,
    canSave: user !== undefined && !loading
  })
);

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