2016-06-20 4 views
1

나는 React (내가 Angular와 함께 작업하는 데 익숙하다.)에 익숙하며 카테고리 선택에 따라 Todo 목록을 필터링하는 작업을 현재하고있다.React Js의 Todo 목록 필터링하기

http://todomvc.com/examples/react/#/에서 Todo 목록 응용 프로그램을 복제했습니다. '카테고리'입력을 추가했는데 목록이 표시되면 카테고리별로 필터링하려고합니다.

현재 카테고리에 대한 검색 기능이 없으며 시작할 위치에 대한 안내를 찾고 있습니다. https://github.com/aenser/todo-react

var app = app || {}; 

(function() { 
    'use strict'; 

    app.ALL_TODOS = 'all'; 
    app.ACTIVE_TODOS = 'active'; 
    app.COMPLETED_TODOS = 'completed'; 
    var TodoFooter = app.TodoFooter; 
    var TodoItem = app.TodoItem; 

    var ENTER_KEY = 13; 

    var TodoApp = React.createClass({ 
     getInitialState: function() { 
      return { 
       nowShowing: app.ALL_TODOS, 
       editing: null, 
       newTodo: '', 
       newCategory: '' 
      }; 
     }, 

     componentDidMount: function() { 
      var setState = this.setState; 
      var router = Router({ 
       '/': setState.bind(this, {nowShowing: app.ALL_TODOS}), 
       '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}), 
       '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS}) 
      }); 
      router.init('/'); 
     }, 

     handleChange: function (event) { 
      this.setState({newTodo: event.target.value}); 
     }, 

     handleCategoryChange: function (event) { 
      this.setState({newCategory: event.target.value}); 
     }, 

     handleNewTodoKeyDown: function (event) { 
      if (event.keyCode !== ENTER_KEY) { 
       return; 
      } 

      event.preventDefault(); 

      var val = this.state.newTodo.trim(); 
      var cat = this.state.newCategory.trim(); 

      if (val, cat) { 
       this.props.model.addTodo(val, cat); 
       this.setState({newTodo: '', newCategory: ''}); 
      } 
     }, 

     toggleAll: function (event) { 
      var checked = event.target.checked; 
      this.props.model.toggleAll(checked); 
     }, 

     toggle: function (todoToToggle) { 
      this.props.model.toggle(todoToToggle); 
     }, 

     destroy: function (todo) { 
      this.props.model.destroy(todo); 
     }, 

     edit: function (todo) { 
      this.setState({editing: todo.id}); 
     }, 

     save: function (todoToSave, text, cat) { 
      this.props.model.save(todoToSave, text, cat); 
      this.setState({editing: null}); 
     }, 

     cancel: function() { 
      this.setState({editing: null}); 
     }, 

     clearCompleted: function() { 
      this.props.model.clearCompleted(); 
     }, 

     render: function() { 
      var footer; 
      var main; 
      var todos = this.props.model.todos; 

      var shownTodos = todos.filter(function (todo) { 
       switch (this.state.nowShowing) { 
       case app.ACTIVE_TODOS: 
        return !todo.completed; 
       case app.COMPLETED_TODOS: 
        return todo.completed; 
       default: 
        return true; 
       } 
      }, this); 

      var todoItems = shownTodos.map(function (todo) { 
       return (
        <TodoItem 
         key={todo.id} 
         todo={todo} 
         onToggle={this.toggle.bind(this, todo)} 
         onDestroy={this.destroy.bind(this, todo)} 
         onEdit={this.edit.bind(this, todo)} 
         editing={this.state.editing === todo.id} 
         onSave={this.save.bind(this, todo)} 
         onCancel={this.cancel} 
        /> 
       ); 
      }, this); 

      var activeTodoCount = todos.reduce(function (accum, todo) { 
       return todo.completed ? accum : accum + 1; 
      }, 0); 

      var completedCount = todos.length - activeTodoCount; 

      if (activeTodoCount || completedCount) { 
       footer = 
        <TodoFooter 
         count={activeTodoCount} 
         completedCount={completedCount} 
         nowShowing={this.state.nowShowing} 
         onClearCompleted={this.clearCompleted} 
        />; 
      } 

      if (todos.length) { 
       main = (
        <section className="main"> 
         <input 
          className="toggle-all" 
          type="checkbox" 
          onChange={this.toggleAll} 
          checked={activeTodoCount === 0} 
         /> 
         <ul className="todo-list"> 
          {todoItems} 
         </ul> 
        </section> 
       ); 
      } 

      return (
       <div> 
        <header className="header"> 
         <h1>todos</h1> 
         <form onKeyDown={this.handleNewTodoKeyDown}> 
          <input 
           placeholder="What needs to be done?" 
           value={this.state.newTodo} 
           autoFocus={true} 
           className="new-todo" 
           onChange={this.handleChange} 
          /> 
         <select value={this.state.newCategory} className="new-todo" 
         onChange={this.handleCategoryChange}> 
          <option value="">Select a Category</option> 
          <option value="Urgent">Urgent</option> 
          <option value="Soon">Soon</option> 
          <option value="Anytime">Anytime</option> 
         </select> 

         </form> 
        </header> 
        {main} 
        {footer} 
       </div> 
      ); 
     } 
    }); 

    var model = new app.TodoModel('react-todos'); 

    function render() { 
     React.render(
      <TodoApp model={model}/>, 
      document.getElementsByClassName('todoapp')[0] 
     ); 
    } 

    model.subscribe(render); 
    render(); 
})(); 

todoModel.js에게

var app = app || {}; 

(function() { 
    'use strict'; 

    var Utils = app.Utils; 
    // Generic "model" object. You can use whatever 
    // framework you want. For this application it 
    // may not even be worth separating this logic 
    // out, but we do this to demonstrate one way to 
    // separate out parts of your application. 
    app.TodoModel = function (key) { 
     this.key = key; 
     this.todos = Utils.store(key); 
     this.onChanges = []; 
    }; 

    app.TodoModel.prototype.subscribe = function (onChange) { 
     this.onChanges.push(onChange); 
    }; 

    app.TodoModel.prototype.inform = function() { 
     Utils.store(this.key, this.todos); 
     this.onChanges.forEach(function (cb) { cb(); }); 
    }; 

    app.TodoModel.prototype.addTodo = function (title, category) { 
     this.todos = this.todos.concat({ 
      id: Utils.uuid(), 
      title: title, 
      category: category, 
      completed: false 
     }); 

     this.inform(); 
    }; 

    app.TodoModel.prototype.toggleAll = function (checked) { 
     // Note: it's usually better to use immutable data structures since they're 
     // easier to reason about and React works very well with them. That's why 
     // we use map() and filter() everywhere instead of mutating the array or 
     // todo items themselves. 
     this.todos = this.todos.map(function (todo) { 
      return Utils.extend({}, todo, {completed: checked}); 
     }); 

     this.inform(); 
    }; 

    app.TodoModel.prototype.filterAll = function() { 
     this.todos = this.todos.map(function (todo) { 
      return Utils.extend({}, todo); 
     }); 

     this.inform(); 
    }; 

    app.TodoModel.prototype.toggle = function (todoToToggle) { 
     this.todos = this.todos.map(function (todo) { 
      return todo !== todoToToggle ? 
       todo : 
       Utils.extend({}, todo, {completed: !todo.completed}); 
     }); 

     this.inform(); 
    }; 

    app.TodoModel.prototype.destroy = function (todo) { 
     this.todos = this.todos.filter(function (candidate) { 
      return candidate !== todo; 
     }); 

     this.inform(); 
    }; 

    app.TodoModel.prototype.save = function (todoToSave, text, cat) { 
     this.todos = this.todos.map(function (todo) { 
      return todo !== todoToSave ? todo : Utils.extend({}, todo, {title: text}, {category: cat}); 
     }); 

     this.inform(); 
    }; 

    app.TodoModel.prototype.clearCompleted = function() { 
     this.todos = this.todos.filter(function (todo) { 
      return !todo.completed; 
     }); 

     this.inform(); 
    }; 

})(); 
을 app.jsx : 나는 당신이 그것을 복제 할 경우 내 REPO에 대한 링크는 여기에 아래의 코드를 게시하지만 것

todoItem.jsx

var app = app || {}; 

(function() { 
    'use strict'; 

    var ESCAPE_KEY = 27; 
    var ENTER_KEY = 13; 

    app.TodoItem = React.createClass({ 
     handleSubmit: function (event) { 
      var val = this.state.editText.trim(); 
      var cat = this.state.editCategoryText.trim(); 
      if (val || cat) { 
       this.props.onSave(val, cat); 
       this.setState({editText: this.props.todo.title, editCategoryText: this.props.todo.category}); 
      } else { 
       this.props.onDestroy(); 
      } 
     }, 

     handleEdit: function (event) { 
      this.props.onEdit(); 
      this.setState({editText: this.props.todo.title, editCategoryText: this.props.todo.category}); 
     }, 

     handleKeyDown: function (event) { 
      if (event.which === ESCAPE_KEY) { 
       this.setState({editText: this.props.todo.title}); 
       this.props.onCancel(event); 
      } else if (event.which === ENTER_KEY) { 
       this.handleSubmit(event); 
      } 
     }, 

     handleChange: function (event) { 
      if (this.props.editing) { 
       this.setState({editText: event.target.value}); 
      } 
     }, 

     handleCategoryChange: function (event) { 
      if (this.props.editing) { 
       this.setState({editCategoryText: event.target.value}); 
      } 
     }, 

     getInitialState: function() { 
      return {editText: this.props.todo.title, editCategoryText: this.props.todo.category}; 
     }, 

     /** 
     * This is a completely optional performance enhancement that you can 
     * implement on any React component. If you were to delete this method 
     * the app would still work correctly (and still be very performant!), we 
     * just use it as an example of how little code it takes to get an order 
     * of magnitude performance improvement. 
     */ 
     shouldComponentUpdate: function (nextProps, nextState) { 
      return (
       nextProps.todo !== this.props.todo || 
       nextProps.editing !== this.props.editing || 
       nextState.editText !== this.state.editText || 
       nextState.editCategoryText !== this.state.editCategoryText 
      ); 
     }, 

     /** 
     * Safely manipulate the DOM after updating the state when invoking 
     * `this.props.onEdit()` in the `handleEdit` method above. 
     * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate 
     * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate 
     */ 
     componentDidUpdate: function (prevProps) { 
      if (!prevProps.editing && this.props.editing) { 
       var node = React.findDOMNode(this.refs.editField); 
       node.focus(); 
       node.setSelectionRange(node.value.length, node.value.length); 
      } 
     }, 

     render: function() { 
      return (
       <li className={classNames({ 
        completed: this.props.todo.completed, 
        editing: this.props.editing 
       })}> 
        <div className="view"> 
         <input 
          className="toggle" 
          type="checkbox" 
          checked={this.props.todo.completed} 
          onChange={this.props.onToggle} 
         /> 
         <label onDoubleClick={this.handleEdit}> 
          {this.props.todo.title} 
         </label> 
         <label onDoubleClick={this.handleEdit}> 
          {this.props.todo.category} 
         </label> 
         <button className="destroy" onClick={this.props.onDestroy} /> 
        </div> 
         <input 
          ref="editField" 
          value={this.state.editText} 
          className="edit" 
          onChange={this.handleChange} 
          onKeyDown={this.handleKeyDown} 
         /> 
         <select value={this.state.EditCategoryText} className="edit" onChange={this.handleCategoryChange} defaultValue={this.props.todo.category} onKeyDown={this.handleKeyDown}> 
          <option value="Urgent">Urgent</option> 
          <option value="Soon">Soon</option> 
          <option value="Anytime">Anytime</option> 
         </select> 
       </li> 
      ); 
     } 
    }); 
})(); 

카테고리 선택을 기준으로 검색 범위를 필터링하는 방법을 알려 주신 데 감사드립니다.

+0

귀하의 Repo는 비공개입니다. – dpwrussell

답변

1

todos와 필터링에 카테고리를 할당하는 데 동일한 입력 선택을 사용하는 것처럼 인터페이스가 약간 혼란 스럽습니다. 답변의 마지막 부분에서 알아볼 것이지만 지금은 방금 카테고리를 사용했습니다. 선택기는 데이터를 입력하고 카테고리별로 필터링합니다.

귀하의 질문에 대한 답변은 매우 간단합니다. 완성 된 상태뿐만 아니라 범주별로 필터링하면됩니다. 이와 같이 :

  var shownTodos = todos.filter(function(todo) { 
       return(todo.category === this.state.newCategory); 
      }, this).filter(function (todo) { 
        switch (this.state.nowShowing) { 
        case app.ACTIVE_TODOS: 
          return !todo.completed; 
        case app.COMPLETED_TODOS: 
          return todo.completed; 
        default: 
          return true; 
        } 
      }, this); 

나는 현재 범주화 된 디스플레이의 하단에 더 많은 버튼을 추가 할 것입니다. nowShowingCategory과 같은 카테고리에 대해 nowShowing과 같은 상태 세트를 새로 추가 할 수도 있습니다. 버튼은이 값을 범주의 3 가지 값으로 설정합니다. 예제에서 newCategory 대신 위의 필터에서 해당 변수를 사용합니다.

관련 문제