Skip to main content

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.

Pre-requisites

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.

manifest.json
{
"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:

TypeStringNumberDescription
TextTEXT1A text value represented as string data type
IntegerINTEGER2A number represented as integer data type
DecimalDECIMAL3A number represented as decimal data type
DateTimeDATETIME4A date and time data type
BooleanBOOLEAN5A boolean data type
JsonJSON6A JSON object represented as String data type
ReferenceREFERENCE7An object referencing another entry. It contains two fields, model a string that represents the model alias and entryId representing the referenced entry id
MediaMEDIA8An object representing a Codex asset
LocationLOCATION9An object representing a location. It contains three fields latitude, longitude and address.
RichTextRICH_TEXT10The HTML produces by the editor represented as string data type
RichContentRICH_CONTENT11An 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:

ValueTypeStringNumberDescription
SingleSINGLE1The field has a single value only
ListLIST2The 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.

Editor.vue
<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.