Dynamically Adding Form Controls Using a StylesFilter

Usually, a form control is added from the CSS using the oxy_editor() function. However, in some cases you don't have all the information you need to properly initialize the form control at CSS level. In these cases you can add the form controls by using the API, more specifically ro.sync.ecss.extensions.api.StylesFilter.

For instance, let's assume that we want a combo box form control and the values to populate the combo are specified inside a file (for a more interesting scenario we could imagine that they come from a database). Here is how to add the form control from the API:

public class SDFStylesFilter implements StylesFilter {

  public Styles filter(Styles styles, AuthorNode authorNode) {
    if(authorNode.getType() == AuthorNode.NODE_TYPE_PSEUDO_ELEMENT 
        && "before".equals(authorNode.getName())) {
      authorNode = authorNode.getParent();
      if ("country".equals(authorNode.getName())) {
        // This is the BEFORE pseudo element of the "country" element.
        // Read the supported countries from the configuration file.
        Map<String, Object> formControlArgs = new HashMap<String, Object>();
        formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_EDIT, "#text");
        formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_TYPE, InplaceEditorArgumentKeys.TYPE_COMBOBOX);
        // This will be a comma separated enumeration: France, Spain, Great Britain
        String countries = readCountriesFromFile();
        formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_VALUES, countries);
        formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_EDITABLE, "false");

        // We also add a label in form of the form control.
        Map<String, Object> labelProps = new HashMap<String, Object>();
        labelProps.put("text", "Country: ");
        labelProps.put("styles", "* {width: 100px; color: gray;}");
        StaticContent[] mixedContent = new StaticContent[] {new LabelContent(labelProps), new EditorContent(formControlArgs)};
        styles.setProperty(Styles.KEY_MIXED_CONTENT, mixedContent);
      }
    }
    
    // The previously added form control is the only way the element can be edited.
    if ("country".equals(authorNode.getName())) {
      styles.setProperty(Styles.KEY_VISIBITY, "-oxy-collapse-text");
    }

    return styles;
  }
}
If the execution of the formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_VALUES, countries); line consumes too much execution time (for example if it connects to a database or if it needs to extract data from a very large file), you can choose to delay it until the values are actually needed by the form control. This approach is called lazy evaluation and can be implemented as follows:
formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_VALUES, new LazyValue<List<CIValue>>() {
  public java.util.List<CIValue> get() {
    // We avoid reading the possible values until they are actually requested.
    // This will be a List with CIValues created over countries: France, Spain, Great Britain
    return readCountriesFromFile();
  }
});
The lazy evaluation approach can be used for the following form controls properties:

The full source code for this example is available inside the Author SDK.