Custom record field rendering
Customizing how AdminForth renders the cells with record values​
Let's change how AdminForth renders the number of rooms in the 'list' and 'show' views.
We will render '🟨' for each room and then we will print square_meter
at the same cells.
Create directory custom
. Create a file RoomsCell.vue
in it:
<template>
<div class="flex items-center">
<span v-for="room in record.number_of_rooms">
🟨
</span>
{{ record.square_meter }} m²
</div>
</template>
<script setup lang="ts">
import type { AdminForthResourceColumnCommon, AdminForthResourceCommon, AdminUser } from '@/types/Common';
const props = defineProps<{
column: AdminForthResourceColumnCommon;
record: any;
meta: any;
resource: AdminForthResourceCommon;
adminUser: AdminUser
}>();
</script>
Now you can use this component in the configuration of the resource:
{
...
resourceId: 'aparts',
columns: [
...
{
...
name: 'number_of_rooms',
components: {
show: '@@/RoomsCell.vue',
list: '@@/RoomsCell.vue',
}
},
...
],
...
}
Here is how it looks:
In very similar way you can render how cell is rendered in 'edit'
and 'create'
view.
You can use it for creating custom editors for the fields. Check component specs to understand which props are passed to the component
Parametrize the custom components​
Sometimes you need to render same component with different parameters. You can use full component declaration
{
...
resourceId: 'aparts',
columns: [
...
{
...
name: 'number_of_rooms',
components: {
show: '@@/RoomsCell.vue',
show: {
file: '@@/RoomsCell.vue',
meta: {
filler: '🟨',
},
},
list: '@@/RoomsCell.vue',
list: {
file: '@@/RoomsCell.vue',
meta: {
filler: '🟦',
},
}
}
},
...
],
...
}
Now our component can read filler
from meta
prop:
<template>
<div class="flex items-center">
<span v-for="room in record.number_of_rooms">
🟨
{{ meta.filler }}
</span>
{{ room.square_meter }} m²
</div>
</template>
<script setup lang="ts">
import type { AdminForthResourceColumnCommon, AdminForthResourceCommon, AdminUser } from '@/types/Common';
const props = defineProps<{
column: AdminForthResourceColumnCommon;
record: any;
meta: any;
resource: AdminForthResourceCommon;
adminUser: AdminUser
}>();
</script>
Using 3rd-party npm packages in the Vue components​
To install 3rd-party npm packages you should create npm package in the custom
directory:
cd custom
And simply do npm install
for the package you need:
npm i <some package> -D
Editing values component​
In same way as we define show
and list component, we can create component for edit/create page.
Let's create custom dropdown for country
field which will show emoji flags of the countries.
<template>
<Select
class="w-full"
:options="column.enum"
:model-value="record[column.name]"
@update:model-value="emit('update:value', $event)"
>
<template #item="{option}">
<span class="text-xl inline-flex">{{ getCountryFlag(option.value) }}</span> {{ option.label }}
</template>
<template #selected-item="{option}">
<span class="text-xl inline-flex">{{ getCountryFlag(option.value) }}</span> {{ option.label }}
</template>
</Select>
</template>
<script setup lang="ts">
import Select from "@/afcl/Select.vue";
import type {
AdminForthResourceColumnCommon,
AdminForthResourceCommon,
AdminUser,
} from "@/types/Common";
const props = defineProps<{
column: AdminForthResourceColumnCommon;
record: any;
meta: any;
resource: AdminForthResourceCommon;
adminUser: AdminUser;
}>();
const emit = defineEmits(["update:value"]);
function getCountryFlag(countryCode: string) {
return countryCode?.toUpperCase()
.replace(/./g, (char) => String.fromCodePoint(char.charCodeAt(0) + 127397));
}
</script>
Now you can use this component in the configuration of the resource:
{
...
resourceId: 'aparts',
columns: [
...
{
name: 'country',
components: {
edit: '@@/CountryDropdown.vue',
create: '@@/CountryDropdown.vue',
},
...
},
...
],
...
}
Pre-made renderers​
Though creating custom renderers is super-easy, we have couple of pre-made renderers for you to use.
CompactUUID​
If you have a UUID column which you want display in table in more compact manner, you can use CompactUUID
renderer.
import { randomUUID } from 'crypto';
...
columns: [
{
name: 'id',
primaryKey: true,
showIn: ['filter', 'show'],
showIn: ['list', 'filter', 'show'],
fillOnCreate: ({ initialRecord, adminUser }) => Math.random().toString(36).substring(7),
fillOnCreate: ({initialRecord}: any) => randomUUID(),
components: {
list: '@/renderers/CompactUUID.vue'
}
}
...
Country Flag​
Renders string fields containing ISO-3166-1 alpha-2 country codes as flags (e.g. 'US', 'DE', 'FR', etc.)
columns: [
...
{
name: 'country',
components: {
list: '@/renderers/CountryFlag.vue'
},
...
}
You can also show country name after the flag:
columns: [
...
{
name: 'country',
components: {
list: {
file: '@/renderers/CountryFlag.vue',
meta: {
showCountryName: true
}
}
},
...
}
Human Number​
It formats large numbers into a human-readable format (e.g., 10k, 1.5M) and supports localization for different number formats.
columns: [
...
{
name: 'square_meter',
label: 'Square',
minValue: 1, // you can set min /max value for number fields
maxValue: 100000000,
components: {
list: {
file: '@/renderers/HumanNumber.vue',
}
}
},
{
...
URL​
If your field has absolute URLs as text strings you can use URLs
renderer to render them as clickable links.
columns: [
...
{
name: 'url',
components: {
list: '@/renderers/URL.vue'
},
...
Relative Time​
To format your date fields to display the elapsed time, you can utilize the RelativeTime renderer.
columns: [
...
{
name: 'created_at',
components: {
list: '@/renderers/RelativeTime.vue'
},
...