Reputation: 1132
I am creating my blog
where an user
can able to edit
his/her blogs.
Here I am popping the data into a modal to make this edit
..
So after all debugging and a better thinking I have figure this out . This is my updated working code for modal
Thank you for your time.
//blog.js
class Blogs extends Component{
constructor(props) {
super(props);
this.state = {
modal: false,
justClicked: null,
activePage: 1,
requiredItem : null,
_id: '',
blog_short_desc:'',
blog_name: '',
blog_desc: '',
blog_image_link: '',
blog_by: '',
blog_by_author: ''
};
this.handleOpenDialog = this.handleOpenDialog.bind(this);
this.handleCloseDialog = this.handleCloseDialog.bind(this);
this.replaceModalItem = this.replaceModalItem.bind(this);
this.onTodoChange = this.onTodoChange.bind(this);
}
static propTypes = {
getBlog: PropTypes.func.isRequired,
deleteBlog: PropTypes.func.isRequired,
updateBlog: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
loading: PropTypes.object.isRequired
}
toggle = (id) => {
this.setState({
modal: !this.state.modal
});
}
componentDidMount() {
this.props.getBlog();
}
replaceModalItem(id, blog_short_desc, blog_name , blog_desc, blog_image_link, blog_by, blog_by_author) {
this.setState({
modal: true,
requiredItem: id,
_id: id,
blog_short_desc: blog_short_desc,
blog_name: blog_name,
blog_desc: blog_desc,
blog_image_link: blog_image_link,
blog_by: blog_by,
blog_by_author: blog_by_author
});
}
onTodoChange = (e) => {
this.setState({
[e.target.name] : e.target.value
});
}
onSubmit = (e, id) => {
e.preventDefault();
const updatedBlog = {
blog_short_desc: this.state.blog_short_desc,
blog_name: this.state.blog_name,
blog_desc: this.state.blog_desc,
blog_image_link: this.state.blog_image_link,
blog_by: this.props.auth["user"]._id,
blog_by_author: this.props.auth["user"].name
}
//update blog via updateblog action
this.props.updateBlog(id, updatedBlog);
alert("Blog updated successfully!");
e.target.reset();
this.toggle();
window.location.reload();
}
handleOpenDialog(id) {
this.setState({
openDialog: true,
OpenEditDialog: true,
justClicked: id
});
}
handleCloseDialog() {
this.setState({
openDialog: false
});
}
onDeleteBlogClick = (id) => {
this.props.deleteBlog(id);
};
handlePageChange(pageNumber) {
this.setState({activePage: pageNumber});
}
render(){
const { blogs, loading} = this.props.resume;
const { user, isAuthenticated } = this.props.auth;
const itemsPerPage = 6;
let activeBlogs = blogs.slice (itemsPerPage * this.state.activePage - itemsPerPage, itemsPerPage * this.state.activePage);
return(
<Container>
{loading ? (
<div><Loading/></div>
) : (
<div>
{/* blog modal */}
<BlogModal />
{/* card dialog */}
<BlogData blogs={blogs} user={this.props.auth} handleCloseDialog={this.handleCloseDialog} {...this.state} toggle={this.toggle}/>
{/* edit card dialog */}
<EditBlog onTodoChange={this.onTodoChange} {...this.state} toggle={this.toggle} onSubmit={this.onSubmit}/>
<Grid style={{padding: 0}} className="blog-grid">
{activeBlogs.map((item, i) => (
<Cell key={item._id} data-id={item._id} className="blog-grid-cell">
<Card shadow={5} className="cards-grid">
{item.blog_image_link ?
(<CardTitle style={{color: '#fff', height: '200px',
width: 'auto', backgroundImage: `url(${item.blog_image_link})`, backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat'}}></CardTitle>) :
(<CardTitle className="card-title-image"></CardTitle>
)
}
<CardText>
<b>{item.blog_short_desc}</b>
</CardText>
<CardActions border>
<p className="block-data-details">
<Button className="blog-read-me-button col-4" onClick={this.handleOpenDialog.bind(this, item._id)}>Read </Button>
{ isAuthenticated === true && (item.blog_by === user._id) ?
<span className="col=8">
<Button className="remove-btn-blog-post"
color="danger"
size="sm"
onClick= {this.onDeleteBlogClick.bind(this, item._id)} title="Delete Blog">
×
</Button>
<a className="btn edit-btn-blog-post" href="#"
onClick={this.replaceModalItem.bind(this, item._id, item.blog_short_desc, item.blog_name, item.blog_desc, item.blog_image_link, item.blog_by, item.blog_by_author )} title="Edit Blog">
<i className="fa fa-pencil" aria-hidden="true"></i>
</a>
</span> : null }
</p>
<p style={{ fontWeight:'bold'}}>By-{item.blog_by_author} <span style={{float:'right',}}>{Moment(item.date).format('Do MMMM YYYY')}</span></p>
</CardActions>
</Card>
</Cell>
))}
</Grid>
</div>
)}
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={6}
totalItemsCount={blogs.length}
pageRangeDisplayed={5}
onChange={this.handlePageChange.bind(this)}
itemClass='page-item'
linkClass='page-link'
/>
</Container>
)
}
}
const mapStateToProps = (state) => ({
resume: state.resume,
auth: state.auth,
loading: state.apiCallsInProgress > 0
});
export default connect(mapStateToProps, {getBlog, deleteBlog, updateBlog }) (Blogs);
//Edit.js
const EditBlog = ({ toggle, onTodoChange, onSubmit, ...state}) => {
return(
<span>
<Modal
isOpen = {state.modal && state.requiredItem === state._id}
toggle = {()=>this.toggle(state._id)}
>
<ModalHeader toggle={toggle} style={{fontWeight: "bold"}}>
Edit your blog {state.blog_name}
</ModalHeader>
<ModalBody>
<Form onSubmit={e => onSubmit(e, state._id )}>
<FormGroup>
<Label for="blogHeading">Blog Heading</Label>
<Input type="text" name="blog_short_desc" id="blogHeading" placeholder="Update one liner"
onChange={onTodoChange} defaultValue={state.blog_short_desc}/>
<Label for="blogName">Blog Name</Label>
<Input type="text" name="blog_name" id="blogName" placeholder="Update blog name"
onChange={onTodoChange} defaultValue={state.blog_name}/>
<Label for="desc1">Description </Label>
<Input type="textarea" name="blog_desc" id="desc1" placeholder="Update your blog"
onChange={onTodoChange} defaultValue={state.blog_desc}/>
<Label for="imageUrl">Image Url</Label>
<Input type="text" name="blog_image_link" id="imageUrl" placeholder="Update image url (Optional)"
onChange={onTodoChange} defaultValue={state.blog_image_link}/>
<Button
color="dark"
style={{marginTop: '2rem'}}
block
>Edit blog</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</span>
)
}
const mapStateToProps = state => ({
resume: state.resume,
auth: state.auth
})
export default connect(mapStateToProps, { updateBlog })(EditBlog);
//CurrentUI of working edit
Upvotes: 3
Views: 1361
Reputation: 4446
First, the uneditable bug is caused by using "value" props for your input in modal inside of "defaultValue". If you use value, you are always giving it the value of initial props. Use default value. Using defaultValue makes it a controlled component. Read more on Stackoverflow here. Change that and see next issues if any.
Second, ensure you avoid UNSAFE_componentWillReceiveProps(). Looking at your componentWillRecieveProps method, what is said in the documentation may be at play:
"Calling this.setState() generally doesn’t trigger UNSAFE_componentWillReceiveProps()."
Update:
Remove the componentWillReceiveProps method. submit should work. And ensure user is authenticated.
Upvotes: 2
Reputation: 1132
I have figure it out with
OnClick
of edit
button I passed all required data along with it.
So, my replaceModalItem()
binds all data together in setState()
In replaceModalItem
i called those data and set it to setState()
.
In Edit.js
I have called all the state
values.
Hence getting all the required values in input field setting it with defaultValue
Upvotes: 1
Reputation: 876
When a user is editing their blog, take their blog information and create an object like this
userBlogData={
blog_heading: 'users blog heading',
blog_name: 'users blog name',
description: 'users blog description',
image_url: 'users blog image url',
}
Update the modal form based on these objects. For example:
<input name="blog_heading" value={blog_heading} ... />
After the user have edited the object you can make an update request on your server and call the get function at the same time for updating the blogs. You can keep the update function on the edit component. But the get function will be passed as a props.
Hope This Helps
This should give you the idea...........................
// Edit Component
this.state = {
blog_name:this.props.data.blog_name
}
onBlogUpdate = () => {
let payload = this.state
API CALL...
}
...
render(){
return(
<input value={this.state.blog_name} name='blog_name' onChange={...} ... />
)
}
Upvotes: 1
Reputation: 2237
It looks to me like your onTodoChange
function is setting state on the parent Blogs
component, but that state doesn't make it back to the input values. Instead, the parent passes a blogs
prop into EditBlogs
, and since onTodoChange
never affects blogs
, the input's value
remains unchanged.
This means your inputs' onChange
event values (e.target.value
) never make it back to the inputs' value
attribute, so the input doesn't actually change values.
Since the blog_
values in state
and onTodoChange
are all local to the edit form, I recommend moving those down to that level.. Blogs
doesn't need to know about that stuff, and it'll simplify things - onTodoChange
will set event values into state
, which will flow right back into the inputs as values.
Your blogs
prop should only set the initial state
.
Upvotes: 1