Create price range fields (min and max) using reactJS - javascript

after spending a lot time I need help here.
I am creating a template. Where I can use different form fields. Everything is working. I am getting value form all fields as expected.
But problem is when I have 2 input fields together in one component and pass this component to parent component and get the value. then save this value in object.
I hope its clear enough. Thank you in advance
class Parent extends Component {
handlePriceMinMax(event) {
console.log(event.target.value);
/* I cant set the right values here.
* These values get overwritten with latest value.
* Because I get value on keypress/onChange value */
this.setState({
priceRange: {
min: event.target.value,
max: event.target.value
}
}
);
}
render() {
return (
<Child onChange={this.handlePriceMinMax}/>
)
}
}
class Child extends Component {
render() {
return (
<div className="form-group">
<label>Price</label>
<input type="number" onChange={this.props.onChange}/>
<input type="number" onChange={this.props.onChange}/>
</div>
);
}
}
export default Child;

https://codesandbox.io/s/zr30923nrm
I think this should work.
So basically you need to tell to the handlePriceMinMax what value do you want to update.
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { priceRange: { min: 0, max: 0 } };
}
handlePriceMinMax = (value, event) => {
const priceRange = this.state.priceRange;
priceRange[value] = event.target.value;
this.setState({ priceRange });
};
render() {
return <Child onChange={this.handlePriceMinMax} />;
}
}
class Child extends React.Component {
render() {
return (
<div className="form-group">
<label>Price</label>
<input type="number" onChange={this.minChange} />
<input type="number" onChange={this.maxChange} />
</div>
);
}
minChange = e => {
this.props.onChange("min", e);
};
maxChange = e => {
this.props.onChange("max", e);
};
}

I changed my code, you can create function in child first that get target value and pass to props function
class Child extends Component {
submitInput(e) {
this.props.onChange(e)
}
render() {
return (
<div className="form-group">
<label>Price</label>
<input type="number" onChange={(e) => this.submitInput(e)}/>
<input type="number" onChange={(e) => this.submitInput(e)}/>
</div>
);
}
}
export default Child;

Related

React - How can I make a component from a function inside a parent component?

New to React - I have a component AddForm that looks like this:
class AddForm extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
};
}
handleInput = event => {
this.setState({ name: event.target.value });
};
logValue = () => {
console.log(this.state.name)
return <Display text={this.state.name} />
};
render() {
return (
<div>
<input onChange={this.handleInput}
placeholder="Type Here" type="text" />
<button onClick={this.logValue}
type="submit">Submit</button>
</div>
)
}
}
And when the user clicks on the "Submit" button I want it to display what was in the form. I stored the value in form in this.state.name and my component for displaying the text inside of the form looks like this:
class Display extends React.Component {
render() {
return (
<h1>{this.props.text}</h1>
)
}
}
I know that I the state.name can access the form because I console.logged it. I just want to know why my return statement in the logValue function in the AddForm component isn't creating a new component, Display, and how can I make it work?
The click of the button should result in a state change that the render method then uses to return the Display component - something like:
logValue = () => {
this.setState({ showingName: !this.state.showingName });
}
render() {
return (
<div>
{
this.state.showingName ? <Display text={this.state.name} /> : null
}
<input onChange={this.handleInput}
placeholder="Type Here" type="text" />
<button onClick={this.logValue}
type="submit">Submit</button>
</div>
)
}

How to add values of dyanamically added fields

I've tried to add new fields here, each time button '+' is clicked it adds field input. It is working fine but the problem I've stuck upon is I want to add the value of those input fields. As I am new to react I am not finding a way to achieve it. Is it possible to achieve this.
class InputFields extends React.Component{
render(){
return (
<div>
<input name={`value[${this.props.index + 1}]`} onChange={this.onChangeValue} />
</div>
);
}
}
class Main extends React.Component{
constructor(props){
super(props);
this.values = props.value;
this.state={
inputs:[],
values:[]
};
this.addInputs = this.addInputs.bind(this);
}
addInputs() {
const inputs = this.state.inputs.concat(InputFields);
this.setState({ inputs });
}
onChangeValue(e){
var value = e.target.value;
this.value =value;
this.addValues();
}
addValues(){
...
}
render () {
const inputs = this.state.inputs.map((Element, index) => {
return <Element key={ index } index={ index } />
});
return <div>
<div>
<input name={`value[${this.props.index}]`} onChange={this.onChangeValue} />
</div>
<div>
<button className="btn btn-sm btn-primary" onClick={this.addInputs}>+</button>
</div>
</div>
}
}
ReactDOM.render(
<Main />,
document.getElementById('calculator')
);
It't not required to manage two different variables to manage it, you can loop it through the array and can change the value on onChange event
import React from "react";
export default class Example extends React.Component {
state = {
values: [null]
};
add() {
this.setState(prevState => prevState.values.push(null));
}
changeVal(val, index) {
this.setState(prevState => (prevState.values[index] = parseFloat(val)));
}
getSum() {
let sum = 0;
for (let i = 0; i < this.state.values.length; i++) {
if (this.state.values[i] !== null) {
sum += this.state.values[i];
}
}
return sum;
}
render() {
return (
<div>
{this.state.values.map((val, index) => (
<div key={index}>
<input
onChange={e => this.changeVal(e.target.value, index)}
type="number"
value={val}
placeholder="Enter a value"
/>
</div>
))}
<hr />
Sum is {this.getSum()}
<hr />
<button onClick={this.add.bind(this)}> +Add</button>
</div>
);
}
}
Edit
Added the method getSum() and converting the number to float in changeVal() method
Codesandbox link - https://codesandbox.io/s/235o6xoxyr
In react, the view is a function of data: UI = fn(data)
This means that you'll write a component tree that can transform data to view.
And only manipulate data, unlike what you might be familiar with in jQuery for example.
In practice, this would mean:
let a component Input handle the rendering of one input:
const Input = ({value, onChange}) =>
<input value={value} onChange={event => event.target.value} />
in your state, only save the list of input values as strings. React will take care of transforming each value to an Input component later on
this.state = {inputs: []}
write a function responsible of adding new inputs, to the state and not the view
addInput = () => {
this.setState({
inputs: this.state.inputs.concat('')
})
}
create a method that takes care of changing the value of one input in the list
changeValue = (i, newValue) => {
this.setState({
inputs: [
...this.state.inputs.slice(0, i),
newValue,
...this.state.inputs.slice(i+1)]
})
}
in the render method of Main, loop over your list of inputs and transform to a list of Input components
this.state.inputs.map(
(input, i) =>
<Input
key={i}
value={input}
onChange={newValue => this.changeValue(i, newValue)}
/>
)

Why does the value in event.target not equal event.target.value

I am learning react, and noticed when changing an input of type number and outputting event.target I see a different value then that when I output event.target.value.
I am wondering why this is?
Some sample code to show what I am talking about:
class Child extends React.Component {
render() {
return (
<input type="number"
value={this.props.weight}
onChange={(event) => this.props.onWeightChange(event, this.props.index)}
step="0.1" />
);
}
}
class Parent extends React.Component {
state = {
text: 'Goals',
weight: 1
}
handleStatWeightChange = (event, index) => {
console.log(event.target)
console.log(event.target.value)
}
render() {
return (
<div>
<Child weight={this.state.weight} onWeightChange={this.handleStatWeightChange}/>
</div>
);
}
}
React.render(<Parent />, document.getElementById('app'));
When changing the input value (from 1.1 from 1) I see the following output in the console:
"<input type='number' value='1' step='0.1' data-reactid='.0.0'>"
"1.1"
why is the value in event.target still 1?
You are not setting event.target.value to weight in handleStatWeightChange event handler function
Try with below change it would work
handleStatWeightChange = (event, index) => {
this.setState({
weight: event.target.value
})
console.log(event.target)
console.log(event.target.value)
}

React, having trouble getting event.key from onKeyPress input event

I'm having trouble getting event.key from input onKeyPress event, getting this error when i type in the input field - TypeError: Cannot read property 'key' of undefined
The plan is to update parent state when enter is pressed in child input component.
class ToDoList extends Component {
constructor(props) {
super(props);
this.handleKeyPress = this.handleKeyPress.bind(this);
this.state = {
todoArr: [],
};
}
handleKeyPress(e){
console.log(e.key);
}
render(){
return(
<div className="wrapper">
<p className = "title">todos</p>
<InputField testProp={this.handleKeyPress}></InputField>
<div className = "filter-wrap">
<ItemsLeft></ItemsLeft>
<Filter></Filter>
<ClearCompleted></ClearCompleted>
</div>
</div>
)
}
}
class InputField extends Component {
render(){
return(
<input type="text" className="input-field" onKeyPress = {()=> this.props.testProp()}/>
)
}
}
You break the code in the children by doing () => this.props.testProp() if you want this way you should have pass the args like this (e) => this.props.testProp(e)
This is how I would have make it
class ToDoList extends Component {
constructor(props) {
super(props);
this.handleKeyPress = this.handleKeyPress.bind(this);
this.state = {
todoArr: []
};
}
handleKeyPress(e) {
console.log(e.key);
}
render() {
return (
<div className="wrapper">
<p className="title">todos</p>
<InputField testProp={this.handleKeyPress} />
</div>
);
}
}
class InputField extends Component {
render() {
return (
<input
type="text"
className="input-field"
onKeyPress={this.props.testProp}
/>
);
}
}
You can test it here :) https://codesandbox.io/s/6n2jp8yzy3
If you want to see the console you have a button bottom left for open it.
By doing this the callback receive all the args provide by the input, so you don't need to write it by your own.

How to stop re-rendering all Childs in React render function when I change just one child value?

I have some Card (more than 10 Card component) in a Cards component and each Card has a form with more than 10 textField components. When I'm typing in textFields, It has delay between type and update value of textField. After spending more than 2 days, I found my problem. I think it's related to re-rendering all Childs (all Card components) when I set my value in statein value update... .
I want to know where am I wrong? If my codes is standard, is there any way to stop re-rendering all Childs after changing state for just one textField?
My codes are like as follow:
MainComponent:
export default class MainComponent extends Component {
constructor(props) {
super(props);
this.state = {
value : {}
};
}
static PropTypes = {
results: PropTypes.array.isRequired
};
handleChange(ref, e) {
this.state.value[ref] = e;
this.setState(this.state);
}
render() {
const { results } = this.props;
<Cards>
{
results.map((result, index) => {
var ref_taxtfield1 = result.id + "taxtfield1";
var ref_taxtfield2 = result.id + "taxtfield2";
var ref_taxtfield3 = result.id + "taxtfield3";
var ref_taxtfield4 = result.id + "taxtfield4";
var ref_taxtfield5 = result.id + "taxtfield5";
return <Card key={ result.id } style={ styles.card }>
<Form>
<div style={ styles.innerContainer }>
<Textfield
name="taxtfield1"
label="My Label 1"
ref={ref_taxtfield1}
onValueChange={this.handleChange.bind(this, ref_taxtfield1)}
value={this.state.value[ref_taxtfield1]}
/>
<Textfield
name="taxtfield2"
label="My Label 2"
ref={ref_taxtfield2}
onValueChange={this.handleChange.bind(this, ref_taxtfield2)}
value={this.state.value[ref_taxtfield2]}
/>
<Textfield
name="taxtfield3"
label="My Label 3"
ref={ref_taxtfield3}
onValueChange={this.handleChange.bind(this, ref_taxtfield3)}
value={this.state.value[ref_taxtfield3]}
/>
<Textfield
name="taxtfield4"
label="My Label 4"
ref={ref_taxtfield4}
onValueChange={this.handleChange.bind(this, ref_taxtfield4)}
value={this.state.value[ref_taxtfield4]}
/>
<Textfield
name="taxtfield5"
label="My Label 5"
ref={ref_taxtfield5}
onValueChange={this.handleChange.bind(this, ref_taxtfield5)}
value={this.state.value[ref_taxtfield5]}
/>
</div>
</Form>
</Card>})}
</Cards>
}
}
My TextField Component
export default class Textfield extends Input {
static defaultProps = {
initialCount: 0,
value: "",
defaultValue: "",
onValueChange: null,
label: ""
};
state = { focused: false };
onChange = this.onChange.bind(this);
onChange(e) {
if(this.props.onValueChange){
this.props.onValueChange(e.target.value);
}
}
handleOnBlur = this.handleOnBlur.bind(this);
handleOnBlur(e){
this.setState({focused: false});
if(this.props.onBlur){
this.props.onBlur(e);
}
}
render() {
const { focused } = this.state;
const { value, disabled } = this.props;
return (
<div>
<label>{this.props.label}</label>
<input
{ ...this.inputProps() }
type="text"
placeholder={this.props.placeholder}
defaultValue={this.props.defaultValue}
onChange={this.onChange}
onBlur={this.handleOnBlur}
value={ isCurrency ? formatData.currency(value) : value}
disabled={disabled}
/>
</div>
)
}
}
My Card and Cards Component
export class Cards extends Component {
render() {
const { children, ...props } = this.props;
return <div {...props} >{ children }</div>;
}
};
export class Card extends Component {
render() {
const { ...props } = this.props;
return <div {...props} } />
}
}
I use ES6 syntax and also remove all style tags from my code to simplify.
You are passing a new function to every Textfield component on render:
onValueChange={this.handleChange.bind(this, ref_taxtfield1)}
.bind returns a new function every time, causing every Textfield to render on each update.
Two possible solutions:
Don't use .bind inside .render. .bind the method once in the constructor and let Textfield pass an identifier to this.props.onValueChange.
Implement shouldComponentUpdate in Textfield, returning false if only this.props.onValueChange changed.

Categories

Resources