This article introduces how to dynamically add and delete rich text using braft-Editor using antD-based forms in the React project.
First, demand background
The required content is to enter the configuration mode by clicking configuration (if existing text modules need to be converted to rich text editing mode). You can dynamically add and delete rich text on the page, and then click the save button to uniformly save all text and display it.
The interaction flow chart is as follows:
Two, the final effect
The final result is as follows:
Third, the implementation process
Basic use of rich text
Antd-based Form forms using rich text can be found in the official Demo
Dynamic add delete rich text
Since the rich text component is placed in the Form component, dynamically adding and deleting rich text is equivalent to dynamically adding and subtracting Form items (form.list).
<Form
onFinish={handleSubmit}
layout="horizontal"
autoComplete="off"
>
<Form.List name="moduleExtras">
{(fields, { add, remove }) => (
<>
{fields.map(field => {
return (
<div key={field.key} className={styles.formItem}>
<div className={styles.formItemHeader}>
<Form.Item
{. field}
label="Title"
name={[field.name, 'title']}
fieldKey={[field.fieldKey, 'title']}
>
<Input placeholder="Please enter a title" allowClear style={{ width: 300}} / >
</Form.Item>
<Button onClick={()= > remove(field.name)} icon={<DeleteOutlined />} danger > delete</Button>
</div>
<Form.Item
{. field}
name={[field.name, 'content']}
fieldKey={[field.fieldKey, 'content']}
>
<BraftEditor
style={{ border: '1px solid #dedede', marginTop: 10 }}
controls={controls}
placeholder="Please enter the content of the text"
/>
</Form.Item>
</div>
);
})}
<Form.Item>
<Button
type="default"
onClick={()= > add()}
icon={<PlusOutlined />} > Add a module</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item style={{ marginTop: 10}} >
<Button type="primary" htmlType="submit">Save the configuration</Button>
</Form.Item>
</Form>
Copy the code
The add module button in the lower left corner and the delete button in the upper right corner call the add and remove methods provided by form. List respectively to add and delete forms.
Displays rich text edited content
When the save configuration button is clicked, the form’s onFinish will collect the form’s data and print it as the first parameter to the method, producing the following results:
ModuleExtras is the name attribute of form. List, which holds the data currently collected by the Form. Content is a rich text instance, and to get the edited content you need to call EditorState.tohtml () to get the HTML.
/** Bind to Form onFinish */
const handleSubmit = values= > {
params = values.moduleExtras.map(item= > ({
title: item.title,
content: item.content.toHTML(),
}));
console.log(params) // [{title: "111", content: "<p>222</p>"}]
}
Copy the code
The rendering text module is based on the HTML of the content. I did not use the method in the official document. The method is as follows:
// Add a specific className to the container used to display HTML content
<div className="braft-output-content" dangerouslySetInnerHTML={{__html: outputContent}}></div>
Copy the code
DangerouslySetInnerHTML is Reac’s alternative to innerHTML for the browser DOM, similar to Vue’s V-HTML.
One problem with this approach is that when there are multiple Spaces in the HTML, only one or no space is rendered.
The solution is to add the white-space: preCSS attribute to the displayed tag.
The way I display HTML is to use the official readOnly property to set the rich text to read-only mode and empty the toolbar to achieve the same effect.
<BraftEditor
value={BraftEditor.createEditorState(content)}
readOnly
controls={[]}
contentStyle={{ height: 'auto'.overflowY: 'hidden'.paddingBottom: 0}} / >Copy the code
Add the ability to upload images to rich text
First refer to the official upload picture Demo method to add rich text upload picture control.
/** Custom upload picture control */
const extendControls = field= >[{key: 'antd-uploader'.type: 'component'.component: (
<Upload {. uploadFiles} >{/* It is best to add type="button" to the button to avoid triggering a form submission in the form container. This is not the case with the BUTTON component using Antd.<button
type="button"
className="control-item button upload-button"
data-title="Insert picture"
onClick={()= >SetUploadField (field)} > Insert image</button>
</Upload>),},];// File upload
const uploadFiles = {
accept: 'image/*'.// Only images are accepted
name: 'file'.action: '/uploadUrl'.// Here is the url of the interface for uploading images
showUploadList: false.onChange: info= > {
if (info.file.status === 'done') { // Image upload success returns url
const { moduleExtras } = form.getFieldsValue(); // Get form data
if (moduleExtras[uploadField.name]) { // uploadField is the content of the current form item saved when an image is clicked. Name is the index
moduleExtras[uploadField.name] = {
// Use name to obtain the form item corresponding to the index. moduleExtras[uploadField.name],// Reset the contents other than rich text, otherwise the contents other than rich text will be empty
content: ContentUtils.insertMedias(moduleExtras[uploadField.name].content, [
{
type: 'IMAGE'.url: info.file.response.data.originUrl / / picture url,},]),};// Backfill the form after modifying the content
form.setFieldsValue({ moduleExtras });
Message.success('Upload successful');
} else {
Message.warning('Upload failed'); }}else if (info.file.status === 'error') {
Message.error('Upload failed'); }}};Copy the code
Antd Upload function to use the Upload component, it is important to note the pictures inserted into the rich text editor needs to call ContentUtils. InsertMedias method, method of the first parameter is the rich text instance, Therefore, we need to obtain the rich text instance under the form item corresponding to the uploaded picture through the form to insert the picture into the corresponding rich text.
Add verification function
Use isEmpty() to add a non-null check function to rich text. The code is as follows:
<Form.Item {... field} name={[field.name,'content']}
fieldKey={[field.fieldKey, 'content']}
rules={[
{
required: true.validator: (_, value) = >
value.isEmpty() // call the isEmpty method to check if it isEmpty
? Promise.reject(new Error('Text cannot be empty'))
: Promise.resolve(),
},
]}
>
Copy the code
Set the initial value for the form
Finally, when several text modules have been added to the page, click the configure button to convert the text module into rich text editing mode.
Just iterate through the data of the text module to generate the data of the initial value of the form, and then pass the data to the initialValues of the form, the implementation code is as follows:
/** Initial value */
const initialValues = initialModule.map((item, index) = > ({
fieldKey: index,
isListField: true.key: index,
name: index,
title: item.title,
content: BraftEditor.createEditorState(item.content),
}));
<Form
form={form}
onFinish={handleSubmit}
layout="horizontal"
initialValues={{ moduleExtras: initialValues }}
autoComplete="off"
>
Copy the code