Edit widgets

This page walks you through all available edit widgets settings.

For an introduction on what widgets are and a comprehensive list of what widgets you'll be able to choose from, check out the previous page: Customize your fields

Text input

Content inputting in its most basic form, the Text input is quite what you will find in most online forms. For more advanced or specialized content types, see the other widgets.

Textarea

Much like the Text input, the Textarea widget is more appropriate when inputting longer portions of text. To input formatted content, check out the Rich text editor below.

Rich text editor

This widget is what you need when handling formatted text. You will be able to decorate your text in bold, italic and much more.

Number input

This widget isn't available yet. It will allow you to:

  • Forbid negative numbers

  • Limit the number

  • Allow you to display a currency symbol

The dropdown is a very powerful and customizable widget. As you would expect, the result will be a dropdown which allows you to choose between several values.

However, you can customize it in the following ways:

Static

Use Static content type if you want to manually enter your content.

Your values should be added manually - as a comma-separated list -, unless you enabled the Use labels option or if your field is an enum, in which cases you will be able to simply enable/disable values to add them :

If you enabled "Use labels"
If your field is an enum

Dynamic

Use this option if you want your content to depend on your own API implementation.

SQL
Mongodb
app.js
'use strict';
var express = require('express');
var app = express();
var fs = require('fs');
// ...
// You MUST require these files before the default routes.
fs.readdirSync('./decorators/routes').forEach((file) => {
if (file[0] !== '.') {
app.use('/forest', require(`./decorators/routes/${file}`));
}
});
fs.readdirSync('./routes').forEach((file) => {
if (file[0] !== '.') {
app.use('/forest', require('./routes/' + file));
}
});
app.use(require('forest-express-sequelize').init({
modelsDir: __dirname + '/models',
envSecret: process.env.FOREST_ENV_SECRET,
authSecret: process.env.FOREST_AUTH_SECRET,
sequelize: require('./models').sequelize
}));
module.exports = app;
decorators/routes/orders.js
// Configure the dropdown in dynamic mode using this path: /forest/orders/shippingStatusOptions
const express = require('express');
const router = express.Router();
const Liana = require('forest-express-sequelize');
// This is a simple case but you can retrieve your data from an external API or using your own logic
const data = [
'Being processed',
'Ready for shipping',
'In transit',
'Shipped',
'Failed',
];
router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, (req, res) => {
res.send({ data });
});
module.exports = router;
The five status are displayed in the drop-down menu.

You can add more logic by retrieving the record id or the record type using request.context.record.id, request.context.record.type

In the example below, the dropdown will only suggest status according to the current status of the order.

decorators/routes/orders.js
const express = require('express');
const router = express.Router();
const Liana = require('forest-express-sequelize');
const models = require('../../models');
const STATUS_OPTION_DEFAULT = 'Being processed';
const STATUS_TRANSITIONS = {
'Being processed': ['Ready for shipping'],
'Ready for shipping': ['In transit'],
'In transit': ['Shipped', 'Failed'],
};
router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, async (req, res) => {
const { context } = req.query;
const recordId = context && context.record && context.record.id;
let data = [STATUS_OPTION_DEFAULT];
if (recordId) {
const order = await models.orders.findByPk(recordId);
const currentShippingStatus = order.shippingStatus;
if (STATUS_TRANSITIONS[currentShippingStatus]) {
data = STATUS_TRANSITIONS[currentShippingStatus];
}
}
res.send({ data });
});
module.exports = router;
Only specific status are displayed based on the previous status of the record.
app.js
'use strict';
var express = require('express');
var app = express();
var fs = require('fs');
// ...
// You MUST require these files before the default routes.
fs.readdirSync('./decorators/routes').forEach((file) => {
if (file[0] !== '.') {
app.use('/forest', require(`./decorators/routes/${file}`));
}
});
fs.readdirSync('./routes').forEach((file) => {
if (file[0] !== '.') {
app.use('/forest', require('./routes/' + file));
}
});
app.use(require('forest-express-mongoose').init({
modelsDir: __dirname + '/models',
envSecret: process.env.FOREST_ENV_SECRET,
authSecret: process.env.FOREST_AUTH_SECRET,
mongoose: require('mongoose')
}));
module.exports = app;
decorators/routes/orders.js
// Configure the dropdown in dynamic mode using this path: /forest/orders/shippingStatusOptions
const express = require('express');
const router = express.Router();
const Liana = require('forest-express-mongoose');
// This is a simple case but you can retrieve your data from an external API or using your own logic
const data = [
'Being processed',
'Ready for shipping',
'In transit',
'Shipped',
'Failed',
];
router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, (req, res) => {
res.send({ data });
});
module.exports = router;
The five status are displayed in the drop-down menu.

You can add more logic by retrieving the record id or the record type using request.context.record.id, request.context.record.type

In the example below, the dropdown will only suggest status according to the current status of the order.

decorators/routes/orders.js
const express = require('express');
const router = express.Router();
const Liana = require('forest-express-mongoose');
const Order = require('../../models/orders');
const STATUS_OPTION_DEFAULT = 'Being processed';
const STATUS_TRANSITIONS = {
'Being processed': ['Ready for shipping'],
'Ready for shipping': ['In transit'],
'In transit': ['Shipped', 'Failed'],
};
router.get('/orders/shippingStatusOptions', Liana.ensureAuthenticated, async (req, res) => {
const { context } = req.query;
const recordId = context && context.record && context.record.id;
let data = [STATUS_OPTION_DEFAULT];
if (recordId) {
const order = await Order.findById(recordId);
const currentShippingStatus = order.shippingStatus;
if (STATUS_TRANSITIONS[currentShippingStatus]) {
data = STATUS_TRANSITIONS[currentShippingStatus];
}
}
res.send({ data });
});
module.exports = router;
Only specific status are displayed based on the previous status of the record.

Relationship

If your field refers to another collection, the dropdown option will automatically populate the data of that collection. In this example, an order belongs to a product. In order's field settings, you'll find:

While creating a new order, all products are available in the dropdown:

You can also add one or more filters to display only a dataset of the associated collection.

In this case, only Star Wars products will be available in the dropdown:

Say you have a long list of options to choose from. A dropdown becomes a bit cumbersome: this is why we've added this option.

When enabled, the widget becomes an auto-complete input dropdown.

Radio button

The radio button widget works the same way as the dropdown widget: depending on your field type and whether you used labels, you will have to manually enter your values.

While editing, the widget will look like this:

Checkboxes

The checkboxes widget works the same way as the dropdown widget: depending on your field type and whether you used labels, you will have to manually enter your values.

While editing, your widget will look like this:

File picker

Use this widget to upload files (images, pdf,..). This can be done by clicking on the grey rectangle or drag & drop'ing your file in the grey rectangle.

Settings

In your field's settings, you may set the following:

  • Specific file extensions: restrict which file types your users may upload

  • Maximum file size: set a maximum weight for your files

  • Prefix: indicate a path to preview your saved files when editing. More on this option here.

Edit tools

The File picker widget looks like this:

When uploading a single image, it allows you to perform 2 basic operations before using this file:

  • Rotate

  • Crop (adjust your image's borders until it fit a desired area)

Upload multiple files at once

For fields accepting multiple files, a new setting is available: setting a maximum number of files.

When uploading multiple files at once, your widget will look like this. Note that uploading multiple files at once will prevent you from using the rotate and crop features.

In the above picture, the Use these files button will become available after removing the first file by clicking the red cross icon.

Large files upload

If you need to upload large files, you may need to add some code to allow it. Check out this paragraph.

Date picker

Use this widget if your content is a date.

To validate these date and time, click outside of the widget

Depending on your field type, this might be a Dateonly picker widget.

Color picker

Use this widget if your content is a color.

JSON editor

Use this widget to handle JSON content.

Address

This widget allows you to benefit from Algolia's address autocompletion.

The full address will be put in a single field (in our above example: description)