or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

action-generation.mdcomponent-store.mdcontainer-components.mddata-services.mdeffect-generation.mdentity-management.mdfeature-generation.mdindex.mdngrx-push-migration.mdreducer-generation.mdselector-generation.mdstore-setup.mdutility-functions.md

selector-generation.mddocs/

0

# Selector Generation

1

2

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.

3

4

## Capabilities

5

6

### Selector Schematic

7

8

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

9

10

```bash

11

# Basic selector generation

12

ng generate @ngrx/schematics:selector User

13

14

# Feature selector generation

15

ng generate @ngrx/schematics:selector User --feature

16

17

# Grouped selectors

18

ng generate @ngrx/schematics:selector User --group

19

```

20

21

```typescript { .api }

22

/**

23

* Selector schematic configuration interface

24

*/

25

interface SelectorSchema {

26

/** Name of the selector (typically entity or feature name) */

27

name: string;

28

/** Path where selector files should be generated */

29

path?: string;

30

/** Angular project to target */

31

project?: string;

32

/** Generate files without creating a folder */

33

flat?: boolean;

34

/** Group selector files within folders */

35

group?: boolean;

36

/** Generate as feature selector */

37

feature?: boolean;

38

}

39

```

40

41

### Basic Selector Generation

42

43

Creates selector functions with proper state access and derived computations.

44

45

```typescript

46

// Generated selector functions

47

import { createFeatureSelector, createSelector } from '@ngrx/store';

48

import { UserState } from './user.reducer';

49

50

// Feature selector

51

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

52

53

// Base selectors

54

export const selectUsers = createSelector(

55

selectUserState,

56

(state: UserState) => state.users

57

);

58

59

export const selectUsersLoading = createSelector(

60

selectUserState,

61

(state: UserState) => state.loading

62

);

63

64

export const selectUsersError = createSelector(

65

selectUserState,

66

(state: UserState) => state.error

67

);

68

69

export const selectSelectedUserId = createSelector(

70

selectUserState,

71

(state: UserState) => state.selectedUserId

72

);

73

74

// Derived selectors

75

export const selectSelectedUser = createSelector(

76

selectUsers,

77

selectSelectedUserId,

78

(users, selectedId) => users.find(user => user.id === selectedId)

79

);

80

81

export const selectActiveUsers = createSelector(

82

selectUsers,

83

(users) => users.filter(user => user.active)

84

);

85

86

export const selectUserCount = createSelector(

87

selectUsers,

88

(users) => users.length

89

);

90

91

export const selectUsersLoadingState = createSelector(

92

selectUsersLoading,

93

selectUsersError,

94

(loading, error) => ({

95

loading,

96

error,

97

loaded: !loading && !error

98

})

99

);

100

```

101

102

**Usage Examples:**

103

104

```bash

105

# Generate user selectors

106

ng generate @ngrx/schematics:selector User --feature

107

108

# Generate product selectors with custom path

109

ng generate @ngrx/schematics:selector Product --path=src/app/catalog --feature

110

111

# Generate grouped selectors

112

ng generate @ngrx/schematics:selector Order --group --feature

113

```

114

115

### Feature State Selectors

116

117

Selectors for accessing feature-specific state slices.

118

119

```typescript { .api }

120

/**

121

* Feature selector pattern for modular state access

122

*/

123

interface FeatureSelectorPattern {

124

/** Root feature selector */

125

featureSelector: 'createFeatureSelector<FeatureState>(featureKey)';

126

/** Property selectors from feature state */

127

propertySelectors: 'createSelector(featureSelector, state => state.property)';

128

/** Derived selectors combining multiple properties */

129

derivedSelectors: 'createSelector(selector1, selector2, (val1, val2) => computation)';

130

}

131

```

132

133

```typescript

134

// Feature selector example

135

export const selectAppState = createFeatureSelector<AppState>('app');

136

137

export const selectUserFeature = createSelector(

138

selectAppState,

139

(state: AppState) => state.user

140

);

141

142

export const selectProductFeature = createSelector(

143

selectAppState,

144

(state: AppState) => state.product

145

);

146

147

// Cross-feature selectors

148

export const selectUserProducts = createSelector(

149

selectUsers,

150

selectProducts,

151

selectSelectedUserId,

152

(users, products, selectedUserId) => {

153

const selectedUser = users.find(user => user.id === selectedUserId);

154

return selectedUser

155

? products.filter(product => product.userId === selectedUser.id)

156

: [];

157

}

158

);

159

```

160

161

### Entity Selectors

162

163

Specialized selectors for working with normalized entity state.

164

165

```typescript

166

// Entity selector patterns

167

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

168

169

export interface UserEntityState extends EntityState<User> {

170

selectedUserId: string | null;

171

loading: boolean;

172

error: string | null;

173

}

174

175

export const userAdapter = createEntityAdapter<User>();

176

177

// Entity selectors from adapter

178

export const {

179

selectIds: selectUserIds,

180

selectEntities: selectUserEntities,

181

selectAll: selectAllUsers,

182

selectTotal: selectUserTotal

183

} = userAdapter.getSelectors(selectUserState);

184

185

// Custom entity selectors

186

export const selectUserById = (id: string) => createSelector(

187

selectUserEntities,

188

(entities) => entities[id]

189

);

190

191

export const selectUsersByStatus = (status: UserStatus) => createSelector(

192

selectAllUsers,

193

(users) => users.filter(user => user.status === status)

194

);

195

```

196

197

### Complex Derived Selectors

198

199

Advanced selectors that perform computations and transformations.

200

201

```typescript

202

// Complex derived selectors

203

export const selectUserStatistics = createSelector(

204

selectAllUsers,

205

(users) => ({

206

total: users.length,

207

active: users.filter(user => user.active).length,

208

inactive: users.filter(user => !user.active).length,

209

byRole: users.reduce((acc, user) => {

210

acc[user.role] = (acc[user.role] || 0) + 1;

211

return acc;

212

}, {} as Record<string, number>)

213

})

214

);

215

216

export const selectSortedUsers = createSelector(

217

selectAllUsers,

218

(users) => users.slice().sort((a, b) => a.name.localeCompare(b.name))

219

);

220

221

export const selectFilteredUsers = (filter: UserFilter) => createSelector(

222

selectAllUsers,

223

(users) => users.filter(user => {

224

if (filter.name && !user.name.toLowerCase().includes(filter.name.toLowerCase())) {

225

return false;

226

}

227

if (filter.role && user.role !== filter.role) {

228

return false;

229

}

230

if (filter.active !== undefined && user.active !== filter.active) {

231

return false;

232

}

233

return true;

234

})

235

);

236

237

export const selectPaginatedUsers = createSelector(

238

selectSortedUsers,

239

(users, props: { page: number; pageSize: number }) => {

240

const start = props.page * props.pageSize;

241

const end = start + props.pageSize;

242

return {

243

data: users.slice(start, end),

244

total: users.length,

245

page: props.page,

246

pageSize: props.pageSize,

247

totalPages: Math.ceil(users.length / props.pageSize)

248

};

249

}

250

);

251

```

252

253

### Parameterized Selectors

254

255

Selectors that accept parameters for dynamic data access.

256

257

```typescript { .api }

258

/**

259

* Parameterized selector patterns

260

*/

261

interface ParameterizedSelectorPatterns {

262

/** Selector with props parameter */

263

withProps: 'createSelector(selector, (state, props) => computation)';

264

/** Factory function returning selector */

265

factory: '(param) => createSelector(selector, state => computation)';

266

/** Memoized parameter selector */

267

memoized: 'createSelector([selector], param => createSelector(...))';

268

}

269

```

270

271

```typescript

272

// Parameterized selectors

273

export const selectUserById = createSelector(

274

selectUserEntities,

275

(entities, props: { id: string }) => entities[props.id]

276

);

277

278

export const selectUsersByRole = (role: UserRole) => createSelector(

279

selectAllUsers,

280

(users) => users.filter(user => user.role === role)

281

);

282

283

// Memoized parameter selectors

284

const selectUsersByRoleMemoized = (() => {

285

const cache = new Map();

286

return (role: UserRole) => {

287

if (!cache.has(role)) {

288

cache.set(role, createSelector(

289

selectAllUsers,

290

(users) => users.filter(user => user.role === role)

291

));

292

}

293

return cache.get(role);

294

};

295

})();

296

```

297

298

### Selector Testing

299

300

Generated selectors include comprehensive testing support.

301

302

```typescript

303

// Selector testing examples

304

describe('User Selectors', () => {

305

const initialState: UserState = {

306

users: [

307

{ id: '1', name: 'John', active: true, role: 'admin' },

308

{ id: '2', name: 'Jane', active: false, role: 'user' }

309

],

310

loading: false,

311

error: null,

312

selectedUserId: '1'

313

};

314

315

it('should select users', () => {

316

const result = selectUsers.projector(initialState);

317

expect(result).toEqual(initialState.users);

318

});

319

320

it('should select active users', () => {

321

const result = selectActiveUsers.projector(initialState.users);

322

expect(result).toEqual([{ id: '1', name: 'John', active: true, role: 'admin' }]);

323

});

324

325

it('should select user count', () => {

326

const result = selectUserCount.projector(initialState.users);

327

expect(result).toBe(2);

328

});

329

330

it('should select selected user', () => {

331

const result = selectSelectedUser.projector(

332

initialState.users,

333

initialState.selectedUserId

334

);

335

expect(result).toEqual({ id: '1', name: 'John', active: true, role: 'admin' });

336

});

337

});

338

```

339

340

### Performance Optimizations

341

342

Generated selectors include memoization and performance best practices.

343

344

```typescript { .api }

345

/**

346

* Selector performance optimization patterns

347

*/

348

interface SelectorOptimizations {

349

/** Memoization for expensive computations */

350

memoization: 'createSelector automatically memoizes results';

351

/** Shallow equality checking */

352

shallowEqual: 'Selectors use reference equality by default';

353

/** Custom equality functions */

354

customEquality: 'createSelector(inputs, projector, equalityFn)';

355

/** Reselect optimization */

356

reselectPattern: 'Compose selectors to minimize recalculation';

357

}

358

```

359

360

```typescript

361

// Performance-optimized selectors

362

import { isEqual } from 'lodash-es';

363

364

// Custom equality for deep object comparison

365

export const selectUserPreferences = createSelector(

366

selectUserState,

367

(state: UserState) => state.preferences,

368

{

369

memoizeOptions: {

370

equalityCheck: isEqual

371

}

372

}

373

);

374

375

// Optimized composition

376

export const selectUserDashboard = createSelector(

377

selectUsers,

378

selectUsersLoading,

379

selectUsersError,

380

selectUserStatistics,

381

(users, loading, error, statistics) => ({

382

users: users.slice(0, 10), // Limit for performance

383

loading,

384

error,

385

statistics,

386

hasMore: users.length > 10

387

})

388

);

389

```

390

391

### Router Selectors

392

393

Selectors that integrate with Angular Router state.

394

395

```typescript

396

// Router integration selectors

397

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

398

399

export const {

400

selectCurrentRoute,

401

selectRouteParams,

402

selectRouteData,

403

selectUrl

404

} = getRouterSelectors();

405

406

export const selectUserIdFromRoute = createSelector(

407

selectRouteParams,

408

(params) => params['id']

409

);

410

411

export const selectCurrentUser = createSelector(

412

selectUsers,

413

selectUserIdFromRoute,

414

(users, userId) => users.find(user => user.id === userId)

415

);

416

```

417

418

### Selector Composition

419

420

Patterns for composing complex selectors from simpler ones.

421

422

```typescript

423

// Selector composition patterns

424

export const selectUserListViewModel = createSelector(

425

selectUsers,

426

selectUsersLoading,

427

selectUsersError,

428

selectSelectedUserId,

429

selectUserStatistics,

430

(users, loading, error, selectedId, statistics) => ({

431

users,

432

loading,

433

error,

434

selectedId,

435

statistics,

436

isEmpty: users.length === 0,

437

hasSelection: selectedId !== null,

438

selectedUser: users.find(user => user.id === selectedId)

439

})

440

);

441

442

export const selectUserFormViewModel = createSelector(

443

selectSelectedUser,

444

selectUsersLoading,

445

selectUsersError,

446

(user, loading, error) => ({

447

user,

448

isEditing: user !== undefined,

449

isLoading: loading,

450

error,

451

canSave: user !== undefined && !loading

452

})

453

);

454

```