Skip to main content

build-angular-lists-and-forms

Build ABP Angular list and form pages the framework way — server-side paged/sorted/filtered lists via ListService, and reactive forms with ABP's automatic validation. USE FOR: ListService with component-scoped providers, hookToQuery returning PagedResultDto, get() refresh, page/maxResultCount/filter/sortKey/sortOrder setters, requestStatus$ (isLoading$ is deprecated), totalCount, LIST_QUERY_DEBOUNCE_TIME, reactive forms validated automatically by @ngx-validate/core, DEFAULT_VALIDATION_BLUEPRINTS + withValidationBluePrint localization keys, abp-validation-error, the skipValidation opt-out, and config-driven abp-dynamic-form (DynamicFormComponent + FormFieldConfig). DO NOT USE FOR: proxy consumption, menus, permission directives (angular-ui); proxy generation/regeneration (abp-cli-commands); adding entity/table/toolbar/form-prop extensions to a shipped module (extend-angular-module-ui); component testing (test-angular-ui); server-side application-service or DTO design (build-crud-application-services).

Zur Installation springen

Quellinformationen

Repository
abpframework/abp-skills
Letzte Quellaktivität
20. Juli 2026 um 03:24
Erkannte Sprache von SKILL.md
Englisch
Sterne
18
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
build-angular-lists-and-forms
description
Build ABP Angular list and form pages the framework way — server-side paged/sorted/filtered lists via ListService, and reactive forms with ABP's automatic validation. USE FOR: ListService with component-scoped providers, hookToQuery returning PagedResultDto, get() refresh, page/maxResultCount/filter/sortKey/sortOrder setters, requestStatus$ (isLoading$ is deprecated), totalCount, LIST_QUERY_DEBOUNCE_TIME, reactive forms validated automatically by @ngx-validate/core, DEFAULT_VALIDATION_BLUEPRINTS + withValidationBluePrint localization keys, abp-validation-error, the skipValidation opt-out, and config-driven abp-dynamic-form (DynamicFormComponent + FormFieldConfig). DO NOT USE FOR: proxy consumption, menus, permission directives (angular-ui); proxy generation/regeneration (abp-cli-commands); adding entity/table/toolbar/form-prop extensions to a shipped module (extend-angular-module-ui); component testing (test-angular-ui); server-side application-service or DTO design (build-crud-application-services).
license
MIT
# Build Angular Lists and Forms (ABP) ABP's Angular UI ships two pieces of infrastructure that AI models routinely re-implement by hand: `ListService` for server-side paged data, and automatic reactive-form validation. Use them instead of hand-rolling paging state or manual error markup. ## When to Use - A list/table page bound to a paged ABP endpoint (`GetListAsync(input)` returning `PagedResultDto<T>`). - Server-side paging, sorting, and search whose subscriptions are cleaned up on component destroy (not leaked). - A reactive create/edit form that should show ABP's localized validation messages automatically. - An arbitrary (non-entity) form you want to drive from a config array rather than template markup. ## When Not to Use - **Consuming generated proxies, menu routes, permission directives** — use **angular-ui**. - **Generating/regenerating the proxies** (`abp generate-proxy -t ng` or the NX generator) — use **abp-cli-commands**. - **Adding columns/actions/form fields to a *shipped* module's page** (Identity, etc.) — use **extend-angular-module-ui**; that's the extension system, a different API. - **Testing these components** — use **test-angular-ui**. - **Designing the server-side app service / DTOs** — use **build-crud-application-services**. ## Lists with `ListService` `ListService` (from `@abp/ng.core`) owns the query state (page, size, filter, sort) and re-runs the request when any of it changes. It **must be component-scoped** — put it in the component's `providers`, never `providedIn: 'root'` — so its subscriptions are cleaned up on destroy. ```ts import { ListService, PagedResultDto } from '@abp/ng.core'; import { Component, inject, OnInit } from '@angular/core'; import { BookService, BookDto } from '../proxy/books'; @Component({ selector: 'app-books', templateUrl: './books.component.html', providers: [ListService], // component-scoped — REQUIRED }) export class BooksComponent implements OnInit { readonly list = inject(ListService); private bookService = inject(BookService); items: BookDto[] = []; count = 0; requestStatus$ = this.list.requestStatus$; // 'idle' | 'loading' | 'success' | 'error' ngOnInit() { // callback receives the composed query, returns Observable<PagedResultDto<T>> this.list .hookToQuery(query => this.bookService.getList(query)) .subscribe(res => { this.items = res.items ?? []; this.count = res.totalCount ?? 0; // read the count off the response }); } } ``` The query object `hookToQuery` passes to your callback is `{ filter, maxResultCount, skipCount, sorting }` — `sorting` is `"field asc|desc"` and `skipCount = page * maxResultCount`, which matches ABP's `PagedAndSortedResultRequestDto`. - **Search:** two-way-bind an input to `list.filter`; the setter re-runs the query. - **Sort:** set `list.sortKey` / `list.sortOrder` (from a table header click). - **Page/size:** set `list.page` / `list.maxResultCount`. - **Refresh after create/update/delete:** call `list.get()` (or `list.getWithoutPageReset()` to stay on the current page). - **Extra query params:** spread the query — `query => this.bookService.getList({ ...query, authorId })`. Debounce is `LIST_QUERY_DEBOUNCE_TIME` (default 300 ms); provide the token alongside `ListService` to change it. ## Reactive forms with automatic validation ABP validates reactive forms through **`@ngx-validate/core`** and renders localized helper text automatically — you do **not** write per-field error `*ngIf` markup. Build a normal `FormGroup` with Angular validators; ABP shows the messages. ```ts form = this.fb.group({ name: ['', [Validators.required, Validators.maxLength(128)]], price: [0, [Validators.required, Validators.min(0)]], }); ``` Message text comes from `DEFAULT_VALIDATION_BLUEPRINTS` (from `@abp/ng.theme.shared`), which maps validator keys (`required`, `email`, `minlength`, …) to localization keys like `AbpValidation::ThisFieldIsRequired`. Override or extend them with `withValidationBluePrint(...)` passed into `provideAbpThemeShared(...)`. - **Custom error rendering:** subclass the `abp-validation-error` component (`ValidationErrorComponent` from `@abp/ng.theme.basic`) and provide `VALIDATION_ERROR_TEMPLATE`. - **Opt out:** put `skipValidation` on a `<form>` (whole form) or on a single `formControlName` input. ## Config-driven dynamic forms For arbitrary (non-entity) forms, drive `<abp-dynamic-form>` (`DynamicFormComponent` from `@abp/ng.components/dynamic-form`) with a `FormFieldConfig[]` array — field types, validators, conditional visibility, nested groups/arrays — instead of writing template markup. This is a **separate validation path** from the reactive-form `@ngx-validate/core` story above: `abp-dynamic-form` does **not** read the theme-shared validation blueprints. It validates from each field's `FormFieldConfig.validators` and renders its own error text (per-field `message`, with an English fallback), so don't expect the automatic localized blueprint messages here — set the message on the field config. ## Validation - Page a list and confirm the network request carries `MaxResultCount`/`SkipCount`/`Sorting` and the grid updates; navigate away and back and confirm no leaked subscriptions (that's the component-scoped provider doing its job). - Submit an invalid form and confirm ABP's localized message appears with **no** hand-written error markup. ## Common Pitfalls - **`ListService` provided in root.** Then it never tears down and leaks across pages. Always component-scoped. - **Reaching for `totalCount$` or `isLoading$`.** `totalCount$` does not exist — read `res.totalCount`. `isLoading$` exists but is **deprecated**; use `requestStatus$`. - **Hand-writing paging state** (page index, skipCount math, debounce). `ListService` already does all of it; wiring your own fights it. - **Manual validation markup.** `@ngx-validate/core` renders messages automatically once the control has Angular validators; adding your own `*ngIf` error blocks duplicates them. - **Confusing the two "dynamic form" APIs.** `abp-dynamic-form` (config-driven, here) is not the entity-extension form (`generateFormFromProps` / `abp-extensible-form`) — that belongs to **extend-angular-module-ui**.
Auf GitHub ansehen