Developer HandBook
- Configurations
- PWA settings
- Hibernate settings
- Views and templates
- Customizing view with html
- Form without html
- Custom grid column renderer template
- Custom gallery template
- Basic operations
- Accessing view
- Accessing field
- Accessing child controller
- Accessing commander and toolbar
- Accessing commander and toolbar
- Accessing Grid
- Accessing Gallery
- Setting a field editable
- Setting a field mandatory
- Setting a view type
- Setting a form mode
- Reacting on events
- Services
- Persistence service
- Writing a business logic
- Calling business logic method from code
- Writing a data getter
- Writing your own service
- Controller events
- Model, Store, Recorder
- Getting all objects currently in Store
- Sorting Store data by property value
- Setting custom filter
- Calling fetch() from code
- Commander
- Getting commander toolbar
- Adding custom control from code
- Custom commands in Form designer
- Commands adapter
- Field value changed
- Entity field value changed
- Meta field value changed
- Validation changed
- Reacting on event when form data is not valid
- Lookup field
- Setting an image
- Setting a filter
- Setting a form filter in lookup window
- Setting a filter from database
- Reports
- Setting custom variables
- Responsive resizer
- Custom validator
- System parameters
- User login
- User login parameters / Local storage
- Caching
- Custom components
Developer HandBook
PWA settings
In order to set application description and an icon used for PWA, set appDescription and appIcon in applicationContext.xml:
<bean id="applicationConfig" class="com.codeless.shared.ApplicationConfig"> <property name="appName"> <value>CodelessPlatform</value> </property> <property name="appIcon"> <value>/VAADIN/themes/codeless/img/PetClinic.png</value> </property> <property name="appDescription"> <value>Codeless Platform demo</value> </property> <property name="domainName"> <value>localhost</value> </property> <property name="productTitle"> <value>CodeLess Platform</value> </property> </bean>
Hibernate settings
Update hibernate.properties with appropriate values for database connection:
# --------- PostgreeSQL (codeless) ------------------------------------------- hibernate.hikari.dataSource.url = jdbc:postgresql://localhost/codeless hibernate.hikari.dataSourceClassName = org.postgresql.ds.PGSimpleDataSource hibernate.hikari.dataSource.user = user hibernate.hikari.dataSource.password = password hibernate.dialect = org.hibernate.dialect.PostgreSQL95Dialect logging.driver = org.postgresql.Driver # -------------------------------------------------------------------------------
Views and templates
Customizing view with HTML
In the Form designer, find fields view that you want to customize:
Click on Configure button:
Now, click on HTML button:
Uncheck option auto-generated and change the view.
Form without HTML
If you want to create a main layout without HTML, you can simply create a form in Form designer without adding anything on the Main panel. Instead of using Main html as a layout, we can do it directly in code.
In this example we will combine two things. The main layout will be created in code and another view will be inserted as part of the code layout.
First create a form in the form designer “MyDemo”. Do not add anything on the Main view, but create an additional view “Fields” and add one StringField “name”.
Empty main view:
Fields view with name field:
Add a custom controller “MyDemoController”. Let’s now do some coding:
@Controller public class MyDemoController extends MyDemoAbstractController { IHorizontalLayout hlc = new UIHorizontalLayout(); IPanel left = new UIPanel(); IPanel right = new UIPanel(); @Override public void onViewConstructed() { super.onViewConstructed(); IContainer viewContent = getLayoutGenerator().getViewContent(); viewContent.addComponent(hlc); hlc.setSizeFull(); left.addStyleName("redPanel"); right.addStyleName("bluePanel"); hlc.addComponent(left, 250, 1); hlc.addComponent(getDetailView("Fields").getMainPanel(), 1, 1); hlc.addComponent(right, 250, 1); } }
The most important method is onViewConstructed(). This method is called the platform when the view is constructed. If we override this method, we can get a container where the form will be rendered:
IContainer viewContent = getLayoutGenerator().getViewContent();
Instead of using the Main HTML, we can add anything we want. In this case, we created HorizontalLayout with height and width set to 100% that has 3 panels.
On the left we have a panel with 250px in red color, on the right panel with 250px in blue color and in the middle we have Fields view.
“Fields” view is accessible by calling:
getDetailView("Fields").getMainPanel();
When started, the form looks like the following:
Custom grid column renderer template
In order to define column renderer in code, our controller needs to implement IColumnTemplateProvider.
public interface IColumnTemplateProvider<T extends AbstractEntity> { void getColumnTemplate ( String metaFieldName, T bean, AsyncCallbackAdapter<String> callback ); }
metaFieldName : name of meta field which column we are rendering
bean : entity object for the current row
callback : provides render template
If you open PetController you can see that this controller defines a template for column image.
Look at getColumnTemplate method that returns HTML template via callback:
<img src="{IMAGE_PATH}/{image}" class="img-responsive" style="height:35px;" />
IMAGE_PATH is the symbolic name for the image path for this form. In this case it will evaluate to:
RESOURCE_ABS_PATH / images / PetClinic / Pet
The image is the name of the property in Pet bean.
Example value for {IMAGE_PATH}/{image}:
http://localhost:8083/CodelessPlatform/image/images/PetClinic/Pet/ptica2_mala.jpg
The column will render as an image:
Custom gallery template
In order to define gallery renderer in code, our controller needs to implement IGalleryTemplateProvider.
public interface IGalleryTemplateProvider<T extends AbstractEntity> { void getGalleryTemplate(T bean, AsyncCallbackAdapter<String> callback); }
bean: entity object for the current card
callback: provides render template
If you open PetController you can see that this controller defines a template for the gallery
Important methods:
// Set label style depending on pet type, call createGalleryTemplate and return html // template via callback @Override public void getGalleryTemplate(Pet pet, AsyncCallbackAdapter<String> callback) // Method returns html template via callback // pet : current object // style : different styles of pet type // text : update label text according to a pet type // getVisitsCount(pet) : get number of visits even before controller has been instantiated private void createGalleryTemplate ( Pet pet, String style, String text, AsyncCallbackAdapter<String> callback) // Get the number of visits for the pet void getVisitsCount(Pet pet, AsyncCallbackAdapter<String> callback)
The gallery looks like the following:
Basic operations
To access a particular detail view from code, override onConstructed() method as you can be sure that view has been created at this moment.
@Override public void onViewConstructed() { super.onViewConstructed(); IView view = getDetailView("Fields"); IComponent panel = view.getMainPanel(); }
If you call getDetailView() without a view name, you will get the default “Main” view.
In order to access fields, you need to create a custom component and check fields that you want to be accessible in the code.
Read more about this in Form Designer/Field connections
@Override public void onViewConstructed() { super.onViewConstructed(); IStringField name = thisForm.FieldsView.nameField; }
this Form is a structure generated for each custom controller.
FieldsView is one of the views of this form
nameField is one of the fields that is part of FieldsView
Accessing child controller
Child controller can be accessed by calling getChildController(String name)
@Override public void onConstructed() { super.onConstructed(); IController child = getChildController(ViewNames.ApplicationMenuItems); }
If you call the same method without a name and there is only one child you will get the same result.
Accessing commander and toolbar
@Override public void onConstructed() { super.onConstructed(); ICommander commander = getCommander(); ICommandToolbar toolbar = commander.getCommandToolbar(); }
Accessing Grid
@Override public void onConstructed() { super.onConstructed(); IGrid grid = getGridView().getGrid(); }
Accessing Gallery
@Override public void onConstructed() { super.onConstructed(); IGallery gallery = getGalleryView().getGallery(); }
Setting a field editable
We can set conditional editability of a field the following way:
@Override public void onConstructed() { super.onConstructed(); IStringField field = thisForm.FieldsView.nameField; field.getFormFieldHelper().setEditableFieldHandler( new IEnabledFieldHandler<AbstractEntity>() { @Override public boolean isEnabled(AbstractEntity entity) { // Check property values of the entity or other // fields in controller and set enabled or not return enabled; } }); }
Setting a field visible
We can set conditional visibility of a field the following way:
field.getFormFieldHelper().setVisibleFieldHandler( new IVisibleFieldHandler<AbstractEntity>() { @Override public boolean isVisible(AbstractEntity entity) { // Check property values of the entity or other // fields in controller and set visible or not return visible; } });
Setting a field mandatory
@Override public void onConstructed() { super.onConstructed(); IStringField field = thisForm.FieldsView.nameField; field.getFormFieldHelper().setMandatoryFieldHandler( new IMandatoryFieldHandler<AbstractEntity>() { @Override public boolean isMandatory(AbstractEntity entity) { // Check property values of the entity or other // fields in controller and set mandatory or not return mandatory; } }); }
Setting a view type
@Override public void onViewConstructed() { super.onViewConstructed(); setViewType(ViewType.GRID); }
ViewType is defined as:
public static enum ViewType { NONE, DETAIL, GRID, GALLERY, CHECKER }
Setting a form mode
@Override public void onViewConstructed() { super.onViewConstructed(); setMode(Mode.EDIT); }
Mode is defined as:
public static enum Mode { VIEW, EDIT, DELETE, ADD }
Reacting on events
Setting an event in Form designer as:
will create a method in your abstract controller that has to implement:
@Override protected void onEventValueChanged(EventData event) { // TODO Auto-generated method stub }
Services
Persistence service
All services are accessible from the Platform.Service
@Override public void onViewConstructed() { super.onViewConstructed(); Platform.Service.persistenceService.findUnique( "select demo from Demo demo", new AsyncCallbackComplexAdapter<Demo>() { @Override public void onComplete(Demo result) { // TODO Auto-generated method stub } @Override public void onError(Throwable error) { // TODO Auto-generated method stub } }); }
Writing a business logic
1. Write Java class that implements ICustomPersistentActions
public class MyDemoBusinessLogic implements ICustomPersistentActions { @Override public DataTransferMap fetch(DataTransferMap doc) throws DataTransferException { return doc; } @Override public DataTransferMap add(DataTransferMap doc) throws DataTransferException { return doc; } @Override public DataTransferMap update(DataTransferMap doc) throws DataTransferException { return doc; } @Override public DataTransferMap delete(DataTransferMap doc) throws DataTransferException { return doc; } @Override public DataTransferMap save(DataTransferMap doc) throws DataTransferException { return doc; } @Override public DataTransferMap commit(DataTransferMap doc) throws DataTransferException { return doc; } }
2. Register this class in the form Business class
Calling business logic method from code
1. Write any Java class with the method that has an argument of type DataTransferMap and returns type DataTransferMap
public class MyOtherLogic { public DataTransferMap myMethod(DataTransferMap doc) throws DataTransferException { doc.setPart("MESSAGE", "Helo world."); return doc; } }
DataTransferMap has a map where you can store anything you want.
2. Register this class in the form Business class
Look for constant in:
/** @generated */ public interface ConstBusinessClasses { ... public static final String MY_OTHER_LOGIC = "MyOtherLogic"; ... }
3. You can call this method like this:
@Override public void onViewConstructed() { super.onViewConstructed(); Platform.Service.businessLogicService.execute( ConstBusinessClasses.MY_OTHER_LOGIC, "myMethod", new DataTransferMap(), new AsyncCallbackComplexAdapter<DataTransferMap>() { @Override public void onComplete(DataTransferMap result) { UINotification.displayInfo( "Info", result.getPart("MESSAGE") ); } @Override public void onError(Throwable error) { // TODO Auto-generated method stub } } ); }
Writing a data getter
DataGetter is a special kind of Business class that returns the list of String. Data getter can be used in FormDesigner for StringListField.
1. Write Java class that implements IStringListDataGetter
public class ApplicationMenuBL implements IStringListDataGetter { PersistenceServiceImpl persistenceService = new PersistenceServiceImpl(); @Override public List<String> getData() throws DataTransferException { return persistenceService.findList("select name from ApplicationMenu"); } }
2. Register this class in the form Business class
3. Use it in Form designer for StrilgListField
4. Result field on the form will be populated as the following:
Writing your own service
1. Write interface with sync method:
public interface IMyService { String getMyMessage() throws DataTransferException; }
2. Write async version:
public interface IMyServiceAsync { void getMyMessage(AsyncCallbackComplexAdapter<String> callback); }
3. Write implementation:
public class MyServiceImpl implements IMyService { @Override public String getMyMessage() throws DataTransferException { return "Hello world."; } public static class Service { private static MyServiceImpl instance; public static MyServiceImpl getInstance() { return (instance == null) ? (instance = new MyServiceImpl()) : instance; } } }
4. Write proxy:
public class MyServiceProxy implements IMyServiceAsync { @Override public void getMyMessage(AsyncCallbackComplexAdapter<String> callback) { try { String message = MyServiceImpl.Service.getInstance().getMyMessage(); callback.onComplete(message); } catch (DataTransferException e) { callback.onError(e); } } }
5. Call the service:
@Override public void onViewConstructed() { super.onViewConstructed(); IMyServiceAsync service = new MyServiceProxy(); service.getMyMessage(new AsyncCallbackComplexAdapter<String>() { @Override public void onComplete(String message) { UINotification.displayInfo("Info", message); } @Override public void onError(Throwable error) { // TODO Auto-generated method stub } }); }
Controller events
You can react to the following controller events:
public enum EventType { ACTIVE_OBJECT_CHANGED, // After bean instance is set ACTIVE_OBJECT_NULL, // When bean instance is null ADD_DATA, // After new instance is added AFTER_CANCEL, // After cancel action is performed BEFORE_CANCEL, // Before cancel action is performed CLEANUP, // After controller cleanup is performed CONSTRUCTED, // After controller is constructed DATA_ARRIVED, // After data is arrived (from database) DATA_COPIED, // After data is copied DATA_SAVED, // After data is saved DATA_CHANGED, // After data is changed DETAIL_VIEW_CREATED, // After data is changed ENABLE_EDITING, // After data editing is enabled FOOTER_VISIBILITY_CHANGE,// After footer visibility is changed GALLERY_VIEW_CREATED, // After gallery view is created GRID_VIEW_CREATED, // After grid view is created CHECKER_VIEW_CREATED, // After checker view is created MODE_CHANGED, // After controller mode is changed REFRESH_VIEW, // After view is refreshed REMOVE_DATA, // After data is removed SAVE_FAILURE, // After save failure VALIDATION_CHANGED, // After validation of data is changed VIEW_TYPE_CHANGED, // After view type is changed ATTACHED // After view is attached }
Example:
@Override public void onViewConstructed() { super.onViewConstructed(); addControllerEventHandler(new IControllerEventHandler() { @Override public void onEvent(ControllerEvent event) { if(event.getEventType().equals(EventType.ADD_DATA)) { UINotification.displayInfo("Infor", "Data added."); } } }); }
Model, Store, Recorder
Getting all objects currently in Store
@Override public void onViewConstructed() { super.onViewConstructed(); for(Demo demo : getModel().getStore().getAll()) { // Do something with bean demo } }
Sorting Store data by property value
@Override public void onViewConstructed() { super.onViewConstructed(); EntityCollectionHelper.sort( getModel().getStore().getAll(), FieldNames.name); }
Setting custom filter
@Override public void onViewConstructed() { super.onViewConstructed(); FilterContainer filter = new FilterContainer(); filter.setExpression("name = :name"); filter.setParameter("name", "MyName"); getModel().getCustomFilters().add(filter); }
Calling fetch() from code
@Override public void onViewConstructed() { super.onViewConstructed(); getModel().fetch(); }
Commander
Getting commander toolbar
@Override public void onViewConstructed() { super.onViewConstructed(); getCommander().getCommandToolbar(); }
Adding custom control from code
@Override public void onViewConstructed() { super.onViewConstructed(); IButton myButton = new UIButton(Icon.ALARM); myButton.addClickEventHandler(new IClickEventHandler() { @Override public void onEvent() { UINotification.displayInfo("Info", "Alarm clicked"); } }); getCommander().getCommandToolbar().addCommand(myButton, "ALARM"); }
Custom commands in Form designer
1. Add commands view:
2. Add button:
3. Configure button and add event “CAR”
4. Inspect preview, save changes.
5. Refresh your controller and implement a new method:
@Override protected void onEventCAR(EventData event) { UINotification.displayInfo("Info", "CAR clicked"); }
6. Check result:
Commands adapter
If you want to react to events that happen in the commander, you can set an Adapter. For example when Add button in commander is clicked, before the controller is notified, you can react an event like this:
getCommander().setAdapter(new IEventAdapter() { @Override public void onEvent(EventData event) { if (event.getName().equals(ICommander.EVT_BEFORE_ADD)) { UINotification.displayInfo("Info", "Add button clicked."); } } });
Field value changed
Entity field value changed
In the case of an entity field that is mapped on one of the entity properties, we should detect changes this way:
@Override public void onViewConstructed() { super.onViewConstructed(); thisForm.FieldsView.nameField .getValueProvider().addPropertyChangedEventHandler( new IPropertyChangedEventHandler<Demo>() { @Override public void onEvent(PropertyChangedEvent event) { UINotification.displayInfo( "Info", "name changed to: " + event.getNewValue()); } }); }
Meta field value changed
In the case of a simple field that is not mapped we should detect changes this way:
@Override public void onViewConstructed() { super.onViewConstructed(); thisForm.FieldsView.nameField.addValueChangedEventHandler( new IValueChangedEventHandler<Demo>() { @Override public void onEvent(ValueChangedEvent event) { UINotification.displayInfo( "Info", "name changed to: " + event.getNewValue() ); } }); }
Validation changed
Reacting on the event when form data is not valid
@Override public void onViewConstructed() { super.onViewConstructed(); getModel().getRecorder() .addValidationChangedEventHandler( new IValidationChangedEventHandler<Demo>() { @Override public void onEvent(ValidationEvent event) { if(!event.isValid()) { UINotification.displayError("Error", "Data is not valid"); } } }); }
Lookup field
Setting an image
In order to set lookup image, fill resourcePath (path of form) and image property name
Check result:
Setting a filter
@Override public void onViewConstructed() { super.onViewConstructed(); ILookupField<Demo> lookupField = new UILookupField<Demo>(); FilterContainer filter = new FilterContainer(); filter.setExpression("name = 'MyName'"); lookupField.getModel().getCustomFilters().add(filter); }
Setting a form filter in the lookup window
@Override public void onViewConstructed() { super.onViewConstructed(); ILookupField<Demo> lookupField = new UILookupField<Demo>(); FilterDefinition filter = new FilterDefinition ( "application", "application", "=", null, "name", false ); lookupField.addFormFilter(filter); }
Setting a filter from the database
When you want to fetch some data from a database that will be part of the filter, you need to create a lookup adapter that will give you the opportunity to do whatever you need to do before the lookup window is shown and data fetched.
@Override public void onViewConstructed() { super.onViewConstructed(); ILookupField<Demo> lookupField = new UILookupField<Demo>(); lookupField.setLookupAdapter(new ILookupAdapter<Demo>() { @Override public void onBeforeFind( AsyncCallbackComplexAdapter<Demo> callBack) { // Call persistence service for setting filter // Set filter and then let know lookup that it can // show lookup window and fetch the data callBack.onComplete(null); } }); }
Reports
Setting custom variables
You can set any variable for any type of report from code. Let’s imagine you have this mapping in your Word template:
#[FROM_CODE]#
You can replace FROM_CODE with “Hello from code” in your report with the following code in your controller:
@Override public void doPrint() { addCustomParameter("FROM_CODE", "Hello from code."); super.doPrint(); }
Responsive resizer
If you are creating a custom form that does not use bootstrap, flex layout or other responsive layout or you are making something very different than standard forms and you need help to make the form responsive you can use ResposiveResizer.
ResponsiveResizer is a helper class that can give you the size of the screen and let you know when size is changed for example from small to large.
1. Let your controller implement IResponsiveHandler:
public class MyDemoController extends MyDemoAbstractController implements IResponsiveHandler<Demo
2. Add Resizer to your class:
IResponsiveResizer resizer = new UIResponsiveResizer(this);
3. Implement required methods:
@Override public void onResponsiveResizeEvent(ResponsiveResizeEvent e) { if (e.isExtraSmall()) { UINotification.displayInfo("Info", "Size is ExtraSmall"); } else if (e.isExtraLarge()) { UINotification.displayInfo("Info", "Size is ExtraLarge"); } } @Override public IResponsiveResizer getResizer() { return resizer; }
4. Check result:
Custom validator
You can create a custom validator by extending class AbstractValidator:
public class MyCustomValidator extends AbstractValidator { @Override public boolean isValidValue(Object value) { String strValue = (String) value; if(strValue != null && strValue.contains("*")) { return false; } else { return true; } } }
You can add a validator in code like this:
@Override public void onViewConstructed() { super.onViewConstructed(); IStringField field = thisForm.FieldsView.nameField; field.addValidator(new MyCustomValidator()); }
If you want to customize the error message, override the method: getMessage()
public class MyCustomValidator extends AbstractValidator { @Override public boolean isValidValue(Object value) { String strValue = (String) value; if(strValue != null && strValue.contains("*")) { return false; } else { return true; } } @Override protected String getMessage() { return "MyCustomMessage: * is not allowed"; } }
Check result:
If you want to use this validator in Form designer for String type, add annotation @Validator and override method getDataType()
@Validator public class MyCustomValidator extends AbstractValidator { @Override public boolean isValidValue(Object value) { String strValue = (String) value; if(strValue != null && strValue.contains("*")) { return false; } else { return true; } } @Override protected String getMessage() { return "MyCustomMessage: * is not allowed"; } @Override public DataType getDataType() { return DataType.String; } }
You can now select a validator from the list of validators:
System parameters
If you want to read system parameter value, you can use the following Platform method:
Boolean confirmDelete = Platform.getInstance().getSystemParameter( ConstSystemParameters.CONFIRM_DELETE );
User login
Use the following Platform method to access currently logged user:
UserLogin user = Platform.getInstance().getUserLogin();
User login parameters / Local storage
Codeless Platform is a technology agnostic solution. For client-side technologies, user parameters are stored in browser local storage and for server-side technologies the same data is stored in the database table user_login_parameter.
The code is the same for both types of technologies.
-
Setting value:
Platform.getInstance().putToStrage(“key”, “value”);
-
Getting value:
String value = Platform.getInstance().getFromStorage(“key”);
Caching
Codeless Platform is using EHCACHE (https://www.ehcache.org/) for caching.
There are several types of data that are cached like MetaForm, Messages, Menus etc.
You can control if you want caching to be used or not and if caching is used, cache limit per each data that is cached, by setting System Parameter.
We will explore how the cache is used on the example of caching Meta Forms:
-
Put Meta Form in cache:
Platform.cacheProvider.getMetaFormCache().put(name, metaForm);
-
Get Meta Form from cache:
MetaForm metaForm = Platform.cacheProvider.getMetaFormCache().get(name);
-
Remove Meta Form from cache:
Platform.cacheProvider.getMetaFormCache().remove(name);
-
Clear Meta Form cache:
Platform.cacheProvider.getMetaFormCache().clear();
-
Get all Meta Forms cached:
List<MetaForm> all = Platform.cacheProvider.getAllMetaFormsCached();
Starting form from code
-
Create and configure form starter example:
FormStarter starter = new FormStarter(); FormStarterConfig config = new FormStarterConfig(); config.setMetaFormName(name); config.setMode(Mode.EDIT); starter.setConfig(config);
Note that there are other configurations you can control, this is just an example.
-
Show form in the window:
starter.showInWidnow();
This will show the form in the window.
-
Show form in a workspace:
starter.showInWorkspace();
This will show the form in the workspace, like it’s started from the application menu.
-
Show form in the panel:
starter.showInPanel(panel);
This will show form on any panel you provide as an argument.
Custom components
The custom component is a GUI component that can be used inside Form Designer like standard Meta Field components. All custom components have the same Meta Field Type: “Custom”
What differs concrete custom components from other custom components is Meta Fields property: “customName”.
Example content of META_FIELD table:
Creating new custom component:
Every GUI component in Codeless Platform has to implement interface IComponent. Custom components can extend any concrete component like UILabel, UIStringField etc.
Every custom component must have annotation @Component defined in Codeless Platform as:
public interface IComponentGetter extends IGetter { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public static @interface Component {} ICustomComponent getInstance(String name) throws Exception; }
In addition, each custom component has to implement ICustomComponent.
Example custom component:
@Component public class MyCustomComponent extends UIStringField implements ICustomComponent { @Override public String getFieldValue() { return "CUSTOM " + super.getFieldValue(); } @Override public void setCustomProperties(String properties) { } @Override public IComponent getDesignerComponent() { return this; } }
Methods setCustomProperties and getDesignerComponent are not used in this example. These two methods are shown here because we need to implement them.
CustomProperties allows us to define properties that are stored in MetaField.customProperty as name-value pairs and method getDesignerComponent() allows us to show some other components in Meta Form designer instead of our component. Examples can be found in the custom component OrgChart.
Using custom component in Form Designer:
In order to use custom components in Form Designer we need to define the properties of our component.
Properties:
All properties are defined in table FIELD_PROPERTY
For each MetaFieldType the list of properties are defined in table META_FIELD_TYPE_ATTRIBUTE
Example content for MyCustomComponent custom component:
The last step is to define an Icon that will show in the list of custom components. In order to define an Icon for our MyCustomComponent we need to copy an image to the location: WebResources\images\static\custom with the name MyCustomComponent and appropriate file type name:
Now, everything is ready, we can use our component in Form Designer:
Open some form and select Fields View where you want to add custom component:
Click “configure” (cogs icon)
Click add and then select “Custom field”:
When added, select the custom component and click “configure”:
Finally, configure properties of custom component in Property window:
That’s it, save your form and use new custom components like any other standard Meta Field.