0

I'm unable to input a value on the input field when selecting edit, i think it could be a onChange issue.

I look at something similar here, but the code seems to be outdated, and im using controlled components and not refs.

enter image description here

enter image description here

Editable.js this component renders an input field when edit is clicked

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.onChange}
            margin="normal"
            variant="outlined"/>

    </div>
)

export default Editable; 

PostList.js renders a list of the post items

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} from '../actions/';
import Editable from './Editable';
const Styles = {
    myPaper: {
        margin: '20px 0px',
        padding: '20px'
    }
}
class PostList extends Component{
    constructor(props){
        super(props);
        this.state ={
        }
    }
    // 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();
        // maybe their is issue with it calling title from name in the editable 
        // component
        this.setState({
            [e.target.title]: e.target.value
        })
    }
    render(){
        const {posts, editForm, isEditing} = this.props;
        return (
            <div>
                {posts.map((post, i) => (
                    <Paper key={i} style={Styles.myPaper}>
                        <Typography variant="h6" component="h3">
                        {/* if else teneray operator */}
                        {isEditing ? (
                             <Editable editField={post.title} onChange={this.onChange}/>
                        ): (
                            <div>
                                {post.title}
                            </div>    
                        )}         
                        </Typography>
                        <Typography component="p">
                            {post.post_content}
                            <h5>
                                by: {post.username}</h5>
                            <Typography color="textSecondary">{moment(post.createdAt).calendar()}</Typography>
                        </Typography>
                        {!isEditing ? (
                            <Button variant="outlined" type="submit" onClick={editForm}>
                                Edit
                            </Button>
                        ):(
                            <Button variant="outlined" type="submit" onClick={editForm}>
                                Update
                            </Button>
                        )}
                        <Button
                            variant="outlined"
                            color="primary"
                            type="submit"
                            onClick={this.removePost(post.id)}>
                            Remove
                        </Button>
                    </Paper>
                ))}
            </div>
        )
    }
}
const mapDispatchToProps = (dispatch) => ({
    // Pass id to the DeletePost functions.
    DeletePost: (id) => dispatch(DeletePost(id))
});
export default connect(null, mapDispatchToProps)(PostList);

Posts.js

import React, { Component } from 'react';
import PostList from './PostList';
import {connect} from 'react-redux';
import { withRouter, Redirect} from 'react-router-dom';
import {GetPosts} from '../actions/';
const Styles = {
    myPaper:{
      margin: '20px 0px',
      padding:'20px'
    }
    , 
    wrapper:{
      padding:'0px 60px'
    }
}
class Posts extends Component {
  state = {
    posts: [],
    loading: true,
    isEditing: false, 
  }
  async componentWillMount(){
    await this.props.GetPosts();
    this.setState({ loading: false })
    const reduxPosts = this.props.myPosts;
    const ourPosts = reduxPosts  
    console.log(reduxPosts); // shows posts line 35
  }

  formEditing = () => {

    if(this.state.isEditing){
      this.setState({
        isEditing: false
      });
    }

    else{
      this.setState({
        isEditing:true
      })
    }
  }


  render() {
    const {loading} = this.state;
    const { myPosts} = this.props
    if (!this.props.isAuthenticated) {
      return (<Redirect to='/signIn' />);
    }
    if(loading){
      return "loading..."
    }
    return (
      <div className="App" style={Styles.wrapper}>
        <h1> Posts </h1>
        <PostList  isEditing={this.state.isEditing} editForm={this.formEditing} posts={myPosts}/>
      </div>
    );
  }
}
const mapStateToProps = (state) => ({
  isAuthenticated: state.user.isAuthenticated,
  myPosts: state.post.posts
})
const mapDispatchToProps = (dispatch, state) => ({
  GetPosts: () => dispatch( GetPosts())
});
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(Posts));
randal
  • 1,272
  • 3
  • 23
  • 48
  • 1
    You're setting the value for your input from `props.title` but your `onChange` is affecting your state. That disconnect means you will not be able to change the value of that input, since you can't edit a components own props. Consider where the source of truth is for your `posts`, add that to state, and then your `onChange` should edit that in the state. – larz Apr 15 '19 at 19:34
  • in layman terms please, im sorry. – randal Apr 15 '19 at 19:35
  • You're setting the value of your input from a different place than where you are trying to edit it. – larz Apr 15 '19 at 19:36
  • what should i do though ? – randal Apr 15 '19 at 19:39

2 Answers2

1

You're setting the value of the input with the property this.props.posts[index].title but you're handling the change through the PostLists state.

You should either delegate the onChange function to the component that's passing the list to your PostList component or store and update the list through the PostLists state.

Rafael Sousa
  • 691
  • 5
  • 8
  • i just updated the code, what do you think i should do now ? – randal Apr 15 '19 at 19:50
  • `Posts` owns the list so it should pass `onChange` function to the `PostList` function: ` ` and in the `PostList` component: `` As a general rule, the component who keeps the value/list should be the one that handle any changes relating to the data. – Rafael Sousa Apr 15 '19 at 20:17
  • thanks, even though i really don't understand. I will figure this out. thanks for your time though. – randal Apr 15 '19 at 20:19
1

you need to pass the value being set in change function

onChange = (e) => {
    e.preventDefault();
    // maybe their is issue with it calling title from name in the editable 
    // component
    this.setState({
        [e.target.title]: e.target.value
    })
}

youre setting the state of your edit field. You have to reference that value again when you reference your Editable.

<Editable editField={this.state.[here should be whatever e.target.title was for editable change event] } onChange={this.onChange}/>

in your editable component your setting the value to the prop editField.

 <TextField
            id="outlined-name"
            label="Title"
            style={{width: 560}}
            name="title"
            **value={props.editField}**
            onChange={props.onChange}
            margin="normal"
            variant="outlined"/>

hope that helps

zach
  • 72
  • 4
  • This is pretty much the same code, this doesn't really help it just confuses me ever more. Thank you for your feedback, however im still confused on what to do. – randal Apr 15 '19 at 20:00
  • you just need to pass the value you want to display back to value – zach Apr 15 '19 at 20:02
  • i would need {post.title} though. Not state. thats the thing – randal Apr 15 '19 at 20:03
  • the value you're passing back to TextField will be from your state. Your setting the value you want to pass back in your onChange call. – zach Apr 15 '19 at 20:04
  • How would i keep the {post.title} in tac. I want to be able to make it editable you know what i mean. – randal Apr 15 '19 at 20:05
  • Then have a post.title and a post.editTitle initially set editTitle to title – zach Apr 15 '19 at 20:13