클론코딩해보기/TodoList

[Todo list] 05. 필터 기능

js0616 2024. 8. 19. 06:06

목록 구현

목록은 총 세가지필드가 존재한다. 할일 / 진행중 / 종료
할일 / 진행중 에 등록된 티켓은 수정 및 삭제가 가능하다.
할일 / 진행중 / 종료 로 서로간에 이동이 가능하다.
각 티켓에는 제목, 내용, 제출 또는 수정날짜가 나타나야 한다.
수정버튼을 눌렀을때 수정모달이 띄워져야 한다.

 

 

이번 글에서 구현할 내용

할일 / 진행중 에 등록된 티켓은 수정 및 삭제가 가능하다.
할일 / 진행중 / 종료 로 서로간에 이동이 가능하다.

      <select name="workState" class="workState">
        <option value="wait">할일</option>
        <option value="going">진행중</option>
        <option value="end">종료</option>
      </select>

 

select-option 를 선택시 해당 값이 반영하기 

    this.addEvent('change', '.workState', e => {
      console.log(e.target.value);
    });

 

이벤트에 'change' 타입으로 값을 가져올 수 있다.  

cf. 'onchange' 는 사용하는 상황이 다름. 

 

// src/components/Item.js
import Component from '../core/Component.js';

export default class Item extends Component {
  template() {
    const { item } = this.props;

    return `
      <div class='title'>제목 : ${item.title} </div>
      <div class='contents'>내용 : ${item.contents} </div>
      <div class='date'>작성시간 : ${item.date} </div>
      <select name="workState" class="workState">
        <option value='wait' ${item.workState === 'wait' ? 'selected' : ''}>할일</option>
        <option value='going' ${item.workState === 'going' ? 'selected' : ''}>진행중</option>
        <option value='end' ${item.workState === 'end' ? 'selected' : ''}>종료</option>
      </select>
      <button class='updateBtn'>수정</button>
      <button>삭제</button>
    `;
  }
  setEvent() {
    const { item, updateItem } = this.props;

    this.addEvent('click', '.updateBtn', () => {
      item.write = true;
      updateItem(item);
    });

    this.addEvent('change', '.workState', e => {
      item.workState = e.target.value;
      updateItem(item);
    });
  }
}

 

option 속성으로 selected 를 사용하면 workState 의 상태에 따라 적용된 option 이 보여진다.


2. 필터 버튼을 만들어서 '전체' , '할일', '진행중' , '종료' 를 필터링해서 보여준다. 

 

// src/components/ItemFilter.js
// 필터 버튼 , 필터 기능

import Component from '../core/Component.js';

export default class ItemFilter extends Component {
  template() {
    return `
        <button>전체</button>
        <button>할일</button>
        <button>진행중</button>
        <button>종료</button>
    `;
  }
  setEvent() {}
}

 

App.js 에서 추가해주면 

 // 자식 컴포넌트가 위치할 dom 요소
  template() {
    return `
    <div data-component="itemAdd"></div>
    <div data-component="itemFilter"></div>
    <div data-component="itemList" class="itemList"></div>
    `;
  }

  // mounted에서 자식 컴포넌트를 마운트
  mounted() {
    const { addItem, currentTime, inputFocus, updateItem } = this;

    const $itemList = this.$target.querySelector('[data-component="itemList"]');
    const $itemAdd = this.$target.querySelector('[data-component="itemAdd"]');
    const $ItemFilter = this.$target.querySelector(
      '[data-component="itemFilter"]',
    );

 

해당 버튼을 클릭할때,

workState 의 값이 버튼에 맞는 값을 가지는 컴포넌트만 보여지도록 한다. 

 

-> 각 버튼에 따라 바뀌는 값을 가지는 state 가 하나 더 필요함  -> App.js 에서 진행

-> 해당 값과 비교하여 컴포넌트가 보여지도록 해야됨. -> ItemList 에서 진행

 

filterVal : 'all'  값을 가지는  state 추가

 

App.js 함수 setFilter 추가하고

ItemFilter 생성시 setFilter  함수를 전달해준다. 

  // 필터 값 변경
  setFilter(NewValue) {
    this.setState({
      filterVal: NewValue,
    });
    console.log('필터 값 확인:', this.state.filterVal);
  }

 

// src/components/ItemFilter.js
// 필터 버튼 , 필터 기능

import Component from '../core/Component.js';

export default class ItemFilter extends Component {
  template() {
    return `
        <button class='filterBtn' value ='all'>전체</button>
        <button class='filterBtn' value ='wait'>할일</button>
        <button class='filterBtn' value ='going'>진행중</button>
        <button class='filterBtn' value ='end'>종료</button>
    `;
  }
  setEvent() {
    const { setFilter } = this.props;

    this.addEvent('click', '.filterBtn', e => {
      setFilter(e.target.value);
    });
  }
}

 

버튼 클릭시 해당 버튼의 value 값을 setFilter 의 인자로 전달하여

filterVal 값을 변경하도록 한다.


 

조건문 추가, 조금 가독성이 떨어질 수 있는데, 

 

1번 조건 : filterVal 가 all 이거나 item.workState 와 같을때, 

2번 조건 : write 가 true 일 경우 -> update(수정) / false 일 경우 -> Item (읽기)

 

// src/components/ItemList.js
import Component from '../core/Component.js';
import Item from './Item.js';
import ItemUpdate from './ItemUpdate.js';

export default class ItemList extends Component {
  template() {
    let ItemDiv = this.props.items.map(item => {
      return `<div data-Item${item.seq} ></div>`;
    });
    return `
      ${ItemDiv.join('')}
    `;
  }
  mounted() {
    const { items, updateItem, currentTime, filterVal } = this.props;

    items.map(item => {
      // workState 적용 - all 이거나 필터값과 같을때,
      filterVal == 'all' || filterVal == item.workState
        ? // write 적용 - true : 수정 , false : 읽기
          item.write
          ? new ItemUpdate(
              this.$target.querySelector(`[data-Item${item.seq}]`),
              {
                item: item,
                updateItem: updateItem,
                currentTime: currentTime,
              },
            )
          : new Item(this.$target.querySelector(`[data-Item${item.seq}]`), {
              item: item,
              updateItem: updateItem,
            })
        : '';
    });
  }
}

 

item 갯수만큼 div 가 생성되고 안에 내용만 필터링 되고있다. 

따라서 ItemList 의 ItemDiv 값도 필터링 해주어야 할듯 하다.

  template() {
    const { items, filterVal } = this.props;
    let ItemDiv = items.map(item => {
      return filterVal == 'all' || filterVal == item.workState
        ? `<div data-Item${item.seq} ></div>`
        : '';
    });

    return `
      ${ItemDiv.join('')}
    `;
  }

 

Item 을 표시하는 부모 div 도 필터링되어 생성되는것을 확인


할일 / 진행중 에 등록된 티켓은 수정 및  삭제가 가능하다.
할일 / 진행중 / 종료 로 서로간에 이동이 가능하다. 

목표인 2가지는 완료했으나 필터가 조금 아쉬우니까 

 

전체(n) / 할일(n) / 진행중(n) / 종료 (n) 를 표시해보겠다. 

전체 state.items 를 돌면서 workState 값을 각각 counting 해야된다. 

전체의 경우 length 로 가능하지만.. 

 

workState 를 카운팅하는 workCount 함수를 생성

  // setWorkCount : workState 의 갯수를 workCount 에 전달
  setWorkCount() {
    let NewCount = { all: 0, wait: 0, going: 0, end: 0 };
    this.state.items.map(item => {
      NewCount['all']++;
      NewCount[item.workState]++;
    });
    this.setState({
      workCount: NewCount,
    });
  }

 

 

해당 함수를 .. 어디서? 언제? 실행 해야될까... 

리액트면.. useEffect 를 사용해서,  state 에 변화가 있을때 하도록 할텐데...

 

그냥 모든 관련 상황에 넣어보면

1. Item 을 입력을 해야 되니까 ItemAdd 에서  Item 추가시

2. select option 을 직접 바꿀 경우

 

 


이제부터는 파일이 너무 많아져서 github로 표기하는게 낫겠다.. 

 

https://github.com/js0616/todoList/tree/main


 

 

필터를 하고나니까.. 음..  정렬도 해보면 어떨까? 

제목순 , 작성시간순..

일단 삭제부터 할까