我正在对表单使用formy-react,我想在触发事件时呈现更多选项,代码看起来像这样:
class MultipleChoice extends Component {
constructor(props) {
super(props);
}
render() {
return(
<div>
<Form>
<div id="dynamicInput">
<FormInput />
</div>
</Form>
</div>
);
}
}
我有一个按钮和onClick事件我想触发一个函数,将另一个函数追加到div id&#34; dynamicInput&#34;,是否可能?
答案 0 :(得分:2)
我没有使用formy-react但是我解决了同样的问题,发布在这里,以防有人试图做同样的事情而没有形式。
class ListOfQuestions extends Component {
state = {
questions: ['hello']
}
handleText = i => e => {
let questions = [...this.state.questions]
questions[i] = e.target.value
this.setState({
questions
})
}
handleDelete = i => e => {
e.preventDefault()
let questions = [
...this.state.questions.slice(0, i),
...this.state.questions.slice(i + 1)
]
this.setState({
questions
})
}
addQuestion = e => {
e.preventDefault()
let questions = this.state.questions.concat([''])
this.setState({
questions
})
}
render() {
return (
<Fragment>
{this.state.questions.map((question, index) => (
<span key={index}>
<input
type="text"
onChange={this.handleText(index)}
value={question}
/>
<button onClick={this.handleDelete(index)}>X</button>
</span>
))}
<button onClick={this.addQuestion}>Add New Question</button>
</Fragment>
)
}
}
答案 1 :(得分:0)
以下是此
的完整解决方案 var OnlineEstimate = React.createClass({
getInitialState: function() {
return {inputs:[0,1]};
},
handleSubmit: function(e) {
e.preventDefault();
console.log( this.refs );
return false;
},
appendInput: function(e) {
e.preventDefault();
var newInput = this.state.inputs.length;
this.setState({ inputs: this.state.inputs.concat(newInput)},function(){
return;
});
$('.online-est').next('.room-form').remove()
},
render: function() {
var style = {
color: 'green'
};
return(
<div className="room-main">
<div className="online-est">
<h2 className="room-head">Room Details
<button onClick={this.handleSubmit} className="rednew-btn"><i className="fa fa-plus-circle"></i> Save All</button>
<a href="javascript:void(0);" onClick={this.appendInput} className="rednew-btn"><i className="fa fa-plus-circle"></i> Add Room</a>
</h2>
{this.state.inputs.map(function(item){
return (
<div className="room-form" key={item} id={item}>
{item}
<a href="" className="remove"><i className="fa fa-remove"></i></a>
<ul>
<li>
<label>Name <span className="red">*</span></label>
<input type="text" ref={'name'+item} defaultValue={item} />
</li>
</ul>
</div>
)
})}
</div>
</div>
);
}
});
答案 2 :(得分:0)
这是一种现代的动态解决方案,其工作方式是根据json文件将输入组件与 React Hooks 重复使用。 外观如下:
使用这种范例的优点:输入组件(具有其自身的挂钩状态)可以在任何其他应用程序部分中重复使用,而无需更改任何代码行。
缺点要复杂得多。 这是简化的json(用于构建基于的组件):
{
"fields": [
{
"id": "titleDescription",
"label": "Description",
"template": [
{
"input": {
"required": "true",
"type": "text",
"disabled": "false",
"name": "Item Description",
"value": "",
"defaultValue": "a default description",
"placeholder": "write your initail description",
"pattern": "[A-Za-z]{3}"
}
}
]
},
{
"id": "requestedDate",
"label": "Requested Date",
"template": [
{
"input": {
"type": "date",
"name": "Item Description",
"value": "10-14-2007"
}
}
]
},
{
"id": "tieLine",
"label": "Tie Line #",
"template": [
{
"select": {
"required": true,
"styles": ""
},
"options": [
"TL625B",
"TL626B-$selected",
"TL627B",
"TL628B"
]
}
]
}
]
}
带有钩子的无状态输入组件,可以读取不同的输入类型,例如:文本,数字,日期,密码和其他一些类型。
import React, { forwardRef } from 'react';
import useInputState from '../Hooks/InputStateHolder';
const Input = ({ parsedConfig, className }, ref) => {
const inputState = useInputState(parsedConfig);
return (
<input
//the reference to return to parent
ref={ref}
//we pass through the input attributes and rewrite the boolean attrs
{...inputState.config.attrs}
required={inputState.parseAttributeValue(inputState.config, 'required')}
disabled={inputState.parseAttributeValue(inputState.config, 'disabled')}
className={`m-1 p-1 border bd-light rounded custom-height ${className}`}
onChange={inputState.onChange}
/>
)
};
//we connect this separated component to passing ref
export default forwardRef(Input)
挂钩持有人InputStateHolder.js文件
import { useState } from 'react';
const useInputState = (initialValue) => {
//it stores read the json, proccess it,
//applies modifies and stores input values
const [config, setInputConfig] = useState({
isLoaded: false,
attrs: { ...initialValue }
});
//mutating and storing input values
function changeValue(e) {
const updatedConfig = { ...config };
updatedConfig.attrs.value = e.target.value;
setInputConfig({ ...config })
}
// to apply form configs to input element
//only one time at the first load
function checkTheFirstLoad() {
const updatedConfig = { ...config };
if (config.attrs.value.length === 0) {
updatedConfig.attrs.value = config.attrs.defaultValue;
//defaultValue is not allowed to pass as attribute in React
//so we apply its value depending on the conditions and remove it
delete updatedConfig.attrs.defaultValue;
updatedConfig.isLoaded = true;
setInputConfig(updatedConfig);
}
}
//parsing boolean input attributs such as required or disabled
function parseAttributeValue(newState, attribute) {
return typeof newState.attrs[attribute] === 'string' && newState.attrs[attribute] === 'true'
? true : false
}
!config.isLoaded && checkTheFirstLoad();
//returning the hook storage
return {
config,
onChange: changeValue,
parseAttributeValue
}
}
export default useInputState;
以及父FormFields组件(包含表单和提交标签):
import React, { createElement } from "react";
import Input from '../UI/Input';
const FormField = ({ setConfig }) => {
//it receives the parsed json and check to not be empty
if (!!Object.keys(setConfig).length) {
const fieldsConfig = setConfig.fields;
//the array to get created elements in
const fieldsToGetBuilt = [];
// the array to store input refs for created elements
const inputRefs = [];
// the function to store new ref
const setRef = (ref) => inputRefs.push(ref);
fieldsConfig.map(field => {
switch (true) {
//here is we create children depending on the form configs
case (!!field.template[0].input): {
let classes = 'someStyle';
fieldsToGetBuilt.push(
createElement(Input, {
ref: setRef,
parsedConfig: field.template[0].input,
key: field.id,
className: classes
})
);
break
}
//default case needed to build warning div notifying the missed tag
default: {
let classes = 'someOther danger style';
let child = `<${Object.keys(field.template[0])[0]}/> not built`;
fieldsToGetBuilt.push(
createElement('div', {
key: field.id,
className: classes
}, child)
);
}
}
})
const onSubmitHandler = (e) => {
//every time we click on submit button
//we receive the inputs`es values in console
e.preventDefault();
inputRefs.map(e =>
console.log(e.value)
)
}
return (
<div className='m-2 d-flex flex-column'>
<form onSubmit={onSubmitHandler}>
<h5 className='text-center'>{setConfig.title}</h5>
<div className='d-flex flex-row justify-content-center align-items-center'>
{fieldsToGetBuilt.map(e => e)}
</div>
<input type="submit" onClick={onSubmitHandler} className='btn-info' />
</form>
</div >
)
}
// if in json there are no any fields to get built
else return <div>no Page has been built</div>
};
export default FormField;
结果在这里
在我的另一个answer中,我基于json实现了动态模块上传