I have a render function in the component which is responsible to render a controls on page. So far it is working fine.
render()
{
render
(
{this.state.Inputs.map(input => {
if (input.CODE === "VARIABLE") {
return (
<div className="row p-1">
<div className="col-sm-4">
<label>
<b>{input.LABEL_NAME}</b>
</label>
</div>
<div className="col-sm-6">
{this.renderControl(input.WIDGET_TYPE)}
<br />
</div>
</div>
);
}
})
)
}
and below is my renderControl() function. I want to generate unique ids for each control when I am rendering it on page. I am not sure how to do this. Could you please help. Thanks in advance.
renderControl = controlName => {
switch (controlName) {
case "INTEGER":
case "TEXTBOX":
case "MEDIUM_TEXTBOX":
case "NUMBER":
return <input type="text" width="70%" className="txtSize" />;
case "DROPDOWN":
case "DIALOG":
return <Dropdown />;
case "DATE":
return (
<DatePicker
selected={this.state.startDate}
onChange={this.handleChange}
/>
);
case "DIALOG":
return <Dropdown />;
case "BOOLEAN":
return (
<div className="some-class">
<input type="radio" className="radio" name="x" value="y" id="y" />
<label htmlFor="y">Yes</label>
<input type="radio" className="radio" name="x" value="z" id="z" />
<label htmlFor="z">No</label>
</div>
);
default:
return;
}
};
Change these 4 lines:
this.state.Inputs.map((input, index) =>
{this.renderControl(input.WIDGET_TYPE, index)}
renderControl = (controlName, index)
return <input type="text" key={index} width="70%" className="txtSize" ></input>;
Pass a unique identifier from the input object, assuming LABEL_NAME is unique.
If not then pass the index from the map function.
{this.state.Inputs.map((input, index) => {
if (input.ROW_CLASS_CODE === "MODEL_VARIABLE") {
return (
<div className="row p-1" key={input.LABEL_NAME}> // Change this line
<div className="col-sm-4">
<label>
<b>{input.LABEL_NAME}</b>
</label>
</div>
<div className="col-sm-6">
{this.renderControl(input.WIDGET_TYPE)}
<br />
</div>
</div>
);
}
change your code to the following
render()
{
render
(
{this.state.Inputs.map((input,key) => {
if(input.ROW_CLASS_CODE === "MODEL_VARIABLE"){
return (
<div className="row p-1">
<div className="col-sm-4">
<label ><b>{input.LABEL_NAME }</b></label>
</div>
<div className="col-sm-6">
{this.renderControl(input.WIDGET_TYPE,key)}
<br></br>
</div>
</div>
)
}
})
)
}
renderControl = (controlName,key) =>{
switch(controlName) {
case 'INTEGER_FIELD':
case 'SMALL_TEXTBOX':
case 'PERCENTAGE':
case 'MEDIUM_TEXTBOX':
case 'REAL_NUMBER':
case 'MONEY':
return <input type="text" key={key} width="70%" className="txtSize" ></input>;
case 'NARROW_DROPDOWN':
case 'SELECTION_DIALOG':
return (<Dropdown key={key}></Dropdown>);
case 'DATE_FIELD':
return (<DatePicker key={key}
selected={this.state.startDate}
onChange={this.handleChange}
/>)
case 'SELECTION_DIALOG':
return <Dropdown key={key}></Dropdown>;
case 'BOOLEAN_FIELD':
return (<div className="some-class" key={key}>
<input type="radio" className="radio" name="x" value="y" id="y" />
<label htmlFor="y">Yes</label>
<input type="radio" className="radio" name="x" value="z" id="z" />
<label htmlFor="z">No</label>
</div>);
default:
return ;
}
}`
Related
For some reason, when switching to Registration, the 3rd input "inherits" the value from the previous state, that is, in theory, it should not have a value, but nevertheless an equal Login appears. How to fix?
import React, { useState } from 'react';
function Auth() {
const [pagination, setPagination] = useState('log');
function pag() {
if (pagination === 'log') {
return (
<>
<input
type="text"
className="email"
placeholder="E-mail"
/>
<input
type="text"
className="password"
placeholder="Пароль"
/>
<input
type="button"
className="done"
value="Войти"
/> // From here is transmitted
</>
);
}
return (
<>
<input
type="text"
className="email"
placeholder="E-mail"
/>
<input
type="text"
className="password"
placeholder="Пароль"
/>
<input
type="text"
className="password password-repeat"
placeholder="Повторите пароль"
/> // To here
<input
type="button"
className="done"
value="Зарегестрироваться"
/>
</>
);
}
function changePag(ev) {
if (ev.target.dataset.type === 'log') {
setPagination('log');
} else {
setPagination('reg');
}
}
return (
<div className="auth_page">
<div className="pagination">
<input
type="button"
className="log"
data-type="log"
onClick={changePag}
value="Вход"
/>
<input
type="button"
className="reg"
data-type="reg"
onClick={changePag}
value="Регистрация"
/>
</div>
<div className="form">
{pag()}
</div>
</div>
);
}
export default Auth;
I am creating a menu planner and and started with basic form. I want to be able to enter an entre. If set entre has free of certain diets. I want to click on a checkbox, to switch to true. So I can save the state and render to the screen.
I tried different approaches and googled a lot but can't find anything that really works for me. I can get the checkboxes to switch to true, but it doesn't save the value changes to undefined. Or I had it work once, but it checked all the other checkboxes in the side object. Not what i want.
const ServiceForm = () => {
const service = {
entre:{
value:"",
veg:false,
glut:false,
dairy:false
},
side:{
value:"",
veg:false,
glut:false,
dairy:false
}
}
const [state, dispatch] = useReducer(reducer, service)
console.log(state)
return (
<div>
<form className="form">
<div className="meal-container">
<div className="entre-form">
<input
type="text"
name="entre.value"
onChange={(event) => {
dispatch({ type: "ENTRE", payload: event.target.value });
}}
className="entree"
placeholder="entree"
/>
<div className="diets">
<input
onChange={() => {
dispatch({ type: "ENTRE", veg: !state.entre.veg });
}}
checked={state.entre.veg}
type="checkbox"
/>
<label>Veg</label>
<input type="checkbox" />
<label>Gluten</label>
<input type="checkbox" />
<label>Dairy</label>
</div>
</div>
<div className="entre-form">
<input type="text" name="sideOne" placeholder="Side One" />
<div className="diets">
<input
onChange={() => {
dispatch({ type: "VEG", payload: !state.vegetarian });
}}
checked={state.vegetarian}
type="checkbox"
/>
<label>Veg</label>
<input type="checkbox" />
<label>Gluten</label>
<input type="checkbox" />
<label>Dairy</label>
</div>
</div>
<div className="entre-form">
<input name="entre.value" placeholder="Side Two" />
<div className="diets">
<input type="checkbox" />
<label>Veg</label>
<input type="checkbox" />
<label>Gluten</label>
<input type="checkbox" />
<label>Dairy</label>
</div>
</div>
<div className="entre-form">
<textarea
name="description"
className="description"
placeholder="description"
/>
</div>
</div>
</form>
</div>
);
};
export default ServiceForm;
My reducer function
export const reducer = (state, action) =>{
switch(action.type){
case 'ENTRE':return{
...state,
entre:{
value:action.payload,
veg:action.veg
}
}
}
}
You reducer should be. I will also suggest you have separate actions for text input and checkbox.
switch(action.type){
case 'ENTRE':return{
...state,
entre:{
...entre,
value:action.payload,
veg:action.veg
}
}
}
}
I am working on a form that takes an order from customers and I am using React Redux to manage my state. There is an array of object named items where I add the items of the order to it. Every item is an object of 4 properties (name, quantity, price, instructions). And here is how I handle my form :
for (let i = 0; i < numOfItems; i++) {
rows.push(
<div key={i} className="add-items-form">
<div className="items-header-container">
<h3 className="items-form-header">ITEM #{i + 1}</h3>
<Button onClick={() => removeItem(i)}>Remove Item</Button>
</div>
<div className="row">
<FormGroup className="col-md-6">
<Label >Item Name</Label>
<Input type="text" name="name" onChange={setFormValue} value={form.items.name} />
</FormGroup>
<FormGroup className="col-md-6">
<Label >QTY</Label>
<Input type="number" name="quantity" onChange={setFormValue} value={form.items.quantity} />
</FormGroup>
</div>
<div className="row">
<FormGroup className="col-md-6">
<Label >Price</Label>
<Input type="number" name="price" onChange={setFormValue} value={form.items.price} />
</FormGroup>
<FormGroup className="col-md-6">
<Label >Special Instructions</Label>
<Input type="text" name="special_instructions" onChange={setFormValue} value={form.items.special_instructions} />
</FormGroup>
</div>
</div>
)
};
This is the redux action that takes the input :
export function setFormValue(field) {
console.log("FIELD", field.target.value)
return function (dispatch) {
dispatch({ type: types.SET_FORM_VALUE, payload: field })
};
}
This is my reducer function where I am handling the part of the items in the form:
if (action.payload.target.name === "items") {
let cloneditems = [...state.form.items];
cloneditems.push(action.payload.target.value);
return {
...state,
form: {
...state.form,
items: cloneditems
}
};
}
What I am planning to do is to add an item object and push it to the items array every time I add an item with its details in my form. Yet, it adds them outside the items array not inside it as an object. Can anyone help me with this part as it consumes a lot of time and I cannot make it? Here is a link to my project if you want to have a look :
https://codesandbox.io/s/hopeful-williamson-nvqx9?file=/src/redux/reducer.js
and here is an example of what I am planning to get :
form : {
user :[{
name: "",
quantity:"",
price:"",
instructions:""
}]
}
Moreover, this is my reducer initial state :
const initialState = {
form: {
pickup_address: {},
delivery_address: {},
items: [{
index: 0,
name: "",
quantity: 0,
price: 0,
special_instructions: ""
}]
},
numOfItems: 0,
};
Any help ?!
It would be great if post CodeSandbox link,
I just posted simple way to add objects to an array, Maybe helpful.
var myArray = ["Red", "Green", "Blue"];
myArray.push("Yellow");
var myObject = {id: 1, name: "Amoos", class: 10};
myArray.push(myObject);
console.log(myArray)
https://codesandbox.io/s/cocky-haze-5p346?file=/src/forms/itemForm.js
Try it now
itemDetails
for (let i = 0; i < numOfItems; i++) {
rows.push(
<ItemForm
index={i}
removeItem={removeItem}
setItemName={setItemName}
setQuantity={setQuantity}
setPrice={setPrice}
setInstructions={setInstructions}
itemName={name}
qty={quantity}
price={price}
special_instructions={special_instructions}
/>
// <div key={i} className="add-items-form">
// <div className="items-header-container">
// <h3 className="items-form-header">ITEM #{i + 1}</h3>
// <Button onClick={() => removeItem(i)}>Remove Item</Button>
// </div>
// <div className="row">
// <FormGroup className="col-md-6">
// <Label>Item Name</Label>
// <Input
// type="text"
// name="name"
// onChange={e => setItemName(e.target.value)}
// value={itemName}
// />
// </FormGroup>
// <FormGroup className="col-md-6">
// <Label>QTY</Label>
// <Input
// type="text"
// name="quantity"
// onChange={e => setQuantity(e.target.value)}
// value={qty}
// />
// </FormGroup>
// </div>
// <div className="row">
// <FormGroup className="col-md-6">
// <Label>Price</Label>
// <Input
// type="text"
// name="price"
// onChange={e => setPrice(e.target.value)}
// value={price}
// />
// </FormGroup>
// <FormGroup className="col-md-6">
// <Label>Special Instructions</Label>
// <Input
// type="text"
// name="special_instructions"
// onChange={e => setInstructions(e.target.value)}
// value={instructions}
// />
// </FormGroup>
// </div>
// </div>
);
}
itemForm.js
import React, { useState } from "react";
import { Button, FormGroup, Input, Label } from "reactstrap";
function ItemForm(props) {
console.log("dssd", props.price);
return (
<div key={props.index} className="add-items-form">
<div className="items-header-container">
<h3 className="items-form-header">ITEM #{props.index + 1}</h3>
<Button onClick={() => props.removeItem(props.index)}>
Remove Item
</Button>
</div>
<div className="row">
<FormGroup className="col-md-6">
<Label>Item Name</Label>
<Input
type="text"
name="name"
onChange={e => props.setItemName(e.target.value)}
value={props.name}
/>
</FormGroup>
<FormGroup className="col-md-6">
<Label>QTY</Label>
<Input
type="text"
name="quantity"
onChange={e => props.setQuantity(e.target.value)}
value={props.quantity}
/>
</FormGroup>
</div>
<div className="row">
<FormGroup className="col-md-6">
<Label>Price</Label>
<Input
type="text"
name="price"
onChange={e => props.setPrice(e.target.value)}
value={props.price}
/>
</FormGroup>
<FormGroup className="col-md-6">
<Label>Special Instructions</Label>
<Input
type="text"
name="special_instructions"
onChange={e => props.setInstructions(e.target.value)}
value={props.instructions}
/>
</FormGroup>
</div>
</div>
);
}
export default ItemForm;
constructor(props) {
super(props);
this.submitQA = this.submitQA.bind(this);
this.onSearchChange = this.onSearchChange.bind(this);
this.isSearched = this.isSearched.bind(this);
this.answerSubmitted = this.answerSubmitted.bind(this);
this.reset = this.reset.bind(this);
this.state = {
answers: [],
answer: '',
searchTerm: '',
}
}
reset() {
console.log("reset");
}
render() {
const answer = true;
return (
<div className="App">
<div className="center">
<form >
Search: <input type="text" onChange={this.onSearchChange} /><br/>
</form>
<form onSubmit={this.submitQA}>
Q & A:
<input type="text" placeholder=" Course/Q/A"/>
<button type="submit"> Submit </button>
</form>
<span>{basicFormat}</span>
</div>
{
this.state.answers.filter(this.isSearched(this.state.searchTerm)).map((item) => {
return (
if(answer) {
this.reset;
}
<div>
<form onSubmit={this.answerSubmitted}>
<text> {item} </text>
<input type="text" placeholder="answer the question"/>
</form>
</div>
)
})
}
</div>
);
}
Why can't I use any logic in this render method? Keeps giving me unexpected token. Do not see anything wrong with it. Looked at some tutorials and they are doing the exact same thing but why is mine throwing me an error?
You've included a Javascript if statement inside the return, mixed with the JSX.
Quoting the React documentation:
if statements and for loops are not expressions in JavaScript, so they can't be used in JSX directly. Instead, you can put these in the surrounding code.
To fix the unexpected token error, move the if statement before the return:
{
this.state.answers.filter(this.isSearched(this.state.searchTerm)).map((item) => {
if(answer) {
this.reset();
}
return (
<div>
<form onSubmit={this.answerSubmitted}>
<text> {item} </text>
<input type="text" placeholder="answer the question"/>
</form>
</div>
)
})
}
I would also recommend that you perform the mapping before the return in the render function. That way, the rendering is more clearly separated from the data manipulation.
render() {
const answer = true;
const answerForms = this.state.answers
.filter(this.isSearched(this.state.searchTerm))
.map((item) => {
if (answer) {
this.reset()
}
return (
<div>
<form onSubmit={this.answerSubmitted}>
<text> {item} </text>
<input type="text" placeholder="answer the question" />
</form>
</div>
)
})
return (
<div className="App">
<div className="center">
<form >
Search: <input type="text" onChange={this.onSearchChange} /><br />
</form>
<form onSubmit={this.submitQA}>
Q & A:
<input type="text" placeholder=" Course/Q/A" />
<button type="submit"> Submit </button>
</form>
<span>{basicFormat}</span>
</div>
{answerForms}
</div>
)
}
I'm pretty new to reactjs, i came across a scenario where i've to create 6 input fields which are very much similar to each other. Right now i've something like this in my render method of class,
render () {
return (
<div>
<p>
<label htmlFor="answer1">Answer:</label><br/>
<input
type="text"
name="answer1"
id="answer1"
className="answer"
value={this.state.answer1}
onChange={this._handleChange}
/>
</p>
<p>
<input
type="text"
name="answer2"
id="answer2"
className="answer"
value={this.state.answer2}
onChange={this._handleChange}
/>
</p>
<p>
<input
type="text"
name="answer3"
id="answer3"
className="answer"
value={this.state.answer3}
onChange={this._handleChange}
/>
</p>
<p>
<input
type="text"
name="answer4"
id="answer4"
className="answer"
value={this.state.answer4}
onChange={this._handleChange}
/>
</p>
<p>
<input
type="text"
name="answer5"
id="answer5"
className="answer"
value={this.state.answer5}
onChange={this._handleChange}
/>
</p>
<p>
<input
type="text"
name="answer6"
id="answer6"
className="answer"
value={this.state.answer6}
onChange={this._handleChange}
/>
</p>
</div>
);
}
The code is ugly and redundant, is there anyway i could do this dynamically?
How about defining an Answer component like this (only showing the render method):
render() {
return (
<p>
<label htmlFor={this.props.name}>Answer:</label>
<input
type="text"
name={this.props.name}
className="answer"
value={this.props.value}
onChange={this.props.handleChange}
/>
</p>
);
}
And then on your parent component you just import it and use it like:
var Answer = require('./answer.js');
//..
render() {
return (
<div>
<Answer name="answer1" value={this.state.answer1} handleChange={this._handleChange} />
<Answer name="answer2" value={this.state.answer2} handleChange={this._handleChange} />
<Answer name="answer3" value={this.state.answer3} handleChange={this._handleChange} />
// add all your Answer components
</div>
);
}
Following Thylossus suggestion, here is an example using map:
var Answer = require('./answer.js');
//...
render() {
// this is supposing you've got an answers array of { name: ..., value: ...} object
var answers = this.state.answers.map(function(a) {
return(<Answer name={a.name} value={a.value} handleChange={this._handleChange} />)
});
return (
<div>
{ answers }
</div>
);
}