I have a collection which has several string fields and I would like to know if there is a way for me to be able to have two different Edit Widgets of the field on the same collection based on a specific check?
I would like to be able to display either a simple Text input or a Rich text editor, based on another field I have in that collection.
Is this possible?
Context
- Agent technology: NodeJS
- Agent (forest package) name & version: @forestadmin/agent 1.35.16, @forestadmin/datasource-mongoose 1.7.3
- Database type: Mongo DB
Hello @Mihai_Chiciu1,
This kind of behaviour would be available within a collection edit action, using dynamic forms.
Let me know if this is something that would fit your use case and I can provide you with an example how to do it.
@Nicolas.M
Hi @Nicolas.M ,
Thank you for you quick answer. I wasn’t aware that the default Edit action can be customized. Would you mind sharing how can I do that?
I will give an example of the data I have in the Mongo Collection.
The collection is called Locale and looks like this:
{
_id: ObjectId;
field: string;
en: string;
de: string;
it: string;
fr: string;
}
What I want to achieve is when the field
includes the string richTextLocale
, I want to display the field in the Edit as a Rich Text Editor. Otherwise, I want to display it as a Text Input.
It would help a lot if you could show me an example on how to do this.
Thank you!
What I meant by edit action is to create a new Action that will handle field edition (your users will have to call this action instead of clicking Edit
. You can remove the “native” Edit button by removing the rights to Edit, so your users will need to use the Action
instead)
Here is a sample below that should work for your use case (for editing field
and en
of the locale collection). Please let me know if this is ok 
.customizeCollection('locale', locales =>
locales.addAction('Edit', {
scope: 'Single',
async form(context) {
// field: String,
// en: String,
const record = await context.getRecord(['field', 'en']);
return [
{
id: 'field',
label: 'field',
type: 'String',
widget: record.field.includes('richTextLocale') ? 'RichText' : 'TextInput',
defaultValue: record.field,
},
{
id: 'en',
label: 'en',
type: 'String',
widget: 'TextInput',
defaultValue: record.en,
},
];
},
async execute(context, resultBuilder) {
await context.collection.update(context.filter, {
field: context.formValues.field,
en: context.formValues.en,
});
return resultBuilder.success('ok');
},
}),
);
Thank you very much @Nicolas.M!
I suppose the same thing can be done for creating a new entry in the Locale collection?
Later Edit:
I tried using you solution and unfortunately it seems like the solution doesn’t work. I tried with your solution and the solution from the documentation at Example 7, but in the code I am not allow to provide a function for the Form. It only let’s me provide an Array.
I will paste the error as well:
Type '(context: any) => Promise<{ id: string; label: string; type: string; widget: string; defaultValue: any; }[]>' is not assignable to type 'DynamicField<ActionContextSingle<Schema, "locales">>[] | DynamicField<ActionContext<Schema, "locales">>[]'.ts(2322)
actions.d.ts(11, 5): The expected type comes from property 'form' which is declared here on type 'ActionDefinition<Schema, "locales">'
Hello @Mihai_Chiciu1,
I suppose the same thing can be done for creating a new entry in the Locale collection?
→ Yes indeed. It will be an Action with scope: ‘Global’ then
Sorry, I should have checked your agent version. Indeed, it does not support functions in the form
attribute.
You will need to upgrade your agent to this version at least: @forestadmin/agent - npm (and update your deps as well)
It should be fairly easy since there are no breaking changes.
Please let me know if this is an option for you.
Thanks @Nicolas.M !
Yes, that works for me and I managed to have a functional version. But I have one more question for this.
How can I make the widget dynamic? If I change I manually change the field in the form, the Widget doesn’t update until I save and close the window. Is there a way to update the widget it immediately after the condition record.field.includes('richTextLocale')
changes?
Right,
So we are at the right at the limit of what can be achieved with action forms 
I did find a way, but the typing does not currently support it, even though the code works. 
I guess that changing widgets on the fly wasn’t a forecast use case.
If you are ok with the ts-ignore
, (or are working in js), then this is a way you can do it:
locales.addAction('Edit', {
scope: 'Single',
form: [
{
id: 'field',
label: 'field',
type: 'String',
defaultValue: async context => {
const record = await context.getRecord(['field', 'en']);
return record.field;
},
},
{
id: 'en',
label: 'en',
type: 'String',
// @ts-ignore
widget: context => {
return context.formValues.field.includes('richtext') ? 'RichText' : 'TextInput';
},
// @ts-ignore
value: async context => {
const record = await context.getRecord(['field', 'en']);
return `${record.en}`; // to prevent wrapping with divs
},
// @ts-ignore
defaultValue: async context => {
const record = await context.getRecord(['field', 'en']);
return record.en;
},
},
],
async execute(context, resultBuilder) {
await context.collection.update(context.filter, {
field: context.formValues.field,
en: context.formValues.en,
});
return resultBuilder.success('ok');
},
}),
I’m making a note to check (and eventually fix) why is the typing not working with this example