Skip to content

Commit 1dc3cd8

Browse files
committed
feat: add support for updating related record fields in custom editors
1 parent bec462b commit 1dc3cd8

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

adminforth/documentation/docs/tutorial/03-Customization/02-customFieldRendering.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,97 @@ Now you can use this component in the configuration of the resource:
233233
}
234234
```
235235
236+
### Custom record editing (updating other fields)
237+
238+
Sometimes a custom editor needs to update not only its own field, but also other fields of the record (for example, generate a slug from a title).
239+
240+
For this, custom `edit`/`create` components can emit an `update:recordFieldValue` event with the payload `{ fieldName, fieldValue }`. AdminForth will update the corresponding field in the record.
241+
242+
```html title='./custom/TitleWithSlugEditor.vue'
243+
<template>
244+
<div class="flex flex-col gap-2">
245+
<Input
246+
:model-value="record[column.name]"
247+
:placeholder="$t('Title')"
248+
@update:model-value="onTitleChange"
249+
/>
250+
<Input
251+
:model-value="record.slug"
252+
:placeholder="$t('Slug')"
253+
readonly
254+
/>
255+
</div>
256+
</template>
257+
258+
<script setup lang="ts">
259+
import Input from "@/afcl/Input.vue";
260+
import type {
261+
AdminForthResourceColumnCommon,
262+
AdminForthResourceCommon,
263+
AdminUser,
264+
} from "@/types/Common";
265+
266+
const props = defineProps<{
267+
column: AdminForthResourceColumnCommon;
268+
record: any;
269+
meta: any;
270+
resource: AdminForthResourceCommon;
271+
adminUser: AdminUser;
272+
readonly: boolean;
273+
}>();
274+
275+
const emit = defineEmits([
276+
"update:value", // update current column value
277+
"update:recordFieldValue", // update any other field in the record
278+
]);
279+
280+
function slugify(value: string) {
281+
return value
282+
?.toLowerCase()
283+
.trim()
284+
.replace(/[^a-z0-9]+/g, "-")
285+
.replace(/(^-|-$)+/g, "");
286+
}
287+
288+
function onTitleChange(newTitle: string) {
289+
// update current column value
290+
emit("update:value", newTitle);
291+
292+
// update another field in the record (e.g. slug)
293+
emit("update:recordFieldValue", {
294+
fieldName: "slug",
295+
fieldValue: slugify(newTitle),
296+
});
297+
}
298+
</script>
299+
```
300+
301+
And use it in the resource configuration for both `edit` and `create` views:
302+
303+
```ts title='./resources/apartments.ts'
304+
{
305+
...
306+
resourceId: 'aparts',
307+
columns: [
308+
...
309+
{
310+
name: 'title',
311+
components: {
312+
edit: '@@/TitleWithSlugEditor.vue',
313+
create: '@@/TitleWithSlugEditor.vue',
314+
},
315+
},
316+
{
317+
name: 'slug',
318+
// standard input; value will be kept in sync
319+
...
320+
},
321+
...
322+
],
323+
...
324+
}
325+
```
326+
236327
### Custom inValidity inside of the custom create/edit components
237328
238329
Custom componets can emit `update:inValidity` event to parent to say that the field is invalid.

adminforth/spa/src/components/ColumnValueInput.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
:column="column"
77
:value="value"
88
@update:value="$emit('update:modelValue', $event)"
9+
@update:recordFieldValue="$emit('update:recordFieldValue', $event)"
910
:meta="column.components[props.source].meta"
1011
:record="currentValues"
1112
:resource="coreStore.resource"

adminforth/spa/src/components/ColumnValueInputWrapper.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
:unmasked="unmasked"
1717
:deletable="!column.editReadonly"
1818
@update:modelValue="setCurrentValue(column.name, $event, arrayItemIndex)"
19+
@update:recordFieldValue="({ fieldName, fieldValue }: { fieldName: string; fieldValue: any }) => setCurrentValue(fieldName, fieldValue)"
1920
@update:unmasked="$emit('update:unmasked', column.name)"
2021
@update:inValidity="$emit('update:inValidity', { name: column.name, value: $event })"
2122
@update:emptiness="$emit('update:emptiness', { name: column.name, value: $event })"
@@ -47,6 +48,7 @@
4748
:columnOptions="columnOptions"
4849
:unmasked="unmasked"
4950
@update:modelValue="setCurrentValue(column.name, $event)"
51+
@update:recordFieldValue="({ fieldName, fieldValue }: { fieldName: string; fieldValue: any }) => setCurrentValue(fieldName, fieldValue)"
5052
@update:unmasked="$emit('update:unmasked', column.name)"
5153
@update:inValidity="$emit('update:inValidity', { name: column.name, value: $event })"
5254
@update:emptiness="$emit('update:emptiness', { name: column.name, value: $event })"

0 commit comments

Comments
 (0)