I'm using a switch checkbox in render, so one important attribute to detect if it's checked or not is defaultChecked. I set the state previously in the componentWillReceiveProps. I try first putting the state as attribute but I'm getting an error Unexpected token when it compiles the code with babel.js. After I try using dangerouslySetInnerHTML but it's still not working (bottom error).
First try:
<input type="checkbox" name="onoffswitch" {this.state.required} />
App.jsx
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
required: ''
};
};
componentWillReceiveProps( nextProps ){
//more code
this.setState({
required: 'defaultChecked'
});
};
render() {
return(
<div id="section">
<div className="bottom-question">
<div>
<div className="onoffswitch-add pull-left">
<input type="checkbox"
name="onoffswitch"
dangerouslySetInnerHTML={this.state.required} />
<label className="onoffswitch-label-add" htmlFor="switch-required">
<div className="onoffswitch-inner-add"></div>
<div className="onoffswitch-switch-add"></div>
</label>
</div>
</div>
</div>
</div>
)
}
}
Error:
The full text of the error you just encountered is:
input is a void element tag and must neither have `children`
nor use `dangerouslySetInnerHTML`. Check the render method of EditInput
you want to use the checked property to apply a check to the checkbox input in javascript
<input type="checkbox" name="onoffswitch" checked={this.state.required === 'defaultChecked'} />
when you set the state of required to be whatever you want it to be (in this case you are using the string 'defaultChecked') you need to tell the input to check itself or not based on that.
I would recommend you refactor the state variable to be a boolean and call it checked like so
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
checked: false
};
};
componentWillReceiveProps( nextProps ){
//more code
this.setState({
checked: true
});
};
render() {
return(
<div id="section">
<div className="bottom-question">
<div>
<div className="onoffswitch-add pull-left">
<input type="checkbox"
name="onoffswitch"
checked={this.state.checked} />
<label className="onoffswitch-label-add" htmlFor="switch-required">
<div className="onoffswitch-inner-add"></div>
<div className="onoffswitch-switch-add"></div>
</label>
</div>
</div>
</div>
</div>
)
}
}
I think you want <input required={this.state.required} />
React has an attribute for this.
<input type="checkbox" name="onoffswitch" disabled={this.state.required} />
where this.state.required is a boolean
You would want to have a disabled prop for your button that is true when the checkbox is not checked, and false when it is.
To do this, start with a state variable that stores the checkbox's value. Then add a function that is fired on the onChange event which toggles the state from true-> false and vice versa.
The button should then be disabled when the checkbox is unchecked.
class MyApp extends React.Component {
constructor() {
super();
this.state = {
checkboxState: false
};
}
toggleCheckbox = () => {
this.setState({checkboxState: !this.state.checkboxState});
}
render() {
return (
<form>
<input type="checkbox" name="onoffswitch" onChange={this.toggleCheckbox} />
<input type="submit" disabled={!this.state.checkboxState} value="submit" />
</form>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Related
I'm learning reactjs and I have a problem with the validation in forms
so I want to have a condition if the user don't enter his name a message 'empty field' appear
else alert hello 'his name' appears
My code
import React ,{Component} from 'react';
class Formular extends Component {
constructor(props) {
super(props);
this.state={
nom:'',
prenom:'',
email:'',
password:'',
error:false,
NameErr:''
}
}
handleValidation() {
if (this.state.nom =='')
{ this.state.error=true
this.state.NameErr='empty field'
//console.log( this.state.NameErr)
return(
this.state.NameErr
)
}
}
handleClick(event){
event.preventDefault()
let error = this.handleValidation()
if (!error)
{
alert('hello '+ this.state.nom)
}
}
render() {
/* console.log('nom',this.state.nom)
console.log('prenom',this.state.prenom) */
return (
<div >
<div className="form__group field">
<input type="input" className="form__field"
placeholder="Name" name="name" id='name'
required size='100' value={this.state.nom}
onChange={(event)=>this.setState({nom:event.target.value})} />
<label for="name" className="form__label">Name</label>
</div>
<div className='alert'> {this.state.NameErr} </div>
export default Formular
You must not change the state by force
like this
this.state.NameErr='empty field'
this.state.error=true
You need to use setState
like this example
this.setState({NameErr:'empty field',error:true})
then you can in render method
{ this.state.error && <div className='alert'> {this.state.NameErr}</div>}
Thus the element will only be displayed if there is an error
Mutation of state isn't correct, always mutate state using setState()
this.setState({NameErr:'empty field', error: true})
jsx
{this.state.error && <div className='alert'> {this.state.NameErr} </div>}
First, you should wrap your input in form tag instead simply div.
Next use event onSubmit on your form to trigger submission of the form.
Create un method to check if your value is not empty, then do what you want
render () {
return <form onSubmit={handleClick}>
<div className="form__group field">
<input
id='name' name="name" type="text"
className="form__field"
size='100' required
placeholder="Name" value={this.state.nom}
onChange={(event)=>this.setState({nom:event.target.value})}
/>
<label for="name" className="form__label">Name</label>
</div>;
<div className='alert'> {this.state.NameErr} </div>
</form>;
}
NT: type attribute of input should be "text" and not "input"
EDIT: Like said other guys, change also your changing state.
I am trying to take input values from text box and displays every comment in new line.
constructor(props) {
super(props);
this.displayCmnts=this.displayCmnts.bind(this);
this.updateCmnts=this.updateCmnts.bind(this);
this.state={
comments:'',
cmntCount:0,
prevCm:''
}
}
render(){
let c=(this.state.prevCm)
return (
<div className="App">
<h3>enter comments</h3>
<input type="text" id="txt-cmnt" vlaue={this.state.comments} onChange=
{this.updateCmnts} placeholder="enter"/>
<br/>
<button onClick={this.displayCmnts}>submit</button>
<br/>
{c+<br/>}
</div>
);
}
updateCmnts(e){
this.setState({comments:e.target.value});
}
displayCmnts(){
this.setState({cmntCount:1});
this.setState({comments:this.state.comments});
var c=this.state.comments+"\n";
this.setState({prevCm:this.state.prevCm+c});
}
when do this it {c+} outputs my-input-comments [object object]
I believe if you change the code to {c}<br/> it should work
So, I want to create a card component many times I want on a click of a button but the problem is that it just creates the cardComponent one time. What should I do? Is there anyone that I could create these.
This is the code:
class GCARD extends Component {
constructor(props) {
super(props);
// This state changes so the card is generated
this.state = {
change: '',
}
this.handel = this.handel.bind(this);
}
handel = (element) => {
// This is the element which creates the card.
element = <CardComponent data="Give a little detail about the thing's you like!"
heading= "Create Your Own Card" image="./owl.jpg"/>
this.setState({
change: element
});
}
render() {
return (
<div>
<div className="form-div">
<div>
<p className="form-title">Create Your Own Card</p>
<hr/>
</div>
<div>
<label className="form-label">Main Heading </label>
<input className="form-input" type="text"/>
<br/><br/>
<label className="form-label">Some Info</label>
<input className="form-input1" type="text"/>
<br/><br/>
{/* Just focus on the button */}
<button onClick={this.handel} className="form-btn">CREATE</button>
</div>
</div>
<div>
{this.state.change}
</div>
</div>
);
}
}
Your current code only replaces the element. You want to use an array instead e.g. use it like this
this.setState({
change: this.state.change.concat(element)
});
The problem on your code is that you override every time the same component. I changed your code for you to fix this:
class GCARD extends Component {
constructor(props) {
super(props);
// This state changes so the card is generated
this.state = {
change: [],
}
this.handel = this.handel.bind(this);
}
handel = (element) => {
// This is the element which creates the card.
let components = this.state.change;
element = <CardComponent data="Give a little detail about the thing's you like!"
heading="Create Your Own Card" image="./owl.jpg" />
components.push(element);
this.setState({
change: components
});
}
render() {
return (
<div>
<div className="form-div">
<div>
<p className="form-title">Create Your Own Card</p>
<hr />
</div>
<div>
<label className="form-label">Main Heading </label>
<input className="form-input" type="text" />
<br /><br />
<label className="form-label">Some Info</label>
<input className="form-input1" type="text" />
<br /><br />
{/* Just focus on the button */}
<button onClick={this.handel} className="form-btn">CREATE</button>
</div>
</div>
<div>
{this.state.change.map(comp => (comp))}
</div>
</div>
);
}
}
There are many different ways you can approach this. I would recommend binding an onClick handler to your create button which would push an object into an array, which then, in turn, you could use to set the state. Then in your render, map over the state to return each card. Remeber you may need to use appropriate CSS for margins, inline-flex etc.
eg:
clickHander(){
let arr = [];
arr.push({
<card/>
})
this.setState({change: arr})
}
render(){
const card = this.state.change.map((card) => { return ( card )})
return (
<div>
{card}
</div>
)
}
Hope this helps!
I'm writing a page that converts temperature from Celcius to Fahrenheit.
User gives temperature in celcius in the first input field,
then onChange should call function convertCelciustoFahr.
The convertCelciustoFahr changes the state.fahrenheit by function this.setState() and temperature in fahrenheit should update to the second input field.
class App extends Component {
constructor(props){
super(props);
this.state = {
//Temperature in fahrenheit
fahrenheit: 0,
//Temperature in celcius
celcius: 0,
};
//Binding
this.convertCelciustoFahr = this.convertCelciustoFahr.this;
}
//Converts celcius to fahrenheit
convertCelciustoFahr(event){
var celcius = Number(event.target.value);
this.setState( function(state,props){
return{
fahrenheit: (celcius-32)/(5/9),
}
}
)
}
render() {
return (
<div className="App">
<h1>Celcius to Fahrenheit converter</h1>
<form id="conversion">
<input className="Celcius" placeholder="°C" onChange={this.convertCelciustoFahr} />
<p>=</p>
<input className="Fahrenheit" value={this.state.fahrenheit} placeholder="°F" />
</form>
</div>
);
}
}
export default App;
Here is the html:
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root">
<div data-reactroot="" class="App">
<h1>Celcius to Fahrenheit converter</h1>
<form id="conversion">
<input class="Celcius" placeholder="°C">
<p>=</p>
<input class="Fahrenheit" value="0" placeholder="°F">
</form>
</div>
</div>
It seems that Javascript is not enabled and the onChange event is not triggered.
Why onChange not updating value to the fahrenheit input field?
bind using
this.convertCelciustoFahr = this.convertCelciustoFahr.bind(this);
I struggling and a bit lost with react about one thing.
I have a row with 5 columns.
Each columns have a checkbox, an input and a button.
So if you look at it in a standard way, it looks like this:
render() {
return (
<div className="sbm-sources">
<div className="col-md-2 sbm-source">
<input type="checkbox" name="c1"/>Add to source.
<br />
<input type="text" name="i1" size="10" onClick={this.expandInput} placeholder="Enter you query." />
</div>
<div className="col-md-2 sbm-source">
<input type="checkbox" name="c2"/>Add source to blipp.
<br />
<input type="text" name="i2" size="10" onClick={this.expandInput} placeholder="Enter you query." />
</button>
</div>
<div className="col-md-2 sbm-source">
<input type="checkbox" name="c3" />Add source to blipp.
<br />
<input type="text" name="i3" size="10" onClick={this.expandInput} placeholder="Enter you query." />
</button>
</div>
<div className="col-md-2 sbm-source">
<input type="checkbox" name="c4" />Add source to blipp.
<br />
<input type="text" name="i4" size="10" onClick={this.expandInput} placeholder="Enter you query." />
</div>
<div className="col-md-2 sbm-source">
<input type="checkbox" name='c5' />Add source to blipp.
<br />
<input type="text" name="i5" size="10" onClick={this.expandInput} placeholder="Enter you query." />
</div>
</div>
);
}
};
The thing is, each column can be validated separately but I need to know which one is trigger.
I know how to do it using the name of each one, but I am not sure that creating a state for EACH input / checkbox and then check which one is triggered one for then associating the data before sending a POST request is the best option here.
ex:
handleChecked(e){
if (e.value.name === c1){
this.setState({checkedC1: true});
}
...
}
This would quickly become messy and hard to maintain, or to make adaptable.
The thing is, when I want to do my Post request, I would love to receive an int. For example, if the checkbox (and / or) input filled is from the first column, the int received would be 0.
Is there ean elegant way of doing so with react? What would you suggest?
I am too much into my code and my lack of experience make me blind about it.
Many thanks!
You would need to keep the state of all your columns inside the parent component, because from there you send your post request.
create an array of column data, and put the array in state
inside render, use .map() to loop over the array and render a Column for each item in the array
optional: put the column inside a separate (stateless) component.
Your state could be like:
// as part of your constructor
let initialColumns = [
{ checked: false, checkText: "Add to source.", inputPh="Enter your query.", value: ""},
...
{ checked: false, checkText: "Add source to blipp.", inputPh="Enter your query.", value: ""}
];
this.state = { colDataArr: initialColumns }
And in your render do:
render() {
let expandInput = this.expandInput;
<div>
{this.state.colDataArr.map( colItem, index => {
<Column
checked = {colItem.checked}
checkText = {colItem.checkText}
...
expandInput = {(e) => { expandInput(e) }} // <== special here
colID = {index} // and here
})}
</div>
}
Create a (stateless) <Column> component that takes the function expandInput as a prop, alongside the other variable props. Whenever this function is called, you get the event, but also the index of the column (from 0-4).
That way, inside expandInput, you can handle one individual update
expandInput(event, type, index) {
// create copy of column object, to avoid mutating state directly
let origColData = this.state.colDataArr[index]
let newColData = {
checked = origColData.checked,
checktext = origColData.checkText,
...
}
// now, do whatever you need with the event data to update the newColData
if (type == "checkbox") {
let checked = e.target.checked
} else {
...
}
// copy the array and replace the updated one
let newColArr = this.state.colDataArr.slice()
newColArr[index] = newColData
// set the new state
this.setState({ colDataArr : newColArr })
}
UPDATE
And your shiny new stateless component could look something like this:
class Column extends React.Component {
constructor(props) {
super(props)
}
render() {
<div className="col-md-2 sbm-source">
<input type="checkbox"
onClick={(e) => this.props.expandInput(e,"checkbox", this.props.colID)}/>
{this.props.checkText}
<br />
<input type="text" size="10"
onChange={(e) => this.props.expandInput(e,"text", this.props.colID)}
placeholder={this.props.inputPH} />
<button
onClick={(e) => this.props.expandInput(e,"button", this.props.colID)}>
Do something
</button>
</div>
}
}
Slightly easier way to maintain is to store the exact field variable name in the name instead, and do:
handleChecked(e){
this.setState({[e.value.name]: true});
...
}