TODO với React + Rails Part 6: Bổ sung chức năng Done task
Bài đăng này đã không được cập nhật trong 5 năm
Trong những bài trước, chúng ta đã hoàn thành về chức năng: add, list, delete, ... Hôm nay, mình sẽ tiếp tục làm demo ToDo App với chức năng Done. Những Task nào mà user đã làm xong, người dùng có thể click button Done để đánh dấu là đã làm xong. Kết quả sau khi làm xong sẽ như sau:
Phần API
Đầu tiên chúng ta sẽ bắt đầu làm API trước, sau đó sẽ làm phần ReactJs.
Trong table tasks, chúng ta phải thêm trường mới : completed :boolean
rails generate migration add_column_completed_to_task
class AddColumnToTasks < ActiveRecord::Migration[5.2]
def change
add_column :tasks, :completed, :boolean, default: false
end
end
Trong tasks_controller, chúng ta sẽ dùng chung với API update task với params truyền lên completed: true/false.
def update
task = Task.find params[:id]
task.update_attributes! task_params
render json: {
success: true,
data: Api::V1::TaskSerializer.new(task)
}
end
...
private
def task_params
params.permit [:title, :completed]
end
API update task sẽ như sau:
URL: {url}/api/v1/tasks/:id
Method: "PUT"
Params:
title: :string
completed: :boolean
Phần ReactJs
Sửa lại component ToDoItem
Trong src/ToDoItem.js
, chúng ta sẽ bổ sung thêm điều kiện khi render.
- Với điều kiện chưa completed, sẽ thêm button "Done".
- Với điều kiện completed, sẽ thêm dấu gạch ngang vào title, và thay button Done bằng "Completed".
vào file src/ToDoItem.js
, chúng ta sẽ sửa code như sau
import React, { Component } from 'react';
import { Button } from 'reactstrap';
class ToDoItem extends Component {
renderData() {
let task = this.props.task;
if (task.completed) {
return(
<tr>
<td style={{textDecoration: "line-through"}}>
{task.title}
</td>
<td><Button color="danger" onClick={this.props.onDelete}>Delete</Button></td>
<td>Completed</td>
</tr>
)
} else {
return(
<tr>
<td>{task.title}</td>
<td><Button color="danger" onClick={this.props.onDelete}>Delete</Button></td>
<td><Button color="success" onClick={this.props.onDone}>Done</Button></td>
</tr>
)
}
}
render() {
return (
<React.Fragment>
{this.renderData()}
</React.Fragment>
)
}
}
export default ToDoItem
Ở code trên, chúng ta đã thấy có props mới là props onDone
. Props này sẽ là method gọi lên server để update task thành completed.
Vào file src/ToDoList.js
, trong hàm renderItem()
, chúng ta sẽ bổ sung props OnDone
này
renderItem() {
const items = this.state.items.map((task) =>
<ToDoItem
key={task.id}
task={task}
onDelete={() => this.onDelete(task.id)}
onDone={() => this.onUpdate({id: task.id, completed: true})}
/>
)
return items;
}
Props onDone sẽ là hàm onUpdate()
có params: id và completed: true.
onUpdate(params) {
let id = params.id;
fetch(`{url}/api/v1/tasks/${id}`, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then(res => res.json())
.then((response) => {
if(response.success) {
// trường hợp update success, sẽ tạo data mới chứa task mới update đó.
// sau đó update lại state
let updatedData = this.state.items.map(item => {
if(item.id === id) {
return {...response.data}
}
return item;
});
this.setState({
items: updatedData,
})
} else {
alert("Cannot delete");
}
})
.catch(error => {
console.log(error);
})
}
Với hàm onUpdate() này, nó cũng sẽ là hàm dùng chung để update attributes khác cho task.
Đến đây chúng ta đã làm xong chức năng Done cho bài demo này rồi.
All rights reserved