Условное отображение / скрытие автоматически сгенерированных элементов формы в ReactJS
У меня есть приложение ReactJS, где я нахожусь
A) чтение входных данных JSON, описывающих структуру формы
B) динамическое создание формы из этого ввода JSON (с использованием document.createElement(..))
JSON будет выглядеть примерно так:
{
formElements: [
{
id: “dd1”,
type: “dropdown”,
options: [ {value: “first”}, {value: “second”}]
},
{
id: “tf1”,
type: “textfield”,
showIf: “dd1 == ‘second’”
}
]
}
Сложность заключается в том, что входной файл JSON не только описывает, какие элементы формы (например, выпадающий список, группа переключателей, текстовое поле) и т. Д. Должны присутствовать, но также описывает логику отображения / скрытия для каждого элемента. Например, если выбран конкретный выпадающий список, то должно быть показано текстовое поле (в противном случае оно должно оставаться скрытым).
Обычно это делается в jQuery, но я слышал, что jQuery не очень хорошая идея с React.
Если бы это были жестко закодированные элементы формы, я мог бы легко закодировать эту логику показа / скрытия. Проблема заключается в том, что элементы формы генерируются динамически (путем чтения этого файла JSON), и мне нужно на лету применить эту логику показа / скрытия к этим автоматически сгенерированным элементам формы.
Я не уверен, как это сделать.
Если у кого-то есть предложения по подходам, особенно с примерами, это будет высоко ценится. Спасибо!
1 ответ
Вы все еще должны иметь возможность применять логику условного рендеринга к коду JSX, который генерирует вашу форму, но рассматривали ли вы использование существующей библиотеки форм, такой как response-form или redux-form? Если вы относительно новичок, чтобы отреагировать, это был бы гораздо более легкий путь для получения желаемых результатов. Я не могу рекомендовать конкретную библиотеку форм, но отмечаю, что она обрабатывает динамические данные.
Вот мой грубый набросок того, как вы могли бы справиться с этим, не используя приставку или встроенную библиотеку форм. Это черновик, который был придуман, но не выполнен, поэтому относитесь к нему как к псевдо-коду и определенно не оптимизируйте:
//import base form components up here (input, checkbox, etc)
// Map the strings in your field object to the component imported or defined above
const fieldSelector = {
input : Input,
textarea: TextArea,
checkbox: CheckBox
}
Class CustomForm extends React.Component {
constructor(props) {
super(props);
const fields = {}
const byId = []
// Note if there is any asynchronous data, you might want to put this logic
// in componentDidMount
// Create an array with each 'id'
const byId = this.props.formData.map( item => item.id );
// Create a map object listing each field by its id
this.props.formData.forEach( (field) => {
fields[field.id] = field;
}
this.state = {
fields,
byId,
}
this.handleChange = this.handleChange.bind(this);
this.checkVisibility = this.checkVisibility.bind(this);
}
// Need to add some additional logic if you're using checkboxes
// Creates an event handler for each type of field
handleChange(id) {
return (event) => {
const updatedFields = {...this.state.fields};
updatedFields[id].value = event.target.value
this.state.byId.forEach( fieldId => {
updatedFields[fieldId].visible = checkVisibility(updatedFields, fieldId)};
}
this.setState({fields: updatedFields})
}
}
// You can either restructure your showIf or include a function above
// to parse our the elements of the expression.
checkVisibility(updatedFields, fieldId) {
const field = updatedFields[fieldId];
const showIfId = field.showIf.triggerFieldId;
const showIfValue = field.showIf.value;
const operator = field.showIf.operator;
switch(operator){
case '===':
return updatedFields[showIfId].value === ShowIfValue;
case '<':
return updatedFields[showIfId].value < ShowIfValue;
//...fill in rest of operators here
default:
return field.visible;
}
}
render() {
return this.state.byId.map( fieldId => {
const field = this.state.fields[fieldId];
const CustomField = FieldSelector[field.type]
return (
{field.visible &&
<CustomField {insert whatever props from field} />
}
);
});
}
}
export default CustomForm