예제 – Todo 앱 만들어보기

간단한 TODO앱을 작성해보도록하자. ToDo 앱은 MVC 패턴으로 구성할 수 있는 가장 간단한 앱의 형태이다. 이 앱을 만들기 위한 기본적인 스케치는 다음과 같다.

  1. 텍스트를 입력할 수 있는 input 박스와 버튼이 있다. 텍스트에 할일을 입력하고 버튼을 클릭하면 아래쪽으로 새로운 할일이 목록에 추가된다.
  2. 목록의 각각의 할일은 체크 박스를 가지고 있다. 완료한 일은 체크 박스에 체크하여 완료로 표시한다. 완료 상태가 되면 해당 할일은 취소선을 적용하여 표시한다.

[UPDATED] Mithril이 2.0 대로 업그레이드 되면서 일부 수정이 필요해졌다. m.withAttr()은 완전히 제거되는 등 몇가지 브레이킹 체인지가 있다.

Model class

간단하게 타이틀과 완료 여부 정도를 가지고 있는 작은 클래스를 하나 작성한다.

class Task
  (@title) ->
     @done = no

컨트롤러

컨트롤러는 뷰에서 벌어지는 이벤트를 처리하거나, 관련된 데이터를 담는 역할을 수행하면 된다. 여기서 ctrl이 그 역할을 담당하는데, 할일의 목록을 관리하고 현재 입력되는 텍스트와 추가 동작을 수행하면 된다.

ctrl = do
  list: []
  desc: ''
  add: !->
    if @desc.length > 0 
    then new Task @desc |> @list.push
         @desc = ''

다음은 입력을 받는 부분을 만들자. 입력부는 독립된 컴포넌트로 작성한다. 컴포넌트는 view 라는 이름의 메소드를 가지고 있는 객체로, vnode 값을 받아서 가상 DOM을 리턴한다.

comp-inputs = do
  view: (vnode) ->
    m \.inputs,
    * m \input, do
        oninput: !-> ctrl.desc = it.target.value
        value: ctrl.desc
      m \button, do
        onclick: ctrl.add.bind add
      , \Add

목록 구현

다음은 할일 목록의 개별 항목을 렌더링하는 영역이다. 리스트 전체를 만들어도 좋은데, 여기서는 각 항목에 해당하는 li 요소를 생성할 것이다. m(component, arg) 와 같은 식으로 렌더링하게 되는데, 이때 전달된 인자는 기본적으로 vnode.attrs로 참조할 수 있다.

comp-listitem = do
  view: (vnode) ->
    m \li,
    * m 'input[type=checkbox]' do
        onchange: vnode.attrs.done = it.target.checked
        checked: vnode.attrs.done
      m \span, do
        style:
          text-decoration: if vnode.attrs.done then 'line-through' else 'none'
      , vnode.attrs.title

Put Together

이제 마지막으로 조합한다. 입력부 아래에 ul 요소를 만들고 그 아래에 ctrl.list 의각 항목을 렌더링할 요소들을 붙여주면 된다.

app = do
  view: (vnode) ->
    m '#app',
    * m comp-inputs
      m \ul, 
        ctrl.list.map (item) -> m comp-listitem item
m.mount document.body, app

아래에서 동작을 확인해볼 수 있다.

https://codepen.io/stripe-q/pen/eYYwvyY