본문 바로가기

Dev.Project/Todolist_project

[TodoMVC] Step 3. To do list Remove Item / list 제거하기


Step 3. To do list에서 Item 제거하기

세번째 단계. 큰 산 하나 넘었다.

실제로 해보면서 늘어난 To do list 목록을 완료, 미완료에 상관없이 일단 삭제부터 해야겠다.

이미 TodoMVC 공식 홈페이지로 부터 HTML 코드를 받았기 때문에 X 버튼이 준비되어 있다.

우리는 event를 걸어 list를 삭제시키자.


1단계 . View.js 파일을 작성한다.

1-1. bind에 event 분기를 추가한다.

view.js code>

1
2
3
4
5
6
7
8
9
10
11
//event: itemRemove
//handler: controller.removeItem
else if(event === 'itemRemove'){
    var todo = self.$todoList;
    todo.addEventListener('click'function(event){
        var target = event.target;
        if(target.className === 'destroy'){
            handler({id:self._getItemId(target.parentNode, 'li')});
        }
    });
}
cs


X 버튼을 클릭했을때, 이벤트를 발생시키기 위해 bind에 해당 이벤트를 추가하자.

template.js 파일에 추가된 html 코드조각을 보면 X 버튼의 요소인 button 의 클래스를 보면 destroy로 되어있다.

click 이벤트가 발생되는 곳이 X button임을 판단하는 것을 className으로 판명하였다.

해당 list만 삭제해야하기 때문에 이벤트가 발생한 list의 id 값을 받아와야 한다.

이를 위해서 view 내부에 private 메소드를 하나 더 생성해야 하는데, 그 메소드가 바로 _getItemId 메소드이다.

이 메소드를 통해서 eventHandler를 발생시켜준다.



1-2. prototype에 _getItemId 메소드를 추가한다.

view.js code>

1
2
3
4
5
6
7
8
//click event가 발생한 list의 id값을 잡아주는 역할
View.prototype._getItemId = function(element, tagName){
    var li;
    if (element.parentNode.tagName.toLowerCase() === tagName.toLowerCase()){
        li = element.parentNode;
    }
    return parseInt(li.dataset.id, 10);//HTML data-id=*에서 *이 id인 값을 10진수로 parsing함
};
cs


_getItemId 메소드로 넘어오는 element를 기준으로 해당 list의 li 태그로 접근해야 하는 과정이다.

tagName 메소드에서 UpperCase 로 return 이 되므로 toLowerCase( ) 메소드를 통해서 일치여부를 파악하자.

li 태그에는 html custom tag가 달려있다.

이 tag로 접근하여 해당 Id 값을 반환해주자.




1-3. render에 viewCommand를 추가한다.

view.js code>

1
2
3
4
//넘겨받은 parameter에 해당하는 list를 화면상에서 지워주는 메소드.
removeItem : function(){
    self._removeItem(parameter);
}
cs


render에 removeItem 이라는 function을 정의하는데,

이는 view prototype에 지정되어 있는 removeItem을 실행시키는 command이다.

controller로부터 ( 정확히는 Storage ) parameter를 넘겨받아 화면에서 삭제된 list를 지우는 역할을 수행하게 된다.



1-4. prototype에 removeItem 메소드를 추가한다.

view.js code>

1
2
3
4
5
6
View.prototype._removeItem = function(id){
    var elem = document.querySelector('[data-id="' + id + '"]');
    if(elem){
        this.$todoList.removeChild(elem);
    }
};
cs


삭제된 list를 id 값을 통해 접근하여 지워준다.

removeChild 메소드를 활용하였다.




2단계 . controller.js 파일을 작성한다.

2-1. 생성자 함수에 bind를 추가해준다.

controller.js code>

1
2
3
this.view.bind('itemRemove'function(item){
    self.removeItem(item.id);
});
cs


새로운 list를 추가할 때와 마찬가지로, 이벤트를 전달받아야 하기 때문에, 생성자 함수에 bind를 정의해준다.



2-2. prototype에 removeItem 메소드를 추가해준다.

controller.js code>

1
2
3
4
5
6
Controller.prototype.removeItem = function(id){
    var self = this;
    self.model.remove(id, function(){
        self.view.render('removeItem', id);
    });
};
cs


controller가 하는 역할은 변하지 않는다.

삭제할 데이터에 대한 정보를 view로부터 얻어와서 model에 전달한다.

그리고 삭제된 결과를 그려야하기 때문에 callback 함수의 구조로 view의 render함수를 넘겨준다.




3단계 . model
.js 파일을 작성한다.

3-1 . prototype에 remove 메소드를 추가해준다.

model.js code>

1
2
3
Model.prototype.remove = function(id, callback){
    this.storage.remove(id, callback);
};
cs


controller로부터, 정확히는 view의 bind 함수로부터 얻은 id 값을 storage로 전달한다.

이 메소드에서도 역시 callback 함수( view의 render 함수 )를 그대로 전달해준다.




4단계 . storage.js 파일을 작성한다.

4-1 . prototype에 remove 메소드를 추가해준다 .

storage.js code>

1
2
3
4
5
6
7
8
9
10
11
12
13
Storage.prototype.remove = function(id, callback){
    var data = JSON.parse(localStorage[this._dbName]);
    var todos = data.todos;
 
    for (var i = 0; i < todos.length; i++) {
        if(todos[i].id == id){
            todos.splice(i, 1);
            break;
        }
    }
    localStorage[this._dbName] = JSON.stringify(data);
    callback.call(this, todos);
};
cs


localStorage에 있는 데이터의 값을 추가하거나 변경해주기 위해서는

자바스크립트가 조작할 수 있는 데이터 형식으로 변환해야 한다.

그렇기에 storage에서 data를 조작하는 과정 전에는

localstorage로부터 값을 꺼내 parsing 하는 과정이 꼭 들어간다.

그리고는 넘어온 data 배열에서 넘겨받은 id 값과 일치하는 list 객체를 찾는다.

우리가 하려는 삭제를 위해, splice 메소드를 사용한다.

>> javascript array splice 메소드 >>

그리고 변경된 data 배열의 값을 다시 localStorage에 저장해준다.

이 과정에서는 위와는 반대로 stringify 메소드를 통해 localstorage에서 저장할 수 있는 값으로 변환시켜준다.




-The End-