목록 구현
목록은 총 세가지필드가 존재한다. 할일 / 진행중 / 종료 할일 / 진행중 에 등록된 티켓은 수정 및 삭제가 가능하다. 할일 / 진행중 / 종료 로 서로간에 이동이 가능하다. 각 티켓에는 제목, 내용, 제출 또는 수정날짜가 나타나야 한다. 수정버튼을 눌렀을때 수정모달이 띄워져야 한다.
이번 글에서 구현할 내용
할일 / 진행중 에 등록된 티켓은 수정 및 삭제가 가능하다. 할일 / 진행중 / 종료 로 서로간에 이동이 가능하다.
<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
필터를 하고나니까.. 음.. 정렬도 해보면 어떨까?
제목순 , 작성시간순..
일단 삭제부터 할까