Create a custom field
Introduction
Codex allows you to create custom fields in the Codex model builder interface. These fields allow you to customize the user interface and user experience of users when creating new entries for specific models.
Before continuing with this tutorial, please make sure you have read our plugins Quick Start guide and Create your first plugin tutorial, which goes through the setup of the first plugin used during this tutorial.
Define the manifest file
Assuming you read the quick start tutorial for developing Codex plugins and have created the manifest.json
file, you can continue developing your first field in Codex below.
Creating new fields in Codex is similar to creating custom blocks for the Codex editor. You are creating new widgets that will take care of a specific field in the entry creation interface.
Let's continue with our example about the sport
plugin. We will create a custom field for matches with the data type Json since we will save a custom object in it. Here is the manifest file for the field plugin.
{
"plugin_name": "sport",
"plugin_display_name": "Sport",
"version": "1.0.0",
"fields": [
{
"displayName": "Sport match",
"name": "match-field",
"renderEditor": "field/Editor.vue",
"renderEditorPanel": null,
"icon": "fields/field-text.png",
"type": "JSON",
"valueType": "SINGLE",
"defaultValue": null,
"attrs": {
}
}
]
}
Descriptions about the field attributes
displayName
A string that represents a human-readable name for the field.
name
A string that represents a unique name for the field. Two fields in the same plugin cannot have the same name.
renderEditor
A string that represents the path of the render editor component for the field. This component will render the content in the editor and allow users to work with the field.
renderEditorPanel
A string or array of objects that represents the field's side panel components. A field can have one or more panels in the Codex admin while using the field, allowing users to configure extra information about the field.
icon
A string that represents the name of the icon to be used for the panel.
attrs
An object that represents the attributes for the field.
Required attributes for the fields are:
type
A string or number that represents the data type of the field. You can send either a value from the String column as a string or a value from the Number column as an integer. Possible values are:
Type | String | Number | Description |
---|---|---|---|
Text | TEXT | 1 | A text value represented as string data type |
Integer | INTEGER | 2 | A number represented as integer data type |
Decimal | DECIMAL | 3 | A number represented as decimal data type |
DateTime | DATETIME | 4 | A date and time data type |
Boolean | BOOLEAN | 5 | A boolean data type |
Json | JSON | 6 | A JSON object represented as String data type |
Reference | REFERENCE | 7 | An object referencing another entry. It contains two fields, model a string that represents the model alias and entryId representing the referenced entry id |
Media | MEDIA | 8 | An object representing a Codex asset |
Location | LOCATION | 9 | An object representing a location. It contains three fields latitude , longitude and address . |
RichText | RICH_TEXT | 10 | The HTML produces by the editor represented as string data type |
RichContent | RICH_CONTENT | 11 | An array of objects representing the content generated by the Codex editor. |
valueType
A string or number that represents the value type of the field. You can send either a value from the String column as a string or a value from the Number column as an integer. Possible values are:
ValueType | String | Number | Description |
---|---|---|---|
Single | SINGLE | 1 | The field has a single value only |
List | LIST | 2 | The field contains multiple values (list of values) |
defaultValue
An object that represents the default value for the field, if any.
Editor component
The editor components take care of the user interface and the user experience for managing the field in Codex admin. In our case, we will show a button that allows users to choose the match they want to save in the field. The chosen match will be saved as the value of the field, and also the users will be able to see a preview of the chosen match in the editor interface.
<template>
<div class="field-sport-match">
<FieldName :name="name" :required="required" />
<template v-if="!match">
<b-button variant="primary" @click="onOpenChooseMatch">Choose match</b-button>
</template>
<template v-else>
<MatchDetails :match="match"></MatchDetails>
</template>
<b-modal v-model="showChooseMatchPopup" size="lg">
<b-row v-for="(match, index) in matches" v-bind:key="index">
<b-col cols="9">
<MatchDetails :match="match"></MatchDetails>
</b-col>
<b-col cols="3">
<b-button variant="primary" size="sm" @click="onMatchChoosen(match)">
Choose match
</b-button>
</b-col>
</b-row>
</b-modal>
<FieldError :error="error" />
</div>
</template>
<script>
import { generateComputedPropsFromAttrs } from '@/components/codex-layout-editor/BuilderUtils'
import { getMatches } from '../shared/sportApi'
import MatchDetails from '../shared/MatchDetails'
import FieldName from '@/components/fields/FieldName.vue'
import FieldError from '@/components/fields/FieldError.vue'
export default {
name: 'SportField',
components: {
MatchDetails,
FieldName,
FieldError,
},
props: {
value: {
type: [String, Array],
default: null,
},
error: {
type: Object,
default: () => ({ isValid: true, message: '' }),
},
widget: {
required: true,
type: Object,
},
updateAttrs: {
type: Function,
default: () => {},
},
readOnly: {
type: Boolean,
default: false,
},
required: {
type: Boolean,
default: false,
},
editable: {
type: Boolean,
default: true,
},
},
data() {
return {
match: null,
showChooseMatchPopup: false,
matches: getMatches()
}
},
watch: {
match: {
handler() {
this.$emit('input', this.match)
},
deep: true,
},
},
computed: {
...generateComputedPropsFromAttrs([
'name',
'alias',
'configured',
'valueType',
'defaultValue',
]),
computedValue: {
get() {
return this.value
},
set(v) {
this.$emit('input', v)
},
},
},
mounted() {
},
methods: {
onOpenChooseMatch() {
this.showChooseMatchPopup = true
},
onMatchChoosen(match) {
this.match = match
this.showChooseMatchPopup = false
},
validate(value) {
// Your code
return { isValid: true, message: false }
}
},
}
</script>
<style lang="scss" scoped>
</style>
As you can see from the code, when the users open an entry creation interface for a model with the Match field, they will see the button for choosing the match. Upon clicking this button, they will be able to see a list of matches returned from the sportApi and be able to choose the match they want to save in the entry. After clicking the choose match button, the match object is automatically saved as the Json value in the specific model field.