@blueprint-ts/core 3.0.0 → 4.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/README.md +25 -1
- package/docs/.vitepress/config.ts +81 -23
- package/docs/index.md +6 -63
- package/docs/{services/laravel → laravel}/pagination.md +19 -6
- package/docs/{services/laravel → laravel}/requests.md +2 -2
- package/docs/services/pagination/index.md +46 -0
- package/docs/services/pagination/infinite-scroller.md +20 -0
- package/docs/services/pagination/page-aware.md +51 -0
- package/docs/services/pagination/state-pagination.md +77 -0
- package/docs/services/pagination/updating-rows.md +52 -0
- package/docs/services/persistence/index.md +46 -0
- package/docs/services/requests/abort-requests.md +29 -0
- package/docs/services/requests/bulk-requests.md +70 -0
- package/docs/services/requests/concurrency.md +58 -0
- package/docs/services/requests/drivers.md +50 -0
- package/docs/services/requests/error-handling.md +153 -0
- package/docs/services/requests/events.md +31 -0
- package/docs/services/requests/getting-started.md +201 -0
- package/docs/services/requests/headers.md +40 -0
- package/docs/services/requests/loading.md +63 -0
- package/docs/services/requests/request-bodies.md +59 -0
- package/docs/services/requests/responses.md +34 -0
- package/docs/services/support/deferred-promise.md +63 -0
- package/docs/services/support/helpers.md +77 -0
- package/docs/services/support/index.md +6 -0
- package/docs/upgrading/v1-to-v2.md +64 -0
- package/docs/upgrading/v2-to-v3.md +52 -0
- package/docs/upgrading/v3-to-v4.md +214 -0
- package/docs/upgrading.md +0 -0
- package/docs/vue/composables/use-confirm-dialog.md +96 -0
- package/docs/vue/composables/use-global-checkbox.md +73 -0
- package/docs/vue/composables/use-is-empty.md +26 -0
- package/docs/vue/composables/use-is-open-from-var.md +32 -0
- package/docs/vue/composables/use-is-open.md +28 -0
- package/docs/vue/composables/use-model-wrapper.md +29 -0
- package/docs/vue/composables/use-on-open.md +26 -0
- package/docs/vue/forms/arrays.md +102 -0
- package/docs/vue/forms/errors.md +52 -0
- package/docs/vue/forms/index.md +99 -0
- package/docs/vue/forms/payloads.md +99 -0
- package/docs/vue/forms/persistence.md +19 -0
- package/docs/vue/forms/state-and-properties.md +26 -0
- package/docs/vue/forms/utilities.md +27 -0
- package/docs/vue/forms/validation.md +189 -0
- package/docs/vue/requests/loading.md +51 -0
- package/docs/vue/{requests → router}/route-resource-binding.md +33 -27
- package/docs/vue/state.md +27 -11
- package/package.json +12 -13
- package/release-tool.json +22 -3
- package/src/{service/bulkRequests → bulkRequests}/BulkRequestSender.ts +29 -17
- package/src/{service/bulkRequests → bulkRequests}/BulkRequestWrapper.ts +5 -5
- package/src/laravel/pagination/dataDrivers/RequestDriver.ts +30 -0
- package/src/laravel/pagination/index.ts +6 -0
- package/src/pagination/BasePaginator.ts +94 -0
- package/src/{service/pagination → pagination}/InfiniteScroller.ts +1 -0
- package/src/{service/pagination → pagination}/PageAwarePaginator.ts +34 -26
- package/src/{service/pagination → pagination}/StatePaginator.ts +2 -8
- package/src/{service/pagination → pagination}/index.ts +1 -3
- package/src/{service/requests → requests}/BaseRequest.ts +89 -4
- package/src/requests/ErrorHandler.ts +144 -0
- package/src/requests/RequestConcurrencyMode.enum.ts +6 -0
- package/src/requests/RequestErrorRouter.ts +89 -0
- package/src/{service/requests → requests}/bodies/FormDataBody.ts +10 -6
- package/src/{service/requests → requests}/contracts/BaseRequestContract.ts +3 -0
- package/src/requests/exceptions/BadGatewayException.ts +3 -0
- package/src/requests/exceptions/BadRequestException.ts +3 -0
- package/src/requests/exceptions/ConflictException.ts +3 -0
- package/src/requests/exceptions/ForbiddenException.ts +3 -0
- package/src/requests/exceptions/GatewayTimeoutException.ts +3 -0
- package/src/requests/exceptions/GoneException.ts +3 -0
- package/src/requests/exceptions/InvalidJsonException.ts +15 -0
- package/src/requests/exceptions/LockedException.ts +3 -0
- package/src/requests/exceptions/MethodNotAllowedException.ts +3 -0
- package/src/requests/exceptions/NotImplementedException.ts +3 -0
- package/src/requests/exceptions/PayloadTooLargeException.ts +3 -0
- package/src/requests/exceptions/PreconditionFailedException.ts +3 -0
- package/src/requests/exceptions/RequestTimeoutException.ts +3 -0
- package/src/requests/exceptions/ServiceUnavailableException.ts +3 -0
- package/src/requests/exceptions/StaleResponseException.ts +13 -0
- package/src/requests/exceptions/TooManyRequestsException.ts +3 -0
- package/src/requests/exceptions/UnsupportedMediaTypeException.ts +3 -0
- package/src/requests/exceptions/index.ts +51 -0
- package/src/requests/factories/FormDataFactory.ts +17 -0
- package/src/{service/requests → requests}/index.ts +9 -3
- package/src/requests/types/RequestConcurrencyOptions.ts +6 -0
- package/src/{service/support → support}/DeferredPromise.ts +1 -1
- package/src/support/index.ts +4 -0
- package/src/vue/composables/useConfirmDialog.ts +5 -1
- package/src/vue/composables/useModelWrapper.ts +3 -0
- package/src/vue/forms/BaseForm.ts +512 -399
- package/src/vue/forms/PropertyAwareArray.ts +6 -2
- package/src/vue/forms/index.ts +4 -4
- package/src/vue/forms/validation/index.ts +5 -2
- package/src/vue/forms/validation/rules/ConfirmedRule.ts +3 -3
- package/src/vue/forms/validation/rules/EmailRule.ts +23 -0
- package/src/vue/forms/validation/rules/JsonRule.ts +28 -0
- package/src/vue/forms/validation/types/BidirectionalRule.ts +2 -2
- package/src/vue/forms/validation/types/ValidationRules.ts +15 -0
- package/src/vue/index.ts +3 -3
- package/src/vue/requests/factories/VueRequestLoaderFactory.ts +3 -2
- package/src/vue/requests/loaders/VueRequestBatchLoader.ts +6 -1
- package/src/vue/requests/loaders/VueRequestLoader.ts +1 -1
- package/src/vue/router/routeResourceBinding/types.ts +3 -3
- package/src/vue/state/State.ts +38 -50
- package/tests/service/helpers/mergeDeep.test.ts +1 -1
- package/tests/service/laravel/pagination/dataDrivers/RequestDriver.test.ts +3 -3
- package/tests/service/laravel/requests/JsonBaseRequest.test.ts +4 -4
- package/tests/service/laravel/requests/PaginationJsonBaseRequest.test.ts +3 -3
- package/tests/service/laravel/requests/responses/JsonResponse.test.ts +2 -2
- package/tests/service/laravel/requests/responses/PaginationResponse.test.ts +2 -2
- package/tests/service/pagination/dtos/PaginationDataDto.test.ts +1 -1
- package/tests/service/pagination/factories/VuePaginationDriverFactory.test.ts +2 -2
- package/tests/service/pagination/frontendDrivers/VuePaginationDriver.test.ts +1 -1
- package/tests/service/requests/ErrorHandler.test.ts +61 -58
- package/tests/service/requests/FormDataBody.test.ts +1 -1
- package/tests/vue/forms/BaseForm.behavior.test.ts +98 -0
- package/docs/.vitepress/theme/Layout.vue +0 -14
- package/docs/.vitepress/theme/components/VersionSelector.vue +0 -64
- package/docs/.vitepress/theme/index.js +0 -13
- package/docs/services/requests/index.md +0 -74
- package/docs/vue/forms.md +0 -477
- package/examples/files/7z2404-x64.exe +0 -0
- package/examples/index.html +0 -14
- package/examples/js/app.js +0 -8
- package/examples/js/router.js +0 -22
- package/examples/js/view/App.vue +0 -49
- package/examples/js/view/layout/DemoPage.vue +0 -28
- package/examples/js/view/pagination/Pagination.vue +0 -28
- package/examples/js/view/pagination/components/errorPagination/ErrorPagination.vue +0 -71
- package/examples/js/view/pagination/components/errorPagination/GetProductsRequest.ts +0 -54
- package/examples/js/view/pagination/components/infiniteScrolling/GetProductsRequest.ts +0 -50
- package/examples/js/view/pagination/components/infiniteScrolling/InfiniteScrolling.vue +0 -57
- package/examples/js/view/pagination/components/tablePagination/GetProductsRequest.ts +0 -50
- package/examples/js/view/pagination/components/tablePagination/TablePagination.vue +0 -63
- package/examples/js/view/requests/Requests.vue +0 -34
- package/examples/js/view/requests/components/abortableRequest/AbortableRequest.vue +0 -36
- package/examples/js/view/requests/components/abortableRequest/GetProductsRequest.ts +0 -25
- package/examples/js/view/requests/components/fileDownloadRequest/DownloadFileRequest.ts +0 -15
- package/examples/js/view/requests/components/fileDownloadRequest/FileDownloadRequest.vue +0 -44
- package/examples/js/view/requests/components/getRequestWithDynamicParams/GetProductsRequest.ts +0 -34
- package/examples/js/view/requests/components/getRequestWithDynamicParams/GetRequestWithDynamicParams.vue +0 -59
- package/examples/js/view/requests/components/serverErrorRequest/ServerErrorRequest.ts +0 -21
- package/examples/js/view/requests/components/serverErrorRequest/ServerErrorRequest.vue +0 -53
- package/src/service/laravel/pagination/contracts/PaginationParamsContract.ts +0 -4
- package/src/service/laravel/pagination/dataDrivers/RequestDriver.ts +0 -32
- package/src/service/laravel/pagination/index.ts +0 -7
- package/src/service/pagination/BasePaginator.ts +0 -36
- package/src/service/pagination/Paginator.ts +0 -11
- package/src/service/requests/ErrorHandler.ts +0 -64
- package/src/service/requests/exceptions/index.ts +0 -19
- package/src/service/requests/factories/FormDataFactory.ts +0 -9
- package/src/service/support/index.ts +0 -3
- /package/src/{service/bulkRequests → bulkRequests}/BulkRequestEvent.enum.ts +0 -0
- /package/src/{service/bulkRequests → bulkRequests}/index.ts +0 -0
- /package/src/{service/laravel → laravel}/pagination/contracts/PaginationResponseBodyContract.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/JsonBaseRequest.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/PaginationJsonBaseRequest.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/index.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/responses/JsonResponse.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/responses/PaginationResponse.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/BaseViewDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/BaseViewDriverFactoryContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginateableRequestContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginationDataDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginationResponseContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginatorLoadDataOptions.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/StatePaginationDataDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/ViewDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/ViewDriverFactoryContract.ts +0 -0
- /package/src/{service/pagination → pagination}/dataDrivers/ArrayDriver.ts +0 -0
- /package/src/{service/pagination → pagination}/dtos/PaginationDataDto.ts +0 -0
- /package/src/{service/pagination → pagination}/dtos/StatePaginationDataDto.ts +0 -0
- /package/src/{service/pagination → pagination}/factories/VueBaseViewDriverFactory.ts +0 -0
- /package/src/{service/pagination → pagination}/factories/VuePaginationDriverFactory.ts +0 -0
- /package/src/{service/pagination → pagination}/frontendDrivers/VueBaseViewDriver.ts +0 -0
- /package/src/{service/pagination → pagination}/frontendDrivers/VuePaginationDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/LocalStorageDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/NonPersistentDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/SessionStorageDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/index.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/types/PersistenceDriver.ts +0 -0
- /package/src/{service/requests → requests}/RequestEvents.enum.ts +0 -0
- /package/src/{service/requests → requests}/RequestMethod.enum.ts +0 -0
- /package/src/{service/requests → requests}/bodies/JsonBody.ts +0 -0
- /package/src/{service/requests → requests}/contracts/AbortableRequestContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/BodyContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/BodyFactoryContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/DriverConfigContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/HeadersContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/RequestDriverContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/RequestLoaderContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/RequestLoaderFactoryContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/ResponseContract.ts +0 -0
- /package/src/{service/requests → requests}/drivers/contracts/ResponseHandlerContract.ts +0 -0
- /package/src/{service/requests → requests}/drivers/fetch/FetchDriver.ts +0 -0
- /package/src/{service/requests → requests}/drivers/fetch/FetchResponse.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/NoResponseReceivedException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/NotFoundException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/PageExpiredException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ResponseBodyException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ResponseException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ServerErrorException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/UnauthorizedException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ValidationException.ts +0 -0
- /package/src/{service/requests → requests}/factories/JsonBodyFactory.ts +0 -0
- /package/src/{service/requests → requests}/responses/BaseResponse.ts +0 -0
- /package/src/{service/requests → requests}/responses/BlobResponse.ts +0 -0
- /package/src/{service/requests → requests}/responses/JsonResponse.ts +0 -0
- /package/src/{service/requests → requests}/responses/PlainTextResponse.ts +0 -0
- /package/src/{helpers.ts → support/helpers.ts} +0 -0
package/docs/vue/forms.md
DELETED
|
@@ -1,477 +0,0 @@
|
|
|
1
|
-
# BaseForm Documentation
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
`BaseForm` is a powerful and flexible TypeScript class for handling form state, validation, and submission in Vue
|
|
6
|
-
applications. It provides a comprehensive solution for managing form data with features like:
|
|
7
|
-
|
|
8
|
-
- Type-safe form state management
|
|
9
|
-
- Dirty + touched state tracking for fields
|
|
10
|
-
- Error handling and field validation
|
|
11
|
-
- Form persistence between page reloads
|
|
12
|
-
- Support for complex nested objects and arrays
|
|
13
|
-
- Automatic transformation of form values to API payloads
|
|
14
|
-
- Supports `File`/`Blob` fields for multipart requests (see “Files / Uploads”)
|
|
15
|
-
|
|
16
|
-
## Key Features
|
|
17
|
-
|
|
18
|
-
### 1. Type-Safe Form Management
|
|
19
|
-
|
|
20
|
-
The `BaseForm` is a generic class that takes two type parameters:
|
|
21
|
-
|
|
22
|
-
- `RequestBody`: The shape of the data that will be sent to the server
|
|
23
|
-
- `FormBody`: The shape of the form's internal state, which can differ from the request payload
|
|
24
|
-
|
|
25
|
-
````typescript
|
|
26
|
-
class MyForm extends BaseForm<MyRequestPayload, MyFormState> {
|
|
27
|
-
// ...
|
|
28
|
-
}
|
|
29
|
-
````
|
|
30
|
-
|
|
31
|
-
### 2. Form State Persistence
|
|
32
|
-
|
|
33
|
-
Forms can automatically save their state to browser storage (session, local, etc.), allowing users to navigate away and
|
|
34
|
-
return without losing their input.
|
|
35
|
-
|
|
36
|
-
````typescript
|
|
37
|
-
protected override getPersistenceDriver(suffix?: string): PersistenceDriver {
|
|
38
|
-
return new SessionStorageDriver(suffix) // Or LocalStorageDriver(suffix), etc.
|
|
39
|
-
}
|
|
40
|
-
````
|
|
41
|
-
|
|
42
|
-
Notes:
|
|
43
|
-
- Persistence is enabled by default. Disable it via `super(defaults, { persist: false })`.
|
|
44
|
-
- `persistSuffix` is passed into `getPersistenceDriver(suffix)` and is typically used to namespace the storage key.
|
|
45
|
-
- Persisted state is only reused if the stored `original` matches your current `defaults`; otherwise it is discarded.
|
|
46
|
-
- `persist: false` disables the automatic rehydration + background persistence, but some explicit mutation helpers (e.g. `fillState()`, `reset()`, `addToArrayProperty()`) still call the driver.
|
|
47
|
-
- `File`/`Blob` values are not JSON-serializable, so persistence is not supported for file inputs. Use `{ persist: false }` for file upload forms.
|
|
48
|
-
|
|
49
|
-
### 3. Transformations and Getters
|
|
50
|
-
|
|
51
|
-
`buildPayload()` supports three “getter” patterns to transform values before sending them to your API.
|
|
52
|
-
|
|
53
|
-
Special value types:
|
|
54
|
-
- `Date` values are treated as scalars and preserved (not “object-walked”). When sent as JSON they serialize to ISO strings via `JSON.stringify()`, and when sent as multipart `FormData` they are appended as `toISOString()`.
|
|
55
|
-
- `File`/`Blob` values are also treated as scalars and preserved for multipart uploads.
|
|
56
|
-
|
|
57
|
-
#### A) Field Getter (common)
|
|
58
|
-
If your form `state` contains a field, you can define a getter for that same field name. During `buildPayload()`,
|
|
59
|
-
`BaseForm` will call it with the field’s current value and use the return value in the payload.
|
|
60
|
-
|
|
61
|
-
Getter name format: `get${upperFirst(camelCase(fieldName))}(value)`
|
|
62
|
-
|
|
63
|
-
Omitting fields:
|
|
64
|
-
- If a field getter returns `undefined`, the field is **not added** to the payload object.
|
|
65
|
-
- Other values (`null`, `false`, `0`, `''`, empty arrays/objects) are included as-is.
|
|
66
|
-
|
|
67
|
-
Examples:
|
|
68
|
-
|
|
69
|
-
````typescript
|
|
70
|
-
// state.name -> payload.name (trimmed)
|
|
71
|
-
protected getName(value: string): string {
|
|
72
|
-
return value.trim()
|
|
73
|
-
}
|
|
74
|
-
````
|
|
75
|
-
|
|
76
|
-
This works for arrays too (plain arrays and `PropertyAwareArray`):
|
|
77
|
-
|
|
78
|
-
````typescript
|
|
79
|
-
// state.positions -> payload.positions (mapped)
|
|
80
|
-
protected getPositions(positions: PositionItem[]): Array<{ id: number }> {
|
|
81
|
-
return positions.map((p) => ({ id: p.id }))
|
|
82
|
-
}
|
|
83
|
-
````
|
|
84
|
-
|
|
85
|
-
#### B) Composite Getter for Nested Props (automatic fallback)
|
|
86
|
-
If you do *not* provide a field getter for a given top-level field, `BaseForm` will recursively walk objects/arrays and
|
|
87
|
-
allow transforming nested properties via composite getter names.
|
|
88
|
-
|
|
89
|
-
Composite getter format: `get${upperFirst(parentFieldKey)}${upperFirst(camelCase(propName))}(value)`
|
|
90
|
-
|
|
91
|
-
Example (field key `businessAssociate`, prop `id`):
|
|
92
|
-
|
|
93
|
-
````typescript
|
|
94
|
-
// state.businessAssociate.id -> payload.businessAssociate.id (replaced with the resource id)
|
|
95
|
-
protected getBusinessAssociateId(value: BusinessAssociateResource | null): string | null {
|
|
96
|
-
return value?.id ?? null
|
|
97
|
-
}
|
|
98
|
-
````
|
|
99
|
-
|
|
100
|
-
Notes:
|
|
101
|
-
- This applies to arrays of objects too, because arrays are mapped recursively.
|
|
102
|
-
- The “parent field” part uses the original field key with only the first character uppercased (not camel-cased).
|
|
103
|
-
- Returning `undefined` from a composite getter omits that nested property from the payload object.
|
|
104
|
-
|
|
105
|
-
#### C) Appended / Computed Payload Fields (advanced)
|
|
106
|
-
If you need payload fields that do not exist in `state`, add their names to `append`. `buildPayload()` will then call a
|
|
107
|
-
zero-argument getter for each appended field.
|
|
108
|
-
|
|
109
|
-
Example (append key `started_at` → getter `getStartedAt()`):
|
|
110
|
-
|
|
111
|
-
````typescript
|
|
112
|
-
protected override append: string[] = ['started_at']
|
|
113
|
-
|
|
114
|
-
protected getStartedAt(): string {
|
|
115
|
-
return DateTime.fromFormat(`${this.state.start_date} ${this.state.start_time}`, 'dd.MM.yyyy HH:mm').toISO()
|
|
116
|
-
}
|
|
117
|
-
````
|
|
118
|
-
|
|
119
|
-
### 4. Error Handling and Validation
|
|
120
|
-
|
|
121
|
-
Map server-side validation errors to specific form fields, with support for nested fields:
|
|
122
|
-
|
|
123
|
-
````typescript
|
|
124
|
-
protected override errorMap: { [serverKey: string]: string | string[] } = {
|
|
125
|
-
started_at: ['start_date', 'start_time'],
|
|
126
|
-
ended_at: ['end_date', 'end_time']
|
|
127
|
-
}
|
|
128
|
-
````
|
|
129
|
-
|
|
130
|
-
Validation is configured by overriding `defineRules()` and returning per-field rules and an optional validation mode:
|
|
131
|
-
|
|
132
|
-
- `ValidationMode.DEFAULT` (default): validates on dirty, touch, and submit
|
|
133
|
-
- `ValidationMode.PASSIVE`: only validates on submit
|
|
134
|
-
- `ValidationMode.AGGRESSIVE`: validates immediately and on all triggers
|
|
135
|
-
- `ValidationMode.ON_DEPENDENT_CHANGE`: revalidates when a dependency changes (see below)
|
|
136
|
-
|
|
137
|
-
Rules can declare dependencies via `rule.dependsOn = ['otherField']`. Some rules (e.g. `ConfirmedRule`) implement
|
|
138
|
-
bidirectional dependencies, so changing either field revalidates the other.
|
|
139
|
-
|
|
140
|
-
### 5. Array Management
|
|
141
|
-
|
|
142
|
-
Special support for arrays with the class `PropertyAwareArray`, enabling reactive updates to array items:
|
|
143
|
-
|
|
144
|
-
````typescript
|
|
145
|
-
public addPosition(): void {
|
|
146
|
-
this.addToArrayProperty('positions', {
|
|
147
|
-
index: this.properties.positions.length + 1,
|
|
148
|
-
gross_amount: null,
|
|
149
|
-
vat_rate: VatRateEnum.VAT_RATE_19,
|
|
150
|
-
booking_account_category_id: null
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
````
|
|
154
|
-
|
|
155
|
-
## Core Concepts
|
|
156
|
-
|
|
157
|
-
### State and Dirty Tracking
|
|
158
|
-
|
|
159
|
-
`BaseForm` tracks the original state and current state of each form field, automatically computing "dirty" status for
|
|
160
|
-
fields that have been changed.
|
|
161
|
-
|
|
162
|
-
````typescript
|
|
163
|
-
// Check if any field in the form has been modified
|
|
164
|
-
form.isDirty()
|
|
165
|
-
|
|
166
|
-
// Check if a specific field has been modified
|
|
167
|
-
form.isDirty('email')
|
|
168
|
-
````
|
|
169
|
-
|
|
170
|
-
### Touched Tracking
|
|
171
|
-
|
|
172
|
-
Touched indicates user interaction (or programmatic updates via setters/fill methods).
|
|
173
|
-
|
|
174
|
-
````typescript
|
|
175
|
-
form.touch('email')
|
|
176
|
-
form.isTouched('email')
|
|
177
|
-
````
|
|
178
|
-
|
|
179
|
-
### The Properties Object
|
|
180
|
-
|
|
181
|
-
The `properties` getter provides access to each form field with its model, errors, and dirty status:
|
|
182
|
-
|
|
183
|
-
````html
|
|
184
|
-
|
|
185
|
-
<template>
|
|
186
|
-
<input v-model="form.properties.email.model.value" />
|
|
187
|
-
<div v-if="form.properties.email.dirty">This field has been changed</div>
|
|
188
|
-
<div v-if="form.properties.email.errors.length">{{ form.properties.email.errors[0] }}</div>
|
|
189
|
-
</template>
|
|
190
|
-
````
|
|
191
|
-
|
|
192
|
-
`properties.<field>` exposes:
|
|
193
|
-
- `model` (a `ComputedRef` compatible with `v-model`)
|
|
194
|
-
- `errors` (array; empty until validated/filled)
|
|
195
|
-
- `dirty` and `touched`
|
|
196
|
-
|
|
197
|
-
### Form Submission
|
|
198
|
-
|
|
199
|
-
Build a payload for API submission with:
|
|
200
|
-
|
|
201
|
-
````typescript
|
|
202
|
-
const payload = form.buildPayload()
|
|
203
|
-
````
|
|
204
|
-
|
|
205
|
-
For validation on submit, call:
|
|
206
|
-
|
|
207
|
-
````typescript
|
|
208
|
-
const ok = form.validate(true)
|
|
209
|
-
if (!ok) return
|
|
210
|
-
await api.submitForm(form.buildPayload())
|
|
211
|
-
````
|
|
212
|
-
|
|
213
|
-
## How to Use
|
|
214
|
-
|
|
215
|
-
### 1. Create a Form Class
|
|
216
|
-
|
|
217
|
-
````typescript
|
|
218
|
-
import { BaseForm, type PersistenceDriver, SessionStorageDriver } from '@hank-it/ui/vue/forms'
|
|
219
|
-
import { RequiredRule, ValidationMode } from '@hank-it/ui/vue/forms/validation'
|
|
220
|
-
|
|
221
|
-
interface MyFormState {
|
|
222
|
-
name: string
|
|
223
|
-
email: string
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
interface MyRequestPayload {
|
|
227
|
-
name: string
|
|
228
|
-
email: string
|
|
229
|
-
timestamp: string // Added field not in the form
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
class MyForm extends BaseForm<MyRequestPayload, MyFormState> {
|
|
233
|
-
// Fields to add to the final payload that aren't in the form state
|
|
234
|
-
protected override append: string[] = ['timestamp']
|
|
235
|
-
|
|
236
|
-
// Fields to exclude from the final payload
|
|
237
|
-
protected override ignore: string[] = []
|
|
238
|
-
|
|
239
|
-
// Map server error keys to form field names
|
|
240
|
-
protected override errorMap: { [serverKey: string]: string | string[] } = {}
|
|
241
|
-
|
|
242
|
-
public constructor() {
|
|
243
|
-
super({
|
|
244
|
-
name: '',
|
|
245
|
-
email: ''
|
|
246
|
-
}, { persist: true, persistSuffix: 'optional-suffix' })
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Use session storage for persistence
|
|
250
|
-
protected override getPersistenceDriver(suffix?: string): PersistenceDriver {
|
|
251
|
-
return new SessionStorageDriver(suffix)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
protected override defineRules() {
|
|
255
|
-
return {
|
|
256
|
-
name: { rules: [new RequiredRule<MyFormState>('Name is required')] },
|
|
257
|
-
email: {
|
|
258
|
-
rules: [new RequiredRule<MyFormState>('Email is required')],
|
|
259
|
-
options: { mode: ValidationMode.DEFAULT }
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Generate a timestamp for the request
|
|
265
|
-
protected getTimestamp(): string {
|
|
266
|
-
return new Date().toISOString()
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
````
|
|
270
|
-
|
|
271
|
-
### 2. Use in Components
|
|
272
|
-
|
|
273
|
-
````vue
|
|
274
|
-
<template>
|
|
275
|
-
<form @submit.prevent="submitForm">
|
|
276
|
-
<div>
|
|
277
|
-
<label>Name</label>
|
|
278
|
-
<input v-model="form.properties.name.model.value" />
|
|
279
|
-
<div v-if="form.properties.name.errors.length" class="error">
|
|
280
|
-
{{ form.properties.name.errors[0] }}
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
|
|
284
|
-
<div>
|
|
285
|
-
<label>Email</label>
|
|
286
|
-
<input v-model="form.properties.email.model.value" />
|
|
287
|
-
<div v-if="form.properties.email.errors.length" class="error">
|
|
288
|
-
{{ form.properties.email.errors[0] }}
|
|
289
|
-
</div>
|
|
290
|
-
</div>
|
|
291
|
-
|
|
292
|
-
<button type="submit" :disabled="!form.isDirty()">Submit</button>
|
|
293
|
-
<button type="button" @click="form.reset()">Reset</button>
|
|
294
|
-
</form>
|
|
295
|
-
</template>
|
|
296
|
-
|
|
297
|
-
<script setup>
|
|
298
|
-
import { MyForm } from './MyForm'
|
|
299
|
-
|
|
300
|
-
const form = new MyForm()
|
|
301
|
-
|
|
302
|
-
async function submitForm() {
|
|
303
|
-
if (!form.validate(true)) return
|
|
304
|
-
try {
|
|
305
|
-
const payload = form.buildPayload()
|
|
306
|
-
await api.submitForm(payload)
|
|
307
|
-
// Success handling
|
|
308
|
-
} catch (error) {
|
|
309
|
-
if (error.response?.data?.errors) {
|
|
310
|
-
form.fillErrors(error.response.data.errors)
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
</script>
|
|
315
|
-
````
|
|
316
|
-
|
|
317
|
-
## Working with Arrays
|
|
318
|
-
The `PropertyAwareArray` class enables special handling for array items. Each value of objects in the PropertyAwareArray will receive a v-model, errors, etc.:
|
|
319
|
-
|
|
320
|
-
````typescript
|
|
321
|
-
import { BaseForm, PropertyAwareArray } from '@hank-it/ui/vue/forms'
|
|
322
|
-
|
|
323
|
-
export interface FormWithPositions {
|
|
324
|
-
// ...other fields
|
|
325
|
-
positions: PositionItem[]
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
export class MyComplexForm extends BaseForm<RequestType, FormWithPositions> {
|
|
329
|
-
constructor() {
|
|
330
|
-
super({
|
|
331
|
-
// ...other defaults
|
|
332
|
-
positions: new PropertyAwareArray([
|
|
333
|
-
{ id: 1, value: '' }
|
|
334
|
-
])
|
|
335
|
-
})
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Add a new position to the array
|
|
339
|
-
public addPosition(): void {
|
|
340
|
-
this.addToArrayProperty('positions', {
|
|
341
|
-
id: this.properties.positions.length + 1,
|
|
342
|
-
value: ''
|
|
343
|
-
})
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Remove a position by id
|
|
347
|
-
public removePosition(id: number): void {
|
|
348
|
-
this.removeArrayItem('positions', (position) => position.id !== id)
|
|
349
|
-
this.resetArrayCounter('positions', 'id')
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const form = new MyComplexForm()
|
|
354
|
-
const id = form.properties.positions[0].id.model.value
|
|
355
|
-
````
|
|
356
|
-
|
|
357
|
-
## Advanced Features
|
|
358
|
-
### 1. Form Reset
|
|
359
|
-
Revert all changes to the original state:
|
|
360
|
-
|
|
361
|
-
````typescript
|
|
362
|
-
form.reset()
|
|
363
|
-
````
|
|
364
|
-
|
|
365
|
-
### 2. Error Handling
|
|
366
|
-
Fill form with validation errors from a server response:
|
|
367
|
-
|
|
368
|
-
````typescript
|
|
369
|
-
try {
|
|
370
|
-
await submitForm(form.buildPayload())
|
|
371
|
-
} catch (error) {
|
|
372
|
-
form.fillErrors(error.response.data.errors)
|
|
373
|
-
}
|
|
374
|
-
````
|
|
375
|
-
|
|
376
|
-
`fillErrors` supports:
|
|
377
|
-
- direct field keys (e.g. `email`)
|
|
378
|
-
- array dot notation where the 2nd segment is a numeric index (e.g. `positions.0.value`)
|
|
379
|
-
- remapping via `errorMap` (including mapping one server key to multiple fields)
|
|
380
|
-
|
|
381
|
-
### 3. Filling Form State
|
|
382
|
-
Update multiple form fields at once and recompute dirty/touched accordingly:
|
|
383
|
-
|
|
384
|
-
````typescript
|
|
385
|
-
form.fillState({
|
|
386
|
-
name: 'John Doe',
|
|
387
|
-
email: 'john@example.com'
|
|
388
|
-
})
|
|
389
|
-
````
|
|
390
|
-
|
|
391
|
-
### 4. Synchronizing Values Without Marking Dirty
|
|
392
|
-
Update both the current and original state, keeping the field "clean":
|
|
393
|
-
|
|
394
|
-
````typescript
|
|
395
|
-
form.syncValue('email', 'new@example.com')
|
|
396
|
-
````
|
|
397
|
-
|
|
398
|
-
### 5. Converting `properties` Back To Data
|
|
399
|
-
If you ever need a plain object from the `properties` tree (e.g. for debugging or integrating with non-`BaseForm` code),
|
|
400
|
-
use `propertyAwareToRaw`:
|
|
401
|
-
|
|
402
|
-
````typescript
|
|
403
|
-
import { propertyAwareToRaw } from '@hank-it/ui/vue/forms'
|
|
404
|
-
|
|
405
|
-
const raw = propertyAwareToRaw<MyFormState>(form.properties)
|
|
406
|
-
````
|
|
407
|
-
|
|
408
|
-
### 6. Checking For Errors
|
|
409
|
-
|
|
410
|
-
````typescript
|
|
411
|
-
form.hasErrors()
|
|
412
|
-
````
|
|
413
|
-
|
|
414
|
-
## Files / Uploads (Multipart)
|
|
415
|
-
If your form includes a file, keep it in state as `File | null` and disable persistence:
|
|
416
|
-
|
|
417
|
-
````typescript
|
|
418
|
-
interface UploadFormBody {
|
|
419
|
-
name: string
|
|
420
|
-
file: File | null
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
class UploadForm extends BaseForm<RequestBody, UploadFormBody> {
|
|
424
|
-
constructor() {
|
|
425
|
-
super({ name: '', file: null }, { persist: false })
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
````
|
|
429
|
-
|
|
430
|
-
`buildPayload()` keeps `File`/`Blob` values intact, so you can send the payload using a multipart `FormData` request body
|
|
431
|
-
(e.g. the request layer’s `FormDataFactory` / `FormDataBody`).
|
|
432
|
-
|
|
433
|
-
If `file` is `null`, `FormDataBody` encodes it as an empty string (the key stays present). Many backends (e.g. Laravel with
|
|
434
|
-
`ConvertEmptyStringsToNull`) will treat that as `null` again.
|
|
435
|
-
|
|
436
|
-
## Real-World Examples
|
|
437
|
-
### 1. Date/Time Handling
|
|
438
|
-
|
|
439
|
-
This example shows the “appended/computed fields” pattern: `started_at` and `ended_at` are not part of the form state,
|
|
440
|
-
so they are listed in `append`, and `buildPayload()` calls `getStartedAt()` / `getEndedAt()` (no arguments).
|
|
441
|
-
|
|
442
|
-
````typescript
|
|
443
|
-
export class TimeTrackingEntryCreateUpdateForm extends BaseForm<RequestPayload, FormState> {
|
|
444
|
-
protected override append: string[] = ['started_at', 'ended_at']
|
|
445
|
-
protected override ignore: string[] = ['start_date', 'start_time', 'end_date', 'end_time']
|
|
446
|
-
|
|
447
|
-
protected getStartedAt(): string {
|
|
448
|
-
return DateTime.fromFormat(`${this.state.start_date} ${this.state.start_time}`, 'dd.MM.yyyy HH:mm').toISO()
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
protected getEndedAt(): string {
|
|
452
|
-
return DateTime.fromFormat(`${this.state.end_date} ${this.state.end_time}`, 'dd.MM.yyyy HH:mm').toISO()
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
````
|
|
456
|
-
|
|
457
|
-
### 2. Complex Object Handling
|
|
458
|
-
|
|
459
|
-
If your form state contains nested objects, `buildPayload()` can transform individual nested properties via
|
|
460
|
-
composite getter names of the form `get<ParentField><NestedProp>()`, where:
|
|
461
|
-
- `ParentField` is based on the form field key (first character uppercased, not camel-cased)
|
|
462
|
-
- `NestedProp` is `upperFirst(camelCase(prop))`
|
|
463
|
-
|
|
464
|
-
Example (field key `businessAssociate`, prop `id`): `getBusinessAssociateId(...)`.
|
|
465
|
-
|
|
466
|
-
````typescript
|
|
467
|
-
export class IncomingVoucherCreateUpdateForm extends BaseForm<RequestPayload, FormState> {
|
|
468
|
-
// Extract IDs from related objects
|
|
469
|
-
protected getBusinessAssociateId(value: BusinessAssociateResource): string | null {
|
|
470
|
-
return value?.id
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
protected getFileId(value: FileResource): string | null {
|
|
474
|
-
return value?.id
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
````
|
|
Binary file
|
package/examples/index.html
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en" class="h-full">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Hank-IT UI</title>
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
</head>
|
|
8
|
-
<body class="h-full">
|
|
9
|
-
|
|
10
|
-
<div id="app" class="w-full h-full"></div>
|
|
11
|
-
|
|
12
|
-
<script type="module" src="/js/app.js"></script>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
package/examples/js/app.js
DELETED
package/examples/js/router.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { createWebHistory, createRouter } from 'vue-router'
|
|
2
|
-
|
|
3
|
-
const routes = [
|
|
4
|
-
{
|
|
5
|
-
path: '/pagination/:component?',
|
|
6
|
-
component: () => import('@view/pagination/Pagination.vue'),
|
|
7
|
-
name: 'pagination',
|
|
8
|
-
props: true,
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
path: '/requests/:component?',
|
|
12
|
-
component: () => import('@view/requests/Requests.vue'),
|
|
13
|
-
name: 'requests',
|
|
14
|
-
props: true,
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export default createRouter({
|
|
20
|
-
history: createWebHistory(),
|
|
21
|
-
routes, // short for `routes: routes`,
|
|
22
|
-
})
|
package/examples/js/view/App.vue
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="container">
|
|
3
|
-
<div class="sidebar">
|
|
4
|
-
<ul>
|
|
5
|
-
<li><RouterLink :to="{ name: 'requests' }">Requests</RouterLink></li>
|
|
6
|
-
<li><RouterLink :to="{ name: 'pagination' }">Pagination</RouterLink></li>
|
|
7
|
-
</ul>
|
|
8
|
-
</div>
|
|
9
|
-
<div class="content">
|
|
10
|
-
<RouterView />
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
</template>
|
|
14
|
-
|
|
15
|
-
<script setup>
|
|
16
|
-
|
|
17
|
-
</script>
|
|
18
|
-
|
|
19
|
-
<style>
|
|
20
|
-
body {
|
|
21
|
-
margin: 0;
|
|
22
|
-
padding:0;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.container {
|
|
26
|
-
display: flex;
|
|
27
|
-
flex-direction: row;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.sidebar,
|
|
31
|
-
.content {
|
|
32
|
-
display: flex;
|
|
33
|
-
flex-direction: column;
|
|
34
|
-
color: black;
|
|
35
|
-
min-height: 500px;
|
|
36
|
-
border-radius: 4px;
|
|
37
|
-
margin: 10px;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.sidebar {
|
|
41
|
-
flex-grow: 1;
|
|
42
|
-
min-width: 300px;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.content {
|
|
46
|
-
flex-grow: 5;
|
|
47
|
-
min-width: 630px;
|
|
48
|
-
}
|
|
49
|
-
</style>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<select v-model="selectedComponentKey">
|
|
3
|
-
<RouterLink
|
|
4
|
-
v-for="(component, key) in components"
|
|
5
|
-
:key="key"
|
|
6
|
-
:to="component.route"
|
|
7
|
-
custom
|
|
8
|
-
v-slot="{ isActive, href, navigate }"
|
|
9
|
-
>
|
|
10
|
-
<option @click="navigate" :value="key">
|
|
11
|
-
{{ component.name }}
|
|
12
|
-
</option>
|
|
13
|
-
</RouterLink>
|
|
14
|
-
</select>
|
|
15
|
-
|
|
16
|
-
<component v-if="selectedComponentKey" :is="components[selectedComponentKey].component" />
|
|
17
|
-
</template>
|
|
18
|
-
|
|
19
|
-
<script setup lang="ts">
|
|
20
|
-
import {ref} from 'vue'
|
|
21
|
-
|
|
22
|
-
const props = defineProps({
|
|
23
|
-
components: {},
|
|
24
|
-
component: String,
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
const selectedComponentKey = ref(props.component)
|
|
28
|
-
</script>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<DemoPage :components="components" />
|
|
3
|
-
</template>
|
|
4
|
-
|
|
5
|
-
<script setup lang="ts">
|
|
6
|
-
import TablePagination from './components/tablePagination/TablePagination.vue'
|
|
7
|
-
import ErrorPagination from './components/errorPagination/ErrorPagination.vue'
|
|
8
|
-
import InfiniteScrolling from './components/infiniteScrolling/InfiniteScrolling.vue'
|
|
9
|
-
import DemoPage from '../layout/DemoPage.vue'
|
|
10
|
-
|
|
11
|
-
const components = {
|
|
12
|
-
'table-pagination': {
|
|
13
|
-
name: 'Paginated table',
|
|
14
|
-
component: TablePagination,
|
|
15
|
-
route: { name: 'pagination', params: { component: 'table-pagination' } },
|
|
16
|
-
},
|
|
17
|
-
'error-pagination': {
|
|
18
|
-
name: 'Pagination with error',
|
|
19
|
-
component: ErrorPagination,
|
|
20
|
-
route: { name: 'pagination', params: { component: 'error-pagination' } },
|
|
21
|
-
},
|
|
22
|
-
'infinite-scrolling': {
|
|
23
|
-
name: 'Infinite scrolling',
|
|
24
|
-
component: InfiniteScrolling,
|
|
25
|
-
route: { name: 'pagination', params: { component: 'infinite-scrolling' } },
|
|
26
|
-
},
|
|
27
|
-
}
|
|
28
|
-
</script>
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<table>
|
|
3
|
-
<tr>
|
|
4
|
-
<th>ID</th>
|
|
5
|
-
<th>Title</th>
|
|
6
|
-
<th>Description</th>
|
|
7
|
-
</tr>
|
|
8
|
-
<tr v-for="row in paginator.getPageData()">
|
|
9
|
-
<td>{{ row.id }}</td>
|
|
10
|
-
<td>{{ row.title }}</td>
|
|
11
|
-
<td>{{ row.description }}</td>
|
|
12
|
-
</tr>
|
|
13
|
-
</table>
|
|
14
|
-
|
|
15
|
-
Current page: {{ paginator.getCurrentPage() }}
|
|
16
|
-
<br>
|
|
17
|
-
Pages: {{ paginator.getPages() }}
|
|
18
|
-
<br>
|
|
19
|
-
Page Size: <input v-model="pageSize" />
|
|
20
|
-
<br>
|
|
21
|
-
Back Page <button @click="paginator.toPreviousPage()">Back</button>
|
|
22
|
-
<br>
|
|
23
|
-
Next Page <button @click="paginator.toNextPage()">Next</button>
|
|
24
|
-
<br>
|
|
25
|
-
Showing {{ paginator.getFromItemNumber() }} to {{ paginator.getToItemNumber() }} of {{ paginator.getTotal() }} items.
|
|
26
|
-
|
|
27
|
-
{{ displayablePages }}
|
|
28
|
-
</template>
|
|
29
|
-
|
|
30
|
-
<script setup lang="ts">
|
|
31
|
-
import {BaseRequest, FetchDriver, VueLoaderDriverFactory} from "@hank-it/ui/service/requests"
|
|
32
|
-
import {Paginator, RequestDriver, VuePaginationDriverFactory} from "@hank-it/ui/service/pagination";
|
|
33
|
-
import {getDisplayablePages} from '@hank-it/ui/service/helpers'
|
|
34
|
-
import {GetProductsRequest} from "./GetProductsRequest";
|
|
35
|
-
import {computed} from 'vue'
|
|
36
|
-
|
|
37
|
-
/* Booting */
|
|
38
|
-
BaseRequest.setRequestDriver(new FetchDriver)
|
|
39
|
-
BaseRequest.setLoaderStateFactory(new VueLoaderDriverFactory)
|
|
40
|
-
Paginator.setViewDriverFactory(new VuePaginationDriverFactory())
|
|
41
|
-
|
|
42
|
-
/* component */
|
|
43
|
-
const getProductsRequest = new GetProductsRequest
|
|
44
|
-
|
|
45
|
-
const paginator = new Paginator(new RequestDriver(getProductsRequest))
|
|
46
|
-
|
|
47
|
-
paginator.init(1, 10).catch(paginationErrorHandler)
|
|
48
|
-
|
|
49
|
-
function paginationErrorHandler(response) {
|
|
50
|
-
console.log(response.getError())
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const pageSize = computed({
|
|
54
|
-
set(value) {
|
|
55
|
-
paginator.setPageSize(value)
|
|
56
|
-
},
|
|
57
|
-
get() {
|
|
58
|
-
return paginator.getPageSize()
|
|
59
|
-
}
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
const displayablePages = computed(() => {
|
|
63
|
-
console.log(paginator.getPages())
|
|
64
|
-
|
|
65
|
-
return getDisplayablePages(paginator.getPages().length, paginator.getCurrentPage())
|
|
66
|
-
})
|
|
67
|
-
</script>
|
|
68
|
-
|
|
69
|
-
<style scoped>
|
|
70
|
-
|
|
71
|
-
</style>
|