Configuration

The configuration object is the whole screen description. It is provided as a value, read by every generated component, and type-checked against the shipped interface by the example below.


A configuration in full

import { ListMode } from '@smartsoft001/angular';
import { CrudFullConfig } from '@smartsoft001/crud-shell-angular';
import { Field, FieldType, Model } from '@smartsoft001/models';

@Model({ titleKey: 'title' })
export class Note {
  id!: string;

  @Field({
    type: FieldType.text,
    create: true,
    update: true,
    list: true,
    details: true,
  })
  title!: string;

  @Field({
    type: FieldType.longText,
    create: true,
    update: true,
    list: true,
    details: true,
  })
  content!: string;
}

export const noteCrudConfig: CrudFullConfig<Note> = {
  apiUrl: 'https://api.example.com/notes',
  entity: 'notes',
  type: Note,
  title: 'Notes',
  add: true,
  edit: true,
  remove: true,
  search: true,
  pagination: { limit: 25 },
  sort: { default: 'title', defaultDesc: false },
  list: { mode: ListMode.desktop },
};

The model and the configuration answer different questions. @Field says what title is and which operations may touch it; the configuration says that this feature has an add button, a search box, pages of 25 records sorted by title, and a desktop list. Neither can substitute for the other.


CrudConfig

The base class carries what every part of the feature needs: where the data is and what it is called. It is provided on its own to the services and the filter widgets, which is why routing: false accepts a plain CrudConfig.

FieldTypeDefaultEffect
apiUrlstring—Required. The base URL of the feature. The service appends /{id}, /bulk and the query string to it, and the file service resolves attachments against it.
entitystring—Required. Keys the NgRx feature slice, so every action and selector of this feature is namespaced by it.
typeany—The @Model-decorated class. The pages instantiate it to read field metadata, so a feature with generated screens needs it.
reducerFactory() => any—Replaces the default reducer registered for entity. Without it the package's own reducer is used.
baseQueryArray<ICrudFilterQueryItem>—Query items applied to every read that carries no query of its own, which is how a feature is scoped to a subset of records.

CrudFullConfig

CrudFullConfig<T> extends CrudConfig<T> with everything the generated pages need. It is required when routing is true.

FieldTypeDefaultEffect
titlestring—Required. The title of the list page.
detailsboolean or { cellPipe?; components?: { top?; bottom? } }offMakes the item page open read-only, with an edit button when edit is also set. Rows in the list become links to the record's route.
editboolean or { cellPipe?; components?: { top?; bottom? } }offAllows updates. Rows in the list become links to the record's route, and the item page renders a form with a save button.
addboolean or { components?: { top?; bottom? } }offAdds the add button to the list header, which navigates to the add route.
removebooleanoffAdds a per-row delete, behind a confirmation alert.
searchbooleanoffRenders the search box in the page header and sends its text as the free-text part of the query.
exportbooleanoffAdds the export button, whose popover offers CSV and XLSX.
pagination{ limit: number }—The page size. It seeds the first read with that limit and an offset of zero, and drives the page counter.
sortboolean or { default?: string; defaultDesc?: boolean }offEnables sorting in the list. The object form also seeds the first read with a sort field and direction.
listobject, see below—Everything specific to the collection view.
buttonsArray<IIconButtonOptions>—Extra buttons, appended to the generated ones in the list page header.
inputComponents{ [fieldKey: string]: Type<InputBaseComponent<T>> }—Replaces the generated editor for named fields in the item form.
cssClassstring—Bound as the class of the page wrapper on both pages.
variantSmartPageVariant—Threaded into the page options as the page variant, which selects the page presentation.

The list block

FieldTypeEffect
modeListModedesktop renders a table, mobile a stacked list, masonryGrid a grid. Unset behaves as desktop.
paginationModePaginationModesinglePage renders page controls, infiniteScroll loads the next page as the user reaches the end.
cellPipeICellPipe<T>Formats cell values. It receives the record and the column name and returns the string to render.
components{ top?; multi? }top is instantiated above the list. multi forces the multiselect button on, whatever the field metadata says.
resetQuery'beforeInit'Discards any filter left in the store and rebuilds it from the configuration when the page initialises.
groupsArray<ICrudListGroup>Splits the list into disclosure groups. See export, multiselect and groups.

The details mode has no inline panel

details does not add a detail panel to the list itself. It makes the rows navigate to the item page, which renders the record read-only. Nothing in the list template renders a details component, so the components block of details reaches the item page only.


The model side of the configuration

The configuration decides that a screen has a form or a table; the field metadata decides what goes in it. Both halves matter, and the per-mode blocks of @Field are where they meet.

Block on @FieldAcceptsWhat the crud screens do with it
createboolean or a modify blockThe field appears in the form when the item page is in create mode.
updateboolean or an edit blockThe field appears in the form in update mode. With multi: true it also becomes editable for a whole selection at once.
listboolean or a list blockThe field becomes a column. The block adds order, permissions and filter, which is what puts it in the filters panel.
detailsboolean or a details blockThe field is shown on the read-only view.

Two details of that metadata bite in practice, and both are documented on the models page. A mode block replaces the top-level required flag rather than inheriting it, so @Field({ required: true, create: true }) yields a field that is editable on create and not required there; the flag has to move inside the block. And permissions inside a block makes the field conditional on the caller's roles, in the form as well as in the generated column.

Model-level options matter too. @Model({ titleKey }) names the field that stands in for the record in the item page title, filters adds filters that no single field could express, and the create, update and remove blocks carry the permissions that the page service checks: when the caller lacks them, it switches add, edit or remove off on the configuration object before the page renders.


Where next

  • List page shows which of these fields the collection view reads.
  • Item page shows how add, edit and details shape the record view.
  • Filters and search covers search, baseQuery and the filter metadata.
  • Overview has the module wiring these fields are passed to.