How do I modify admin forms?

We are often asked how to make modifications to select fields in an admin entity form.  This article will address adding a dynamic field and modifying the attributes of an existing field.

The Broadleaf admin portal is almost exclusively driven by metadata.  The metadata controls location (tab/section), the label, the field type, the visibility, the ability to edit, etc.  The metadata approach is quite powerful given that extending or adding a new Entity bean only requires the addition of @AdminPresentation annotations.  These annotations drive the definition of the metadata and the final presentation of the entity in the admin.

There are times that small changes are needed to the entity in the admin - perhaps permanently making a field readonly.  Permanent changes to metadata can be done by overriding the metadata via an Entity class override or via XML override approaches.  This is covered in the online documentation - https://www.broadleafcommerce.com/docs/core/current/broadleaf-concepts/admin/admin-metadata-overrides

There are other use cases where a form field needs to be changed dynamically.  For example, making a field readonly only when a form is being edited - for add operations the field should be editable.  In cases like this you will likely need to modify the entity form prior to it being displayed.

There are two approaches for dynamically working with the admin fields: 
1) modifying metadata through CustomPersistenceHandlers
and
2) extending the Controller to modify the entity form

Note the distinction between modifying metadata and modifying entity forms.

CustomPersistenceHandlers

CustomPersistenceHandlers provide a hook to normal persistence behaviors of the admin but these classes can also be used to modify the admin metadata.  Our online documentation contains information on the various hook points where changes can be made - https://www.broadleafcommerce.com/docs/core/current/broadleaf-concepts/admin/custom-persistence-handlers

Extending Controllers

In many cases, doing one-off changes to a form field will be done by extending the AdminBasicEntityController class and hooking into the modifyAddEntityForm or the modifyEntityForm.  Note that these two methods are only available when you extend the AdminBasicEntityController.  If you extend the AdminAbstractController, you will need to identify points within your controller where you will want to modify the form field metadata.

Here is an example of a class that extends the AdminBasicEntityController to add a readonly field and to make an existing field readonly if the user is editing the form.  This example can be extended to do a number of interesting changes to forms.

package com.mysite.controller;

import java.util.Map;

import org.broadleafcommerce.admin.web.controller.entity.AdminProductController;
import org.broadleafcommerce.cms.field.type.FieldType;
import org.broadleafcommerce.core.catalog.domain.ProductAdminPresentation;
import org.broadleafcommerce.openadmin.web.form.entity.EntityForm;
import org.broadleafcommerce.openadmin.web.form.entity.Field;
import org.broadleafcommerce.openadmin.web.form.entity.FieldGroup;
import org.broadleafcommerce.openadmin.web.form.entity.Tab;

public class MyAdminProductController extends AdminProductController {

    @Override
    protected void modifyAddEntityForm(EntityForm ef, Map<String, String> pathVars) {
        super.modifyAddEntityForm(ef, pathVars);
        addCustomFieldToForm(ef);
    }

    @Override
    protected void modifyEntityForm(EntityForm ef, Map<String, String> pathVars) {
        super.modifyAddEntityForm(ef, pathVars);
        makeFieldReadOnly(ef);
        addCustomFieldToForm(ef);
    }

    private void addCustomFieldToForm(EntityForm ef) {
        // Creating a "Field" to show a link
        Field myField = new Field()
                .withName("Myfield")
                .withFriendlyName("My Field")
                .withValue("Image URL LinK: https://www.something.com")
                .withOrder(1)
                .withFieldType(FieldType.STRING.getType())
                .withReadOnly(true);

        Tab generalTab = ef.findTab(ProductAdminPresentation.TabName.General);
        FieldGroup generalGroup = generalTab.findGroupByKey(ProductAdminPresentation.GroupName.General);
        generalGroup.addField(myField);
    }
    
    private void makeFieldReadOnly(EntityForm ef) {
        Field field = ef.findField("manufacturer");
        field.setReadOnly(true);
    }
}