I have created a button that saves the entered data, however when I click on it, nothing happens.Here is the code.
class DefinesPagePresenter extends Component {
constructor(props) {
super(props);
this.state = {
isNeedOpenInfoWindow: false,
filesContentDict: {
[props.iniType]: props.json
}
};
}
onChange = () => {
if (this.state.filesContentDict[this.props.iniType]) {
this.props.changeInitFileParams(this.props.market, this.props.iniType, this.state.filesContentDict[this.props.iniType]);
this.setState({ isNeedOpenInfoWindow: true });
}
}
<form onSubmit={(e) => {
e.preventDefault()
this.onChange()
}}>
<div height="200%" style={{
margin: '20px 0px 0px 40px'
}}><input type="submit" value="Ok" className="c4t-button" height="200%" size="50px" /></div>
</form>
The following similar snippet to your code shows that the alert does run when clicking on the <input type='submit' /> without seeing your code there could be other problems or this.state is not what you think it is within that function (improper scoping or just at the time it is false so it doesn't run what is within the if statement).
I suggest you have an else { for the event Handler which you called onChange: so you can see if that's triggered for example it seems like you are waiting for a prop named json= to be filled in and maybe it is not when you try clicking. You might consider disabling the button until this.props.json is there.
onChange = () => {
if (this.state.filesContentDict[this.props.iniType]) {
//also make sure this method is actually running
console.log('about to run: changeInitFileParams')
this.props.changeInitFileParams(this.props.market, this.props.iniType, this.state.filesContentDict[this.props.iniType]);
this.setState({ isNeedOpenInfoWindow: true });
}
else {
alert('JSON Was not yet loaded')
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isNeedOpenInfoWindow: false,
filesContentDict: {
[props.iniType]: props.json
}
};
}
onConfirm = () => {
if (this.state.filesContentDict[this.props.iniType]) {
this.props.alertInputs(JSON.stringify({
statement: this.state.filesContentDict[this.props.iniType].statement,
iniType: this.props.iniType
}, null, 4))
this.setState({
isNeedOpenInfoWindow: true
}, console.log) // should reflect the state immediately after change
}
else {
alert('false')
}
}
render() {
return (
<form
style={{ background: 'green', height: 300 }}
onSubmit={(e) => {
e.preventDefault();
this.onConfirm();
}}
>
<input
type='submit'
value='Ok'
/>
{this.state.isNeedOpenInfoWindow &&
<div style={{
display: 'flex', justifyContent: 'space-between', alignItems: 'center', margin: '6rem' }}>
<div>
iniType:<br />
statement: <br />
</div>
<div>
{this.props.iniType} <br />
{this.state.filesContentDict[this.props.iniType].statement}
</div>
</div>
}
</form>
);
}
}
ReactDOM.render(
<App
iniType='load'
alertInputs={inputs => alert(inputs)}
json={{ statement: 'The quick Brown Fox jumped over the lazy dog!' }}
/>,
window.root
);
<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='root'></div>
I find it a bit strange (but I'm not sure what the exact situation is with your props) that it seems like you send the changeInitFileParams to an outer/parent React Component and then change the state of this child to isNeedOpenInfoWindow it would make more sense to change that state to the parent in most situations if the parent needs the changeInitFileParams to run.
In short nothing is not going to work with any of the code you're actually shown (I proved that it works all the functions get called) and the alert shows up. Whatever is not working is not displayed here: I'd be most suspicious about json={neverBeingDefined} or isNeedOpenInfoWindow being on this Component's state vs on the parent. (Assuming the render(){ method returns that form and some sort window that needs the state: isNeedOpenInfoWindow.
I think you should change your from onSubmit like this
onsubmit={(event)=> onChange(event)}
then use this code on onChange =>
const onChange = (event) => {
e.preventDefault();
if (this.state.filesContentDict[this.props.iniType]) {
this.props.changeInitFileParams(this.props.market, this.props.iniType,
this.state.filesContentDict[this.props.iniType]);
this.setState({ isNeedOpenInfoWindow: true });
}
}
The main reason you getting error because you are not using button. You are using input tag.
Change
<button type="submit" className="c4t-button" height="200%" size="50px">Ok</button>
Related
I have a simple React component that I'm working on creating right now. Basically, the user can input an ID and when they submit, it will display some information that is in a container. The code looks like so
export default class IDContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
Id: '',
isSubmitted: false
};
}
handleSubmit = (event) => {
this.setState({
isSubmitted: true
});
};
handleChange = (event) => {
this.setState({
Id: event.target.value
});
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}
>
<Input type={'text'} placeholder={"Enter Id"} value={this.state.Id} onChange={this.handleChange} />
<Button type={'submit'} > Lookup </Button>
</div>
<div>
{this.state.isSubmitted && <DetailsContainer Id={this.state.Id} />}
</div>
</form>
);
}
}
The details container has already been created and just returns some details about the Id that has been passed in. I can show the details of the first Id that I pass in just fine. However, when I enter in another Id and submit the form, the DetailsContainer is not re-rendering and is still showing the details for the older Id. I tried moving it around and adding some logic (I even put the DetailsContainer in my state to see if I can manipulate it that way), but that doesn't seem to be working. I see that there is a shouldComponentUpdate() method, and that seems to be what I need to use, but the guides I saw all place it inside of the DetailsContainer. Anyway for me to have it in IDContainer, or is there an easier way to re-render the DetailsContainer?
I think part of the issue here is that once isSubmitted is set, every change you make to the input will be applied to this.state.Id and passed into DetailsContainer.
I think you'd be better off having one variable for tracking the input state, and variable one for tracking the Id you want to pass into DetailsContainer.
state = { Id: null, inputId: '' };
handleSubmit = (event) => {
this.setState({
Id: this.state.inputId
});
};
handleChange = (event) => {
this.setState({
inputId: event.target.value
});
};
render() {
return (
...
<Input ... value={this.state.inputId} />
...
{this.state.Id !== null ? <DetailsContainer Id={this.state.Id} /> : null}
);
}
This question already has answers here:
How to disable button in React.js
(8 answers)
Closed 3 years ago.
I am using trying to disable a button in react based on couple states. Down below is a breakdown of my code
constructor(props) {
super(props);
this.state = {
email: '',
pass: '',
disabled: true
}
this.handleChange = this.handleChange.bind(this);
this.handlePass = this.handlePass.bind(this);
}
pretty self explanatory constructor. The disabled will be changed as state changes. My render method looks something like this
render() {
if(this.state.email && this.state.pass) {
this.setState({ disabled: false })
}
return (
<div className='container'>
<div className='top'></div>
<div className='card'>
<MuiThemeProvider>
<Card >
<div className='wrapper'>
<TextField
hintText="Email"
value={this.state.email} onChange={this.handleChange}
/><br/>
<TextField
hintText="Password"
type="password"
/><br/>
<div className='login-btn'>
<RaisedButton label="Login" primary={true}
disabled={this.state.disabled} />
</div>
</div>
</Card>
</MuiThemeProvider>
</div>
</div>
)
}
As you can see I have 2 text fields and I am handeling the data changes with the following method
handleChange(e) {
this.setState({email: e.target.value});
}
handlePass(e) {
this.setState({pass: e.target.value});
}
Now my button is initially disabled and everytime a state is changed and component re-renders I want to check for state changes and enable button accordingly. So I was thinking of using the life cycle method like so
componentWillMount() {
if(this.state.pass && this.state.disabled) {
this.setState({disabled: false})
}
}
However, this doesn't work. When both email and password field is not empty the button stays disabled. I am not sure what am I doing wrong.
Please, do not set states inside render() function. That might cause infinite loops to occur.
Refer: https://github.com/facebook/react/issues/5591
Instead of setting states inside render() function, you can set the disabled state inside the handleChange() and handlePass() function.
If more detail required, please do mention.
You should be setting the disabled state inside your handleChange and handlePass functions.
componentWillMount() only runs right before the component is rendered, but never again.
Just made a demo , is that you need, check the code in the demo below
demo
Change below code :
class App extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
pass: '',
invalidData: true
}
this.onEmailChange = this.onEmailChange.bind(this);
this.onPasswordChange = this.onPasswordChange.bind(this);
}
// componentWillUpdate is to be deprecated
//componentWillUpdate(nextProps, nextState) {
// nextState.invalidData = !(nextState.email && nextState.pass);
//}
onEmailChange(event) {
this.setState({ email: event.target.value });
}
onPasswordChange(event) {
this.setState({ pass: event.target.value });
}
render() {
return (
<form>
<input value={this.state.email} onChange={this.onEmailChange} placeholder="Email" />
<input value={this.state.password} onChange={this.onPasswordChange} placeholder="Password" />
// from this <button disabled={this.state.invalidData}>Submit</button>
//to
<button disabled={!(this.state.email && this.state.password)}>Submit</button>
</form>
);
}
}
**updated **
disable submit button in <button disabled={!(this.state.email && this.state.password)}>Submit</button> itself.
I have small class in react, i want to display the result on the screen after i click on the button, but before the display happens, the page reload.
how do i do it?
what am I missing?
import React, {Component} from 'react';
class InputFieldWithButton extends Component{
constructor(props){
super();
this.state = {
message: ''
};
}
handleChange(e){
this.setState({
message: e.target.value
});
}
doSomething(e){
return(
<h1>{this.state.message}</h1>
)
}
render(){
return (
<div>
<form >
<input type="text" placeholder="enter some text!" value=
{this.state.message}
onChange={this.handleChange.bind(this)}/>
<button onClick={this.doSomething.bind(this)}>Click me</button>
</form>
</div>
)
}
}
export default InputFieldWithButton;
Your button is inside a form and triggering a submit.
You can use the preventDefault() method to stop it from doing so:
doSomething(e) {
e.preventDefault();
return (
<h1>{this.state.message}</h1>
)
}
By the way, your return statement of this click handler makes no sense at the moment.
Edit
As a followup to your comment:
Can you explain me what is my mistake in the return?
Not really a mistake, but it is useless in this context as your are not doing anything with the returned object.
Where and how do you expect to use the <h1>{this.state.message}</h1> that you are returning?
If you intend to show / hide the input message in your screen you could do it with conditional rendering.
Just store a bool like showMessage in your state and render the message only if it's set to true.
Here is a small example:
class InputFieldWithButton extends React.Component {
constructor(props) {
super(props);
this.state = {
message: '',
showMessage: false
};
}
handleChange = (e) => {
this.setState({
message: e.target.value
});
}
toggleMessage = (e) => {
e.preventDefault();
this.setState({ showMessage: !this.state.showMessage })
}
render() {
const { showMessage, message } = this.state;
return (
<div>
<form >
<input
type="text"
placeholder="enter some text!"
value={message}
onChange={this.handleChange}
/>
<button onClick={this.toggleMessage}>Toggle Show Message</button>
{showMessage && <div>{message}</div>}
</form>
</div>
)
}
}
ReactDOM.render(<InputFieldWithButton />, document.getElementById('root'));
<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="root"></div>
By the way, it is considered as bad practice to bind the functions inside the render method, because you are creating a new instance of a function on each render call. instead do it inside the constructor which will run only once:
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
Or you can use arrow functions which will reference this in a lexical context:
handleChange = (e) => {
this.setState({
message: e.target.value
});
}
This is what i've used in my example.
you're not specifying the buttons'type
<button type="button">
Set the type attribute on the button to be button. The default is submit since it is wrapped in a form. So your new button html should look like this:
<button type="button" onClick={this.doSomething.bind(this)}>Click me</button>
I am trying to make a text box auto focus.
However, I the setState is being called too late it seems.
It is being called within Popup.show. I created a button to console.log the state, and it does seem to be set to true but it must happen too late.
How can I get setState to be called as the Popup.show happens?
class Dashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
focused: false,
};
}
onClick = (event) => {
console.log('Says focussed FALSE', this.state.focused)
this.setState({ focused:true });
Popup.show(<div>
<SearchBar
autoFocus
focused={this.state.focused}
/>
<button onClick={this.checkState}>It says TRUE here</button>
</div>,
console.log('Says focussed FALSE still', this.state.focused),
{ animationType: 'slide-up'});
};
checkState = (e) =>{
console.log(this.state)
}
render() {
return (
<div style={{ padding: '0.15rem' }}>
<Button onClick={this.onClick.bind(this)}>Open & Focus</Button>
</div>);
}
}
Always remember that setState won't execute immediately. If you want Popup.show() after setState, you can use a callback:
this.setState({ focused: true }, () => {
Popup.show(...)
})
And you are already using arrow functions, you don't need the .bind(this) in your render function.
setState doesn't immediate set the state
From: https://facebook.github.io/react/docs/react-component.html#setstate
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
Changing your setState to something like
this.setState({ focused: true }, () => {
Popup.show(<div>
<SearchBar
autoFocus
focused={this.state.focused}
/>
<button onClick={this.checkState}>It says TRUE here</button>
</div>)
});
I have a function(onClickAddSection), when its called, it should set the state to empty string but it doesn't do that at all.
Please take a look at the code and tell me what im doing wrong thank you.
class AddNewSectionForm extends Component {
constructor(props) {
super(props);
this.state = {
sectionName: '',
validation:false
};
this.onSectionNameChange = this.onSectionNameChange.bind(this);
this.onClickAddSection = this.onClickAddSection.bind(this);
}
onSectionNameChange(event) {
if(this.state.validation==false){
this.setState({validation:true});
}
this.setState({sectionName: event.target.value});
}
onClickAddSection(event) {
event.preventDefault();
this.props.saveSection(this.state.sectionName);
this.setState({sectionName:'',validation:false});
}
render() {
return (
<div>
<TextInput name="newSection" label="Section Name :"
onChange={this.onSectionNameChange}
value={this.state.sectionName}
error = {this.state.validation==true&& this.state.sectionName.length==0?'Enter Section Name':''}/>
<AddCloseButtons add = {this.onClickAddSection}
close = {this.props.closeCharm}
/>
</div>
);
}
}
the onClickAddSection function doesn't set the sectionName back to ''.
AddCloseButton:
const AddCloseButtons = ({add,close}) => {
return (
<div className="form-group">
<button className="btn btn-primary" style={{width: '40%', border:'solid black 1px'}} onClick={add}>Add</button>
<button className="btn btn-secondary" style={{width: '40%', float: 'right',border:'solid black 1px'}} onClick={close}>Close</button>
</div>);
};
Are you using Redux? if so, this.props.saveSection makes any Ajax Call?. If so, could be that you update the local state with setState and then your Ajax response re updates it the received value?
Just try and see the functional version of setState.
this.setState(function (state, props) {
return {
sectionName:'',
validation:false
}
});
It seems that when you click the button, onSectionNameChange and onClickAddSection happen at the same time and will have conflict (because the name is set to blank means its name is being changed ^^), so how about not setting state for sectionName in onSectionNameChange:
onSectionNameChange(event) {
if(this.state.validation==false){
this.setState({validation:true});
}
//this.setState({sectionName: event.target.value});
}
I guess so, please post here some errors if any, thanks