Issue
In previous versions of Liferay, certain components, such as form fields, allowed the alteration of their HTML elements using JavaScript. However, starting from version 7.3.x, Liferay transitioned its components from Metal to React, and this capability is no longer feasible.
React manages its own virtual DOM to efficiently update the actual DOM. Directly modifying the DOM bypasses React's control and can lead to inconsistencies, particularly when state changes occur.
Environment
- Tested From Quarterly Release 2024.Q1
- To Quarterly Release 2025.Q1
Resolution
Creating a custom React component provides the ability to modify the virtual DOM used by React. Let's illustrate this with an example:
Suppose you are developing a form and need to alter some HTML elements of a field provided by Liferay out-of-the-box (OOTB), which is implemented in React, such as the upload field type.
Problem: You cannot access the React DOM object using JavaScript.
Solution: To address this, you can create a custom form field and modify the React virtual DOM elements.
We aim to change the color of this icon and alter the label and alter the background of form description
Current behavior: Icon are blue and description background is white.
Expected client behavior: Icon are green and form description background is red
How to implement:
- Create a custom form field using the instructions provided at https://learn.liferay.com/web/guest/w/dxp/process-automation/forms/developer-guide/writing-a-custom-form-field-type
- Modify the *.es.js file using the "useEffect" hook: React's "useEffect" hook is an essential part of functional components, allowing developers to manage side effects in their applications. One common scenario is interacting with external components.
import {ReactFieldBase as FieldBase} from 'dynamic-data-mapping-form-field-type'; import React, {useState, useEffect, useRef} from 'react'; export default function Slider({ label, name, onChange, predefinedValue, readOnly, value, ...otherProps }) { const [currentValue, setCurrentValue] = useState( value ? value : predefinedValue ); useEffect(() = { const collection = document.getElementsByClassName('ddm-form-field-repeatable-add-button'); const myElements = Array.from(collection); const descriptionEditor= document.getElementById('descriptionEditor'); if(descriptionEditor) { descriptionEditor.style.background = 'red'; console.log('descriptionEditor: '+descriptionEditor); } myElements.forEach((element, index) = { console.log('element: '+element); element.style.background = 'green'; element.title = 'Duplicate Odds'; }); }, []); return ""; };
After implementing this code, by adding the new form field type to the form, changes will be applied to the React component provided by Liferay OOTB.
Additional Information
- https://legacy.reactjs.org/docs/faq-internals.html
- https://blog.logrocket.com/virtual-dom-react/
- Important: For versions prior to 2024.Q1, use this article Modify-OOTB-react-component-I