Utils
A schematic for renaming collection-based properties in your ngrx store and related files. Useful for refactoring collection names or completing migrations the automatic migrator couldn't handle.
ng g @ngrx-traits/signals:rename-collection --old-name=<name> [--new-name=<name>] [--path=<path>]
| Parameter | Required | Default | Description |
|---|---|---|---|
--old-name |
Yes | - | Current collection name to find |
--new-name |
No | oldName | New collection name (defaults to oldName for v21 migration) |
--path |
No | src |
Directory to search for files |
If the automatic migration missed some files, use this schematic:
# Adds 'Entities' suffix to 'product' collection properties
ng g @ngrx-traits/signals:rename-collection --old-name=product --path=src/app
This transforms:
// Before
store.productCallStatus();
store.isProductLoading();
store.loadProductPage(1);
store.productFilter();
// After
store.productEntitiesCallStatus();
store.isProductEntitiesLoading();
store.loadProductEntitiesPage({ pageIndex: 1 });
store.productEntitiesFilter();
Rename a collection from product to item:
ng g @ngrx-traits/signals:rename-collection --old-name=product --new-name=item --path=src/app
This transforms a complex store feature with filter, pagination, sort and loading:
// Before
const productEntityConfig = entityConfig({
entity: type<Product>(),
collection: 'product',
});
const productsStoreFeature = signalStoreFeature(
withEntities(productEntityConfig),
withCallStatus({
...productEntityConfig,
initialValue: 'loading',
errorType: type<string>(),
}),
withEntitiesRemoteFilter({
...productEntityConfig,
defaultFilter: { search: '' },
}),
withEntitiesRemotePagination({
...productEntityConfig,
pageSize: 10,
}),
withEntitiesRemoteSort({
...productEntityConfig,
defaultSort: { field: 'name', direction: 'asc' },
}),
withEntitiesLoadingCall(
({ productEntitiesPagedRequest, productEntitiesFilter, productEntitiesSort }) => ({
...productEntityConfig,
fetchEntities: async () => {
const res = await lastValueFrom(
inject(ProductService).getProducts({
search: productEntitiesFilter().search,
skip: productEntitiesPagedRequest().startIndex,
take: productEntitiesPagedRequest().size,
sortAscending: productEntitiesSort().direction === 'asc',
sortColumn: productEntitiesSort().field,
}),
);
return { entities: res.resultList, total: res.total };
},
}),
),
);
// Usages
store.productEntitiesFilter();
store.productEntitiesSort();
store.productEntitiesCurrentPage();
store.isProductEntitiesLoading();
store.loadProductEntitiesPage({ pageIndex: 1 });
// After
const productEntityConfig = entityConfig({
entity: type<Product>(),
collection: 'item',
});
const productsStoreFeature = signalStoreFeature(
withEntities(productEntityConfig),
withCallStatus({
...productEntityConfig,
initialValue: 'loading',
errorType: type<string>(),
}),
withEntitiesRemoteFilter({
...productEntityConfig,
defaultFilter: { search: '' },
}),
withEntitiesRemotePagination({
...productEntityConfig,
pageSize: 10,
}),
withEntitiesRemoteSort({
...productEntityConfig,
defaultSort: { field: 'name', direction: 'asc' },
}),
withEntitiesLoadingCall(
({ itemEntitiesPagedRequest, itemEntitiesFilter, itemEntitiesSort }) => ({
...productEntityConfig,
fetchEntities: async () => {
const res = await lastValueFrom(
inject(ProductService).getProducts({
search: itemEntitiesFilter().search,
skip: itemEntitiesPagedRequest().startIndex,
take: itemEntitiesPagedRequest().size,
sortAscending: itemEntitiesSort().direction === 'asc',
sortColumn: itemEntitiesSort().field,
}),
);
return { entities: res.resultList, total: res.total };
},
}),
),
);
// Usages
store.itemEntitiesFilter();
store.itemEntitiesSort();
store.itemEntitiesCurrentPage();
store.isItemEntitiesLoading();
store.loadItemEntitiesPage(1);
The schematic renames all collection-based properties:
{old}CallStatus → {new}EntitiesCallStatus{old}Error → {new}EntitiesErroris{Old}Loading → is{New}EntitiesLoadingis{Old}Loaded → is{New}EntitiesLoadedset{Old}Loading → set{New}EntitiesLoadingset{Old}Loaded → set{New}EntitiesLoadedset{Old}Error → set{New}EntitiesError{old}Pagination → {new}EntitiesPagination{old}CurrentPage → {new}EntitiesCurrentPage{old}PagedRequest → {new}EntitiesPagedRequestload{Old}Page → load{New}EntitiesPageset{Old}PagedResult → set{New}EntitiesPagedResultloadMore{Old} → loadMore{New}Entitiesload{Old}NextPage → load{New}EntitiesNextPageload{Old}PreviousPage → load{New}EntitiesPreviousPageload{Old}FirstPage → load{New}EntitiesFirstPage{old}Filter → {new}EntitiesFilteris{Old}FilterChanged → is{New}EntitiesFilterChangedreset{Old}Filter → reset{New}EntitiesFilterfilter{Old}Entities → filter{New}Entities{old}Sort → {new}EntitiesSortsort{Old} → sort{New}Entities{old}IdsSelectedMap → {new}IdsSelectedMap{old}EntitiesSelected → {new}EntitiesSelected{old}IdsSelected → {new}IdsSelectedisAll{Old}Selected → isAll{New}EntitiesSelectedtoggleSelectAll{Old}Entities → toggleSelectAll{New}Entitiesselect{Old}Entities → select{New}Entitiesdeselect{Old}Entities → deselect{New}Entitiesclear{Old}Selection → clear{New}EntitiesSelection{old}Entities → {new}Entities{old}Ids → {new}Ids{old}EntityMap → {new}EntityMapcollection: '{old}' → collection: '{new}'The schematic processes:
.ts files (TypeScript).html files (templates)Files in node_modules and .git directories are automatically excluded.
# Rename multiple collections
ng g @ngrx-traits/signals:rename-collection --old-name=product
ng g @ngrx-traits/signals:rename-collection --old-name=order
ng g @ngrx-traits/signals:rename-collection --old-name=user