randal
randal

Reputation: 1372

Disable button based onChange value in React

How can i tell onChange to set the disable button to true on the update button, if this.state.title is less than 3 characters, i made an attempt but it wont let me enter a value. It breaks the code pretty much. I want the update to be passed to redux.

here is what i have, disclaimer some code has been removed to be more relevant.

PostItem.js

import React, { Component } from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import Editable from './Editable';
import {connect} from 'react-redux';
import {UpdatePost} from '../actions/';
const Styles = {
    myPaper: {
        margin: '20px 0px',
        padding: '20px'
    },
    button:{
        marginRight:'30px'
    }
}


class PostItem extends Component{

    constructor(props){
        super(props);

        this.state = {
            disabled: false,
        }
    }


    onUpdate = (id, title) => () => {
        // we need the id so expres knows what post to update, and the title being that only editing the title. 
        if(this.props.myTitle !== null){
            const creds = {
                id, title
            }
            this.props.UpdatePost(creds); 
        }

    }
    render(){
        const {title, id, removePost, createdAt, post_content, username, editForm, isEditing, editChange, myTitle, postUpdate} = this.props
        return(
            <div>
                   <Typography variant="h6" component="h3">
                   {/* if else teneray operator */}
                   {isEditing ? (
                    //  need a way to disable update button if the value is less than 3 characters 
                       <Editable editField={myTitle ? myTitle : title} editChange={editChange}/>
                   ): (
                       <div>
                           {title}
                       </div>    
                   )}         
                   </Typography>
                   <Typography component="p">
                       {post_content}
                       <h5>
                           by: {username}</h5>
                       <Typography color="textSecondary">{moment(createdAt).calendar()}</Typography>
                   </Typography>
                   {!isEditing ? (
                       <Button variant="outlined" type="submit" onClick={editForm(id)}>
                           Edit
                       </Button>
                   ):(

                       // pass id, and myTitle which as we remember myTitle is the new value when updating the title
                    //  how would i set disabled to false if the value from editField is less than 3 charaters.
                        <Button 
                            disabled={this.state.title.length > 3 }
                            variant="outlined" 
                            onClick={this.onUpdate(id, myTitle)}>
                            Update
                        </Button>
                   )}
                   <Button
                       style={{marginLeft: '0.7%'}}
                       variant="outlined"
                       color="primary"
                       type="submit"
                       onClick={removePost(id)}>
                       Remove
                   </Button>
           </div>
       )

    }

}

const mapStateToProps = (state) => ({
    disabled: state.post.disabled
})


const mapDispatchToProps = (dispatch) => ({
    // pass creds which can be called anything, but i just call it credentials but it should be called something more 
    // specific.
    UpdatePost: (creds) => dispatch(UpdatePost(creds)),
    // Pass id to the DeletePost functions.
});
export default connect(mapStateToProps, mapDispatchToProps)(PostItem);

editChange is being called from this onChange method

PostList.js

import React, { Component } from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import {connect} from 'react-redux';
import {DeletePost, UpdatePost,EditChange, DisableButton} from '../actions/';
import PostItem from './PostItem';
const Styles = {
    myPaper: {
        margin: '20px 0px',
        padding: '20px'
    }
}
class PostList extends Component{
    constructor(props){
        super(props);
        this.state ={
            title: ''
        }
    }
    // Return a new function. Otherwise the DeletePost action will be dispatch each
     // time the Component rerenders.
    removePost = (id) => () => {
        this.props.DeletePost(id);
    }
    onChange = (e) => {
        e.preventDefault();
        this.setState({
            title: e.target.value
        })


    }


    formEditing = (id) => ()=> {;

        this.props.EditChange(id);
    }

    render(){
        const {posts} = this.props;
        return (
            <div>
                {posts.map((post, i) => (
                    <Paper key={post.id} style={Styles.myPaper}>
                    {/* {...post} prevents us from writing all of the properties out */}
                        <PostItem
                             myTitle={this.state.title} 
                             editChange={this.onChange} 
                             editForm={this.formEditing} 
                             isEditing={this.props.isEditingId === post.id} 
                             removePost={this.removePost} 
                             {...post} 
                        />
                    </Paper>
                ))}
            </div>
        )
    }
}

const mapStateToProps = (state) => ({
    // disabled: state.post.disabled,
    isEditingId: state.post.isEditingId
})
const mapDispatchToProps = (dispatch) => ({
    // pass creds which can be called anything, but i just call it credentials but it should be called something more 
    // specific.
    EditChange: (id) => dispatch(EditChange(id)),
    UpdatePost: (creds) => dispatch(UpdatePost(creds)),
    // Pass id to the DeletePost functions.
    DeletePost: (id) => dispatch(DeletePost(id))
});
export default connect(mapStateToProps, mapDispatchToProps)(PostList);

Action for this.props.DisableButton

export const DisableButton = () => {
    return(dispatch) => {
        dispatch({type:DISABLED});
    }
}

Posts reducer for disable button, etc.

import { DISABLED} from '../actions/';

const initialState = {,
    disabled: false,
    isEditingId:null
}

export default (state = initialState, action) => {
    switch (action.type) {

        case DISABLED:
            return({
                ...state,
                disabled:true
            })

        default:
            return state
    }
}

editable component

import React from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';

const Editable = (props) => (
    <div>
        <TextField
            id="outlined-name"
            label="Title"
            style={{width: 560}}
            name="title"
            value={props.editField}
            onChange={props.editChange}
            margin="normal"
            required
            variant="outlined"/>

    </div>
)

export default Editable; 

Upvotes: 0

Views: 118

Answers (1)

mfakhrusy
mfakhrusy

Reputation: 1208

You don't need to call DisableButton method to disable its value.

Fix your onChange, perhaps roughly like this:

onChange = (e) => {
  this.setState({ title: e.target.value });
}

yes, this is sufficient.

now you can use a logic to disable the Button component, like this:

<Button
  disabled={this.state.title.length <= 3}
  // rest of the attributes
/>

You don't need to use disabled props on redux. It's not necessary since you can just move the logic by using local state of title directly on Button component.

==== edit

you need to initialize this.state.title first

constructor(props) {
  super(props);

  this.state = {
    title: '',
  }

}

=== edit 2nd time after the questioner added some details

If this.state.title is on PostList (the parent component) component and your Button is accessing it through myTitle props since it's on PostItem component. You can do it like this:

<Button
  disabled={this.props.myTitle.length <= 3}
  // rest of the attributes
/>

Upvotes: 1

Related Questions