Render dynamic elements ReactJS? - javascript

So i am trying to create a dynamic form with a couple of HTML inputs. i have an array of object Forms which contain the type of input that should be rendered. Currently i am able to render a couple of inputs like text area but how do i deal with radios, check boxes, selects along with their options? Any help will be appreciated.
See this CodeSandbox.
Check this Sample Code:-
class App extends React.Component {
state = {
Forms: [{
name: "select",
type: "select",
options: ["a", "b", "c"]
},
{
name: "Radio",
type: "radio",
options: ["a", "b", "c"]
},
{
name: "Date",
type: "date",
value: "2018-07-22"
},
{
name: "Text Input",
type: "text",
value: "text input"
},
{
name: "Checkbox",
type: "checkbox",
options: ["a", "b", "c"]
},
{
name: "Textarea",
type: "textarea",
value: "text area"
}
]
};
renderForm = () => {
return this.state.Forms.map((form, index) => ( <
label key = {index} > { form.name}
<input type = { form.type }
value = { form.value } />
<select/ >
</label>
));
};
render() {
return <div > {
this.renderForm()
} < /div>;
}
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Thank you for all the help. :)

Something like:
import React from "react";
import "./styles.css";
class App extends React.Component {
state = {
Forms: [
{ name: "select", type: "select", options: ["a", "b", "c"] },
{ name: "Radio", type: "radio", options: ["a", "b", "c"] },
{ name: "Date", type: "date", value: "2018-07-22" },
{ name: "Text Input", type: "text", value: "text input" },
{ name: "Checkbox", type: "checkbox", options: ["a", "b", "c"] },
{ name: "Textarea", type: "textarea", value: "text area" }
]
};
getField = (field) => {
switch(field.type) {
case 'date':
case 'text':
case 'textarea':
return <input type={field.type} value={field.value} />;
case 'select':
return <select name={field}>
{field.options.map(option =>
<option key={option} value={option}>{option}</option>
)};
</select>;
case 'radio':
case 'checkbox':
return <div>{field.options.map((option) =>
<label>
{option}:
<input key={option} type={field.type} name={option} value={option}/>
</label>
)}</div>;
default:
return <div>Unknown form field</div>;
}
}
renderForm = () => {
return this.state.Forms.map((field, index) => (
<label key={index}>
{field.name}
{this.getField(field)}
</label>
));
};
render() {
return <div>{this.renderForm()}</div>;
}
}
export default App;

You need to handle the different form types differently. See update example:
class App extends React.Component {
state = {
Forms: [{
name: "select",
type: "select",
options: ["a", "b", "c"]
},
{
name: "Radio",
type: "radio",
options: ["a", "b", "c"]
},
{
name: "Date",
type: "date",
value: "2018-07-22"
},
{
name: "Text Input",
type: "text",
value: "text input"
},
{
name: "Checkbox",
type: "checkbox",
options: ["a", "b", "c"]
},
{
name: "Textarea",
type: "textarea",
value: "text area"
}
]
};
renderForm = () => {
return this.state.Forms.map((form, index) => {
if (form.type === 'checkbox' || form.type === 'radio') {
return (
<span>
{form.name}
{form.options.map(opt => (
<label key={opt}>
<input type={form.type} group={form.name} value={opt} />
{opt}
</label>
))}
</span>
);
}
if (form.type === 'select') {
return (
<label key={index}>{form.name}
<select>
{form.options.map(opt => (
<option key={opt}>
{opt}
</option>
))}
</select>
</label>
);
}
return (
<label key={index}>{form.name}
<input type={form.type} value={form.value} />
</label>
);
});
};
render() {
return <div > {
this.renderForm()
} < /div>;
}
}
ReactDOM.render(<App />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Related

how to display json data in dropdown using reactj

i need to display data in dropdown i haven given json data with code.
this.setState({
data : [
{id:1,type:A},
{id:1,type:B},
{id:1,type:C},
]
})
<select className="form-control" onChange={(e) => this.handleChange(e)} >
<option >Select data</option>
{
this.state.data.map((i, h) =>
(<option key={h} value={i.type}>{i.type}</option>))
}
</select>
Json isn't correct...put quotation for string type value-"A", "B", "C"
data: [{ id: 1, type: "A" }, { id: 1, type: "B" }, { id: 1, type: "C" }]
JSX
class App extends Component {
state = {
data: [{ id: 1, type: "A" }, { id: 1, type: "B" }, { id: 1, type: "C" }]
};
handleChange = e => {
console.log(e.target.value);
};
render() {
return (
<div>
<select className="form-control" onChange={this.handleChange}>
<option>Select data</option>
{this.state.data.map((i, h) => (
<option key={h} value={i.type}>
{i.type}
</option>
))}
</select>
</div>
);
}
}

Attempting to show array element of react select in list item

I am using react-select to store multiple elements and am using the map function to display elements which is working fine. But when I am using the same element in another class to display in a list element it shows a blank.
Here is the code where I am displaying the multiple options.
const Departments = [
{ label: "OneIT", value: "OneIT" },
{ label: "HR", value: "HR" },
{ label: "Vigilance", value: "Vigilance" },
{ label: "Ethics", value: "Ethics" },
{ label: "Corporate Services", value: "Corporate Services" },
{ label: "Legal", value: "Legal" },
{ label: "Sports", value: "Sports" },
{ label: "TQM", value: "TQM" },
{ label: "Iron Making", value: "Iron Making" },
{ label: "TMH", value: "TMH" }
];
class MultiSelect2 extends Component {
state = {
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
render() {
const { selectedOption } = this.state;
return (
<div className="container">
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-8">
<span>Select Department</span>
<Select
value={selectedOption}
options={Departments}
onChange={this.handleChangeField}
isMulti
/>
{this.state.selectedOptions.map(o => (
<p>{o.value}</p>
))}
</div>
<div className="col-md-4"></div>
</div>
</div>
);
}
}
I am trying to display this in another class in the list item but it is not showing.
export class Confirm extends Component {
state = {
selectedOptions: []
};
render() {
const {
values: {selectedOptions
}
} = this.props;
return (
<List>
<ListItemText primary="Departments" secondary={selectedOptions} />
</List>

Filling a model with a list from Textarea

Now I do not really understand you. Sorry, I just started this whole study not so long ago. I’ll try to explain again what I can’t do.
I have an empty object and an object with data with the same structure.
data: [
{id: 1, title: "title1"},
{id: 2, title: "title1"},
{id: 3, title: "title3"},
{id: 4, title: "title4"},
{id: 5, title: "title3"}
],
item: [
{
itemId: "",
itemname: ""
}
]
And I have select and textarear. Select have data, textarear empty. Textarear displays title.
I want to press a button. Selected item from select. copied to textarear (title only), and also itemId - this selected element id: 5 and itemname - the same title: "title3" element, was recorded in item [].
https://codesandbox.io/s/priceless-hermann-g9flw
Please do check now
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
id: null,
title: "",
filmItem: "",
listFilms: [],
data: [
{ id: 1, title: "title1" },
{ id: 2, title: "title2" },
{ id: 3, title: "title3" },
{ id: 4, title: "title4" }
],
item: []
};
this.onChange = this.onChange.bind(this);
this.onChangeArea = this.onChangeArea.bind(this);
this.addFilm = this.addFilm.bind(this);
this.choice = this.choice.bind(this);
}
addFilm(film) {
const selectedData = this.state.data.find(item => item.id == film);
console.log(selectedData);
this.setState({
listFilms: [...this.state.listFilms, selectedData.title],
item: [
...this.state.item,
{ itemId: selectedData.id, itemname: selectedData.title }
]
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onChangeArea = e => {
this.setState({ [e.target.name]: e.target.value.split("\n") });
};
choice(title) {
this.setState({ filmItem: title });
}
render() {
return (
<div className="App">
<div className="row App-main">
<div>
<select name="filmItem" size="4" onChange={e => this.onChange(e)}>
{this.state.data.map(film => (
<option key={film.title} value={film.id}>
{film.title}
</option>
))}
</select>
</div>
<div>
<button
className="editButton"
onClick={() => this.addFilm(this.state.filmItem)}
>
button
</button>
</div>
<div>
<textarea
name="films"
onChange={this.onChangeArea}
value={this.state.listFilms.map(r => r).join("\n")}
/>
</div>
<div>
<input type="text" name="text-input" onChange={this.onChange} />
</div>
</div>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(this.state)}
</pre>
</div>
);
}
}
export default App;

Display JSON in table with React

I am new to React and I am trying to display table of data from objects with plan to also have a collapsible detail of the properties for each store but for now I am struggling to display anything other than the first value. Any help appreciated. I looked at many other examples but being a newbie I can't get my head around them so hoping understanding my exact scenario first will allow me figure out more on my own.
Tried return multiple calls with for loop but returns just one element and exits.
import React, { Component } from "react";
class DataStores extends Component {
state = [
{
name:"PODs",
storeType:"fixed",
properties: [
{
name:"PODNo",
type: "text",
regex: ""
}
,
{
name:"CustomerCode",
type: "text",
regex: ""
},
{
name:"CustomerName",
type: "text",
regex: ""
},
{
name:"RefDate",
type: "datetime",
regex: ""
}]
}
,
{
name:"SalesOrders",
storeType:"variable",
properties: [
{
name:"OrderNo",
type: "text",
regex: ""
}
,
{
name:"CustomerRef",
type: "text",
regex: ""
},
{
name:"OrderDate",
type: "datetime",
regex: ""
}]
}
];
;
render() {
console.log('state', this.state);
for (let store of this.state){
console.log(store.name);
let chars = store["properties"]
console.log(chars);
for(let i=0, len=chars.length; i < len; i++){
console.log(chars[i].name)
// console.log(chars[i].name);
// console.log(chars[i]["type"]);
}
}
return (
<table>
<tbody>{this.state.map((item, key) =>{
return (
<tr key = {key}>
<td>{item.name}</td>
<td>{item.storeType}</td>
</tr>
)
})}</tbody>
</table>
)
// let dataStores = this.state.dataStores.map(store => {
// console.log("this the ",Object.keys(store),store.name);
// return (<div><li>{store.name}</li>
// </div>
// );
// });
}
}
export default DataStores;
Here you go, the following approach is much better.
Check it out on sandbox as well: https://codesandbox.io/s/silly-meadow-f6hpz?fontsize=14
import React, { Component } from "react";
class DataStores extends Component {
state = {
values: [
{
name: "PODs",
storeType: "fixed",
properties: [
{
name: "PODNo",
type: "text",
regex: ""
},
{
name: "CustomerCode",
type: "text",
regex: ""
},
{
name: "CustomerName",
type: "text",
regex: ""
},
{
name: "RefDate",
type: "datetime",
regex: ""
}
]
},
{
name: "SalesOrders",
storeType: "variable",
properties: [
{
name: "OrderNo",
type: "text",
regex: ""
},
{
name: "CustomerRef",
type: "text",
regex: ""
},
{
name: "OrderDate",
type: "datetime",
regex: ""
}
]
}
]
};
render() {
// console.log('state', this.state);
// for (let store of this.state){
// console.log(store.name);
// let chars = store["properties"]
// console.log(chars);
// for(let i=0, len=chars.length; i < len; i++){
// console.log(chars[i].name)
// // console.log(chars[i].name);
// // console.log(chars[i]["type"]);
// }
// }
return (
<table>
<tbody>
{this.state.values.map((item, key) => {
return (
<tr key={key}>
<td>{item.name}</td>
<td>{item.storeType}</td>
</tr>
);
})}
</tbody>
</table>
);
// let dataStores = this.state.dataStores.map(store => {
// console.log("this the ",Object.keys(store),store.name);
// return (<div><li>{store.name}</li>
// </div>
// );
// });
}
}
export default DataStores;

React how to jump to a target input area in a form?

I had a very long form which around 20 different fields and I displayed those input area using map function. I want to valid the input data when I click the submit button and jump to the corresponding input required box.
const ReportFields = [
{
title: "Report Title*",
field: "report_title",
type: "text",
required: true
},
{
title: "Submitting Agency*",
field: "submitting_agency",
type: "text",
required: true
},
{
title: "Division*",
field: "division",
type: "select",
required: true
},
{
title: "Committee*",
field: "committee",
type: "select",
required: true
},
{
title: "Assigned Contact*",
field: "assigned_contact",
type: "select",
required: true
},
{
title: "Other Recipients",
field: "other_recipients",
type: "text",
required: false
}];
class App extends Component {
state = {
report: {
report_title: "",
submitting_agency: "",
division: "",
committee: "",
assigned_contact: "",
other_recipients: ""
},
errorMessage: "",
refs: {}
}
componentDidMount() {
this.registerRefs();
}
registerRefs = () => {
const refs = ReportFields.reduce((acc, current) => {
const ref = React.createRef();
acc[current.field] = ref;
return acc;
}, {});
this.setState({ refs });
}
onSubmit = (e) => {
e.preventDefault();
for (let i = 0; i < ReportFields.length; i++) {
const curt = ReportFields[i];
if (curt.required && this.state.report[curt.field] === "") {
this.setState({errorMessage: `${curt.title} cannot be empty!`});
this.state.refs[curt.field].current.focus();
break;
}
}
}
render() {
const display = ReportFields.map((field, idx) => {
return (
<div key={idx}>
<p>{field.title}</p>
<input
type={field.type}
onChange={(e) => {
this.setState({
report: {...this.state.report, [field.field]: e.target.value}
})
}}
ref={this.state.refs[field.field]}
></input>
</div>
);
})
return (
<div className="App">
{display}
<input type="button" value="submit" onClick={this.onSubmit}/>
</div>
);
}
}
export default App;
I tried to use react refs but it doesn't work, any idea?
Also, I am actually using these content in react modal, will this be one of the reason why it doesn't work?
Ok here is a solution I know who can work but I don't say it's the best one. A working example here https://codesandbox.io/s/94v4r6w7kr. As you can see when you click submit you jump to password input.
How do that work ? First as you can see we need a way to save all the ref we gonna create. I save it in the state refs here. The way that work is a loop over each field and for each one I createRef and add this to an object. I use this object inside the state. When you want to use it after that, you then can call this.state.refs[thenameoftheinput].current.focus().
This is an example, and I let you make it work with your own data. But I hope that can give you an idea :)
const ReportFields = [
{
title: "Report Title*",
field: "report_title",
type: "text",
required: true
},
{
title: "Submitting Agency*",
field: "submitting_agency",
type: "text",
required: true
},
{
title: "Division*",
field: "division",
type: "select",
required: true
},
{
title: "Committee*",
field: "committee",
type: "select",
required: true
},
{
title: "Assigned Contact*",
field: "assigned_contact",
type: "select",
required: true
},
{
title: "Other Recipients",
field: "other_recipients",
type: "text",
required: false
}
];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
refs: {}
};
}
componentDidMount() {
this.registerRefs();
}
registerRefs = () => {
const refs = ReportFields.reduce((acc, current) => {
const ref = React.createRef();
acc[current.field] = ref;
return acc;
}, {});
this.setState({ refs });
};
focusTextInput = () => {
this.state.refs.division.current.focus();
};
render() {
const inputs = ReportFields.map(el => {
return <input placeholder={el.title} ref={this.state.refs[el.field]} />;
});
return (
<div>
<form>
{inputs}
<input type="button" value="submit" onClick={this.focusTextInput} />
</form>
</div>
);
}
}
Iterate through all fields and create a separate ref for each one of them. Use a unique identifier (as a suggestion - the name property) to access the ref later.
class App extends Component {
constructor(props) {
super(props);
this.focusTextInput = this.focusTextInput.bind(this);
// Fields
this.ReportFields = [
{
type: "text",
name: "firstname",
title: "First Name"
},
{
type: "text",
name: "lastname",
title: "Last Name"
}
];
this.inputRefs = this.ReportFields.reduce((acc, field) => ({
...acc,
[field.name]: React.createRef()
}), {});
}
state = {
a: {
b: "",
c: "",
d: "",
e: "",
f: "",
g: "",
h: "",
i: "",
j: "",
k: "",
l: "",
m: "",
n: "",
o: "",
p: "",
q: "",
r: "",
s: "",
t: "",
u: "",
v: "",
w: "",
x: "",
y: ""
},
errorMessage: ""
};
focusTextInput() {
// Focus on the input you wish, in this case "firstname"
console.log(this.inputRefs["firstname"].current.focus());
}
render() {
const display = this.ReportFields.map((field, idx) => {
return (
<div key={idx}>
<p>{field.title}</p>
<input
type={field.type}
onChange={e => {
this.setState({
report: { ...this.state.report, [field.field]: e.target.value }
});
}}
ref={this.inputRefs[field.name]}
/>
</div>
);
});
return (
<div className="App">
{display}
<input type="button" value="submit" onClick={this.focusTextInput} />
</div>
);
}
}

Categories

Resources