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