Leaderboard ads banner

Filter (Bộ Lọc)

Khi người dùng muốn xem danh sách các bug, thay vì hiển thị toàn bộ các record trên DB chúng ta sẽ thêm một chức năng tiện dụng cho phép người dùng có thể lọc kết quả dựa theo tiêu chí như trạng thái bug, thứ tự ưu tiên.
Ở phần này chúng ta sẽ bổ sung thêm tính năng filter kết quả này vào ứng dụng.

Chúng ta sẽ bắt đầu bằng việc triển khai tính năng filter này trên server API.

Bước 8.1: Thêm Filter Cho API

Trong webapp.js chúng ta sẽ cập nhật đoạn code để lấy về danh sách các bug từ database như sau:

...
app.get('/api/bugs', function(req, res) {
  console.log("Query string", req.query);
  var filter = {};
  if (req.query.priority)
    filter.priority = req.query.priority;
  if (req.query.status)
    filter.status = req.query.status;

  db.collection("bugs").find(filter).toArray(function(err, docs) {
    res.json(docs);
  });
});
...

Với đoạn code cập nhật ở trên thì đối với các request gửi tới server để lấy về danh sách các bug mà trong URL có các query parameterprioritystatus thì API sẽ query các record. Ví dụ với request URI như sau:

/api/bugs?priority=P1&status=Open

Thì API sẽ trả về các bug với priorityP1statusopen. Trước khi kiểm tra lại API này thì bạn cần restart Node.js server để thay đổi ở trên có hiệu lực.

So sánh thay đổi trong source code ở bước 8.1 ở đây.

Bước 8.2: Thêm Hardcode Filter

Ở bước này chúng ta sẽ thêm một filter tạm thời được hardcode vào trong BugFilter component. Cập nhật đoạn code trong của component này thành như sau:

...
var BugFilter = React.createClass({
  render: function() {
    console.log("Rendering BugFilter");
    return (
      <button onClick={this.submit}>Lọc Kết Quả</button>
    )
  },
  submit: function(e) {
    this.props.submitHandler({});
  }
});

Ở đoạn code trên chúng ta sẽ thay phần tử <div> bằng một <button> khi component được render. Đồng thời khi người dùng click vào button này thì method submit() mới được thêm vào cho component này sẽ được gọi.

    submit: function (e) {
        this.props.submitHandler({});
    }

Tới đây có thể bạn đang thắc mắc về property submitHandler trong BugFilter trên lấy ở đâu? Property chưa có và chúng ta sẽ thêm property này từ BugList. Mở file BugList.js và tìm tới đoạn code bên trong phương thức render() và sửa lại thành như sau:

...
  render: function() {
    console.log("Rendering bug list, số lượng item:", this.state.bugs.length);
    return (
      <div>
        <h1>Ứng Dụng Bug Tracker</h1>
        <BugFilter submitHandler={this.loadData}/>
        <hr />
        <BugTable bugs={this.state.bugs}/>
        <hr />
        <BugAdd addBug={this.addBug} />
      </div>
    )
  },
...

Ở trên khi sử dụng BugFilter component chúng ta đã truyền vào property submitHandle={this.loadData}. Như vậy thì phương thức loadData() trong BugList sẽ được gọi khi method submitHandler trong BugFilter được gọi.

Tuy nhiên thì trong BugList chưa có phương thức loadData() này và chúng ta sẽ cần phải thêm vào:

   loadData: function(filter) {
      $.ajax('/api/bugs', {data: filter}).done(function(data) {
        this.setState({bugs: data});
      }.bind(this));
      // Cần thêm logic xử lý lỗi nếu triển khai trên môi trường production.
   },

Bạn có thể thấy loadData() gọi AJAX request tới API với query parameter được định nghĩa bởi giá trị của đối số truyền vào cho filter.

Trước khi kết thúc bước này chúng ta sẽ thực hiện một thay đổi nhỏ cho đoạn code nằm bên trong componentDidMount của BugList component để sử dụng phương thức loadData() mới thêm vào như sau:

...
  componentDidMount: function() {
    this.loadData({});
  },
...

Ở trên khi component được mount chúng ta sẽ load dữ liệu ban đầu với một filter là một object {}. Nói cách khách chúng ta sẽ load tất cả các bug có trong database mà không filter.

Bây giờ khi refresh trang trên trình duyệt và bấm vào button thêm vào trong BugFilter bạn sẽ thấy kết quả không thay đổi. Điều này là bởi vì chúng ta đã hardcode giá trị của filter cũng với giá trị là một object {} bên trong phương thức submit() của BugFilter:

...
   submit: function(e) {
     this.props.submitHandler({});
   }
...

Để chắc chắn rằng filter hoạt động bạn cập nhật lại code trên thành như sau:

...
    submit: function(e) {
        this.props.submitHandler({priority: "P1"});
    }
...

Bây giờ khi refresh lại trang và bấm vào button filter bạn sẽ thấy trang chỉ hiển thị các bug với mức độ ưu tiên P1.

So sánh thay đổi trong source code ở bước 8.2 ở đây.

Bước 8.3: Tạo Form Filter

Ở bước trước chúng ta đã thêm filter được hardcode vào ứng dụng. Tuy nhiên chúng ta cần tạo một filter mà người dùng có thể tùy chính các tiêu chí tìm kiếm thay vì hardcode như trên.
Chúng ta sẽ làm điều này bước này.

Đầu tiên chúng ta sẽ cần cập nhật render() trong BugFilter trong đó có thêm hai thẻ HTML <select> qua đó người dùng có thể chọn tiêu chí khi filter như sau:

...
var BugFilter = React.createClass({
  render: function() {
    console.log("Rendering BugFilter");
    return (
      <div>
        <h3>Bộ Lọc</h3>
        Trạng Thái (Status):
        <select onChange={this.onChangeStatus}>
          <option value="">---Chọn---</option>
          <option value="New">New</option>
          <option value="Open">Open</option>
          <option value="Closed">Closed</option>
        </select>
        <br/>
        Ưu Tiên (Priority):
        <select onChange={this.onChangePriority}>
          <option value="">---Chọn---</option>
          <option value="P1">P1</option>
          <option value="P2">P2</option>
          <option value="P3">P3</option>
        </select>
        <br/>
        <button onClick={this.submit}>Áp Dụng</button>
      </div>
    )
  },
...

Ở đây chúng ta có tham chiếu tới hai phương thức onChangeStatus()onChangePriority() của BugFilter. Cả hai phương thức này chưa được định nghĩa trong BugFilter do đó chúng ta cần định nghĩa hai phương thức trên vào BugFilter component như sau:

...
  onChangeStatus: function(e) {
    this.setState({status: e.target.value});
  },
  onChangePriority: function(e) {
    this.setState({priority: e.target.value});
  },
...

Tiếp theo thêm phương thức getInitialState() để thiết lập state mặc định cho component:

  getInitialState: function() {
    return {status: "", priority: ""};
  },

Ở trên chúng ta thiết lập state mặc định cho componet với các giá trị của trường statuspriority là rỗng.

Trong Reactjs khi làm việc với thẻ <select> chúng ta có thể sử dụng thuộc tính value để thực hiện chọn một <option> với giá trị cho trước. Cập nhật hai thẻ mở <select> nằm trong phương thức render() lần lượt thành như sau:

...
    <select value={this.state.status} onChange={this.onChangeStatus}>
...

Và:

...
    <select value={this.state.priority} onChange={this.onChangePriority}>
...

Cuối cùng cập nhật câu lệnh bên trong phương thức submit() của BugFilter component để sử dụng các giá trị người dùng lựa chọn khi filter thay vì sử dụng một filter được harcode:

...
  submit: function(e) {
    this.props.submitHandler({priority: this.state.priority, status: this.state.status});
  }
});

Refresh lại trình duyệt để kiểm tra kết quả, bạn sẽ thấy hai dropdown menu hiển thị để giúp chọn tiêu chí dùng filter danh sách bug hiển thị. Sau khi chọn xong tiêu chí filter bạn nhấp vào button để lấy dữ liệu từ server, lúc này bạn sẽ thấy trình duyệt chỉ hiển thị các bug đã được filter.

So sánh thay đổi trong source code ở bước 8.3 ở đây.

Nội dung không được để trống

Hướng Dẫn Liên Quan