首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从react中呈现的html表单中提取值-传单弹出。

从react中呈现的html表单中提取值-传单弹出。
EN

Stack Overflow用户
提问于 2022-08-14 16:59:27
回答 1查看 78关注 0票数 0

好的,我正在使用react -传单库将一张地图带到我的页面中,这是我用react和nextjs创建的。我增加了反应传单绘制库的组件,允许用户在地图上绘制功能。

我的目标是在用户完成绘制功能时打开一个弹出窗口。在该弹出窗口中将有一个简单的表单,用户可以在其中输入“名称”和“描述”,当单击“保存”时,将发出一个redux操作,包括其有效载荷名称、描述和绘制功能的geojson。

当用户完成绘图时,我能够打开一个弹出窗口,用一个简单的HTML表单填充它,并且独立于它,并将绘制的特性提取为GeoJSON。我的问题是无法提取输入字段的内容。

这是呈现映射的功能组件:

代码语言:javascript
复制
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css';
import 'leaflet-defaulticon-compatibility';
import 'leaflet-draw/dist/leaflet.draw.css'
import { FeatureGroup, MapContainer, Marker, Popup, TileLayer } from 'react-leaflet'
import { locationsType } from '../../pages/api/starterSet'
import { EditControl } from 'react-leaflet-draw'
import styles from '../../styles/components/popupForm.module.css'
import L from 'leaflet';
import PopupForm from './PopupForm'
import { useDispatch } from 'react-redux';
import { testing } from '../../reduxState/reduxState'
import ReactDOMServer from 'react-dom/server'


interface leafletMapProps {
  locations: locationsType
  drawnLayersRef: any
}

const LeafletMap = ({ locations, drawnLayersRef }:leafletMapProps) => {
  const dispatch = useDispatch()

  //creating button and its event listener that dispatches action
  const button = L.DomUtil.create('button');
  button.innerHTML = 'Save';
  button.addEventListener('click', () => { 
    console.log(
      "eventlistener triggered, input content: ", 
      document.getElementById('popupFormName')?.innerHTML
      )
    dispatch(testing())
  });

  //creating popupcontent out of simple html form and adding button
  const container = L.DomUtil.create('div');
  container.innerHTML = ReactDOMServer.renderToString(<PopupForm/>);
  container.appendChild(button);

  //creating custom popup and filling it with custom content
  const popup = L.popup();
  popup.setContent(container);


  return (
    <>
      <MapContainer center={[52.5200, 13.4050]} zoom={13} scrollWheelZoom={true} style={{height: 400, width: "100%"}}>
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        <FeatureGroup ref={drawnLayersRef}>
          <EditControl
            position="topright"
            draw={{
              rectangle: false,
              circle: true,
              circlemarker: false,
              polyline: { 
                showLength: true,
                metric: true },
              polygon: {
                allowIntersection: false, // Restricts shapes to simple polygons
                drawError: {
                  color: 'red', // Color the shape will turn when intersects
                  message: '<strong>That is a terrible polygon! Draw that again!'
                }
              }
            }}
            onCreated={(e) => {
              console.log("onCreated!")
              console.log("CREATED LAYER", e.layer.toGeoJSON())
              e.layer.bindPopup(popup).openPopup();
            }}
          />
        </FeatureGroup>   
      </MapContainer>
    </>
  )
}

export default LeafletMap

这是包含html表单的函数组件。

代码语言:javascript
复制
import styles from '../../styles/components/popupForm.module.css'

const PopupForm = (ref: any) => {
  return (
    <form className={styles.form}>
      <input
        id='popupFormName'
        name='name' 
        placeholder='name...'
        ref={ref}
        className={styles.inputField}
      />
      <textarea 
        id='popupFormDescr'
        name="description" 
        placeholder="description (max 300 characters)"
        maxLength={300}
        className={styles.inputTextarea}
      />
    </form>
  )
}

export default PopupForm

我使用ReactDOM.renderToString方法创建弹出的内容,因为在react-传单中,您很不幸不能在弹出窗口中直接呈现JSX。该解决方案被建议为这里

我尝试使用getElementByID提取带有普通Javascript的输入字段内容,但是innerHTML属性返回为空。当我console.log HTML元素本身时,我得到

代码语言:javascript
复制
<input id="popupFormName" name="name" placeholder="name..." class="popupForm_inputField__iQuhs">

我认为这是元素的初始状态,即执行renderToString方法时所处的状态。因此,在renderToString执行之后,浏览器似乎对这些html元素发生的更改不再敏感,尽管它正确地呈现了它们。

我尝试使用Reacts`s的useRef钩子,方法有两种: 1)在映射组件的级别上创建ref,通过道具将其传递给PopupForm组件,并使用ForwardRef组件将其分配给HTML元素和2)。在这两种情况下,我都能够console.log实际的HTML元素,该元素分配了ref,但是它的value属性也是空的。

我已经考虑过ReactDOM.findDOMNode方法,但是它是遗留的,文档声明它不适用于功能组件。

我正在寻找A)一种在弹出窗口中提取HTML输入元素内容的方法,坚持我对renderToString方法或B的方法)一种将HTML或理想的JSX代码引入弹出式中的替代方法,这是已知的与我的usecase一起工作的方法。

帮助是非常感谢的!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-15 11:45:11

好的,我改变了弹出内容的构造方式,开始工作了。现在我不再使用ReactDOM.renderToString方法,而是使用ReactDOM.render方法。

这就是现在的整个组件

代码语言:javascript
复制
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css';
import 'leaflet-defaulticon-compatibility';
import 'leaflet-draw/dist/leaflet.draw.css'
import { FeatureGroup, MapContainer, Marker, Popup, TileLayer } from 'react-leaflet'
import { locationsType } from '../../pages/api/starterSet'
import { EditControl } from 'react-leaflet-draw'
import styles from '../../styles/components/popupForm.module.css'
import L from 'leaflet';
import { useDispatch } from 'react-redux';
import { testing } from '../../reduxState/reduxState'
import * as ReactDOM from 'react-dom/client';


interface leafletMapProps {
  locations: locationsType
  drawnLayersRef: any
}

const LeafletMap = ({ locations, drawnLayersRef }:leafletMapProps) => {
  const dispatch = useDispatch()

  const createPopupContent = (geoJsonString: string) => { 
   return <form 
      className={styles.form}
      onSubmit={(event: React.FormEvent<HTMLFormElement> & { target: HTMLFormElement }) => {
        console.log("FORMSUBMIT FUNC TRIGGERD")
        event.preventDefault()
        const formData = Object.fromEntries(new FormData(event.target));
        console.log("FORMDATA: ", formData, "GEOJSON: ", geoJsonString)
        dispatch(testing())
        }
      }
    >
      <input
        id='popupFormName'
        name='name' 
        placeholder='name...'
        className={styles.inputField}
      />
      <textarea 
        id='popupFormDescr'
        name="description" 
        placeholder="description (max 300 characters)"
        maxLength={300}
        className={styles.inputTextarea}
      />
      <input
        id='submitBtn'
        type='submit'
        name='Submit!'
        />
    </form>
  }
  
  const renderPopupForm = (geoJsonString: string) => {
    const popup = L.popup();
    const container = L.DomUtil.create('div');
    popup.setContent(container);
    const root = ReactDOM.createRoot(container);
    root.render(createPopupContent(geoJsonString));
    return popup;
  }

  return (
    <>
      <MapContainer center={[52.5200, 13.4050]} zoom={13} scrollWheelZoom={true} style={{height: 400, width: "100%"}}>
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        <FeatureGroup ref={drawnLayersRef}>
          <EditControl
            position="topright"
            draw={{
              rectangle: false,
              circle: true,
              circlemarker: false,
              polyline: { 
                showLength: true,
                metric: true },
              polygon: {
                allowIntersection: false,
                drawError: {
                  color: 'red',
                  message: '<strong>That is a terrible polygon!'
                },
              }
            }}
            onCreated={(e) => {
              const geoJsonString = e.layer.toGeoJSON()
              e.layer.bindPopup(renderPopupForm(geoJsonString), {
                closeButton: false
              }).openPopup();
            }}
          />
        </FeatureGroup>   
      </MapContainer>
    </>
  )
}

export default LeafletMap

我沿着函数传递GeoJSON字符串,这有点笨重,我通过表单提交均衡器中的“新FormData”提取输入值,这不是惯例。

我试着用usestate重写这两个语句,但是在formsubmit均衡器中调用那些状态将返回空值,不知道为什么,很可能与异步属性有关。

我还尝试用函数组件的导入替换createPopupContent(),但这会引发错误。

到目前为止,我也希望它能正常工作,但是如果有人有改进的建议,他们会非常感激的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73353506

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档