Form items
Contents
In this chapter, you’ll create an Animal content type, give it alternative names and images, and link your artists to their favorite animals. You’ll then follow those relationships in Guillotine.
Form items are the building blocks of content forms. You’ve already used TextLine, TextArea and Date; now you’ll make a field repeatable and use selectors to reference other content.
Create the Animal form
An animal needs a species name and may have other names, such as "Caribou" for a reindeer. Use the display name for the species and a repeatable TextLine for its other names.
Task: Add alternative names
-
Define alternative names - Create the Animal content type in your app:
src/main/resources/cms/content-types/animal/animal.yamlkind: "ContentType" title: "Animal" description: "An animal that lives on planet Earth" displayNamePlaceholder: "Species" superType: "base:structured" form: - type: "TextLine" name: "otherNames" label: "Other names" helpText: "Other names for this species." occurrences: min: 0 max: 0
As with Artist, displayNamePlaceholder tells editors what to enter in the display name, here the species. For the otherNames field:
-
typechooses the form item, in this case TextLine. -
nameis the property name used to store the value and expose it through GraphQL. -
labelandhelpTextguide the editor filling out the form. -
occurrencesallows the editor to add multiple values:min: 0makes the field optional, andmax: 0means there is no upper limit.
Without occurrences, a field is optional and accepts a single value (min: 0, max: 1). Setting both to 1 makes it required. Content Studio allows editors to save drafts with missing required values, but those items cannot be marked as ready or published.
Choose field names that will last, and use camelCase, such as otherNames. Renaming a field does not migrate its stored values, and queries using its old name will need updating. You can change its label without changing the stored property or API field. |
Select an image
The lion image you uploaded in the previous chapter is a separate content item. An ImageSelector stores a reference to it, so you can reuse the same image across several animals without uploading copies.
Task: Add an image selector
-
Add image references - Append this form item to the Animal form, at the same indentation as
otherNames:src/main/resources/cms/content-types/animal/animal.yaml- type: "ImageSelector" name: "images" label: "Images" helpText: "Images of the animal" occurrences: min: 0 max: 3
Here, min: 0 and max: 3 allow up to three images, including none. ImageSelector lets editors select existing images or upload new ones. For this exercise, you’ll select the existing lion image.
Task: Create two animals
-
Deploy the Animal schema - Save the schema file and let your running
enonic devwatcher update the app. -
Create the Animals folder - In Content Studio, create a folder named "Animals" at the root of "My First Project", next to Artists and Images. Check that its path is
/animals. -
Create Lion - Select Animals, click New, and choose Animal. Enter "Lion" as the display name and select your uploaded
lion.jpgin the Images field. Leave Other names empty and save the item.
Figure 1. The Animal form with a reference to the uploaded lion image -
Create Reindeer - Create another Animal named "Reindeer" in the same folder. Enter "Caribou" in Other names, leave Images empty, and save it. Notice that you can add another Other names entry because the field is repeatable.
Both items are saved in Draft; keep using Draft in Query Playground for the exercises below.
Query the animal’s fields
Guillotine uses occurrences when generating the GraphQL fields. Both otherNames and images accept multiple values, so both become lists, even when an item has just one value. The names are strings; the images are content references whose fields you can select.
Task: Fetch the lion and its image
-
Fetch Lion and its image - Open Query Playground for "My First Project", keep Draft selected, and run:
{ guillotine { get(key: "/animals/lion") { displayName ... on com_example_dev101_Animal { data { otherNames images { displayName ... on media_Image { imageUrl(scale: "width(600)") { path queryString } } } } } } } }The result contains an empty
otherNamesarray and one entry inimages. Build the image URL by joininghttp://localhost:8080/api,pathandqueryString, as in the media chapter. -
Compare Reindeer - Change the key to
/animals/reindeerand run the query again. TheotherNameslist now contains"Caribou", whileimagesis empty.
The get result and the items in images use GraphQL’s Content interface. As in the Headless API chapter, an inline fragment selects fields belonging to a more specific GraphQL type:
-
... on {app-name-query}_Animalgives you access to the Animal’sdata. -
... on media_Imagegives you access to the image’simageUrl.
These are GraphQL type names; your CMS content types are com.example.dev101:animal and media:image. The image selector stores the image’s ID, and Guillotine resolves that reference for you.
Link artists to animals
A ContentSelector can reference other kinds of content, just as ImageSelector references images. You’ll use it to give each artist one optional favorite animal.
Task: Add a favorite animal
-
Define the favorite animal field - Append this field to the Artist form, after
birthday:src/main/resources/cms/content-types/artist/artist.yaml- type: "ContentSelector" name: "favoriteAnimal" label: "Favorite animal" allowContentType: - "animal" allowPath: - "/animals/*" -
Select each artist’s favorite animal - Save the schema, let the watcher update the app, and reopen your artists in Content Studio. Make these selections and save each artist:
Artist Favorite animal Cardi B
Lion
Missy Elliott
Reindeer
P!nk
Lion
Figure 2. The Artist form with an animal selected
The selector narrows the available choices in two ways:
-
allowContentTypepermits only theanimalcontent type from this app. -
allowPathrestricts the choices to content below/animals.
There is no occurrences setting, so the editor can select at most one animal and can leave the field empty.
| Reference an item when it should be edited and reused independently. Two artists can reference the same Lion, and an edit to that animal is visible through both references. For data that only belongs to one item, such as an artist’s filmography entries, you’ll use sets in the next chapter. |
Task: Follow the reference in a query
-
Fetch the referenced animals - Start with the type-filtered artist query from the Headless API chapter and select
favoriteAnimal:{ guillotine { queryDsl( query: { term: { field: "type" value: { string: "com.example.dev101:artist" } } } ) { displayName ... on com_example_dev101_Artist { data { favoriteAnimal { displayName ... on com_example_dev101_Animal { data { otherNames } } } } } } } }
The favoriteAnimal field returns a single content item. You can read its displayName directly, then use an Animal fragment to select data.otherNames. There is no need for a separate query to fetch the referenced animal.
With the sample selections above, the data.guillotine.queryDsl array contains the following items; their order may differ:
[
{
"displayName": "Cardi B",
"data": {
"favoriteAnimal": {
"displayName": "Lion",
"data": {
"otherNames": []
}
}
}
},
{
"displayName": "Missy Elliott",
"data": {
"favoriteAnimal": {
"displayName": "Reindeer",
"data": {
"otherNames": ["Caribou"]
}
}
}
},
{
"displayName": "P!nk",
"data": {
"favoriteAnimal": {
"displayName": "Lion",
"data": {
"otherNames": []
}
}
}
}
]
If an artist has no selection, favoriteAnimal is null. Compare that with the empty lists for an animal’s unused otherNames or images fields.
More form items
You now have the basics for configuring fields and linking content. The CMS form items reference covers the full range of form items and their settings, including ImageSelector and ContentSelector.
For a file that belongs directly to one content item, AttachmentUploader stores it as an attachment on that item, instead of creating separate media content to reference. Query the content item’s attachments field and select attachmentUrl on each attachment to retrieve its URL components. See the Guillotine Attachment reference for the available fields.
Coming up
You’ve created repeatable fields, selected an image, linked artists to animals, and followed those references through Guillotine. In the next chapter, you’ll group and reuse form items with sets and form fragments.