Todo 앱 : 예제 – Mithril [updated for 1.0]

mithril 관련 글

  1. mithril 앱의 기본 구성 및 m()
  2. m.render – 가상 DOM 렌더링하기
  3. m.mountmithril을 이용한 양방향 바인딩 & 템플릿 렌더링
  4. m.prop 양방향 바인딩을 위한 데이터 래퍼
  5. m.withAttr 양방향 바인딩을 위한 이벤트 매퍼
  6. m.componentmithril 앱을 컴포넌트화하기
  7. * Todo
  8. m.route – 단일페이지 애플리케이션 및 라우팅 규칙
  9. m.request – 서버 API와 통신하기

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

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

<Updated> Mithril 1.0이 발표되면서, 현재 포스트를 작성하던 시점에서 API의 많은 부분이 변경되었다. 이 글은 Mitrhil 1.0을 기준으로 다시 쓰여졌으며, 글 말미에 실행 가능한 CodePen을 붙였으니 체크해보시라.

Model class

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

controller

컨트롤러는 할일 객체의 리스트를 관리하며, UI 상의 텍스트 필드와 추가 버튼등에 바인딩되는 값을 관리한다. m.prop을 사용하지 않는 단순 프로퍼티로 정의된다. 하지만 모든 변경은 UI의 이벤트를 통해서 촉발될 것이며, mithril은 이러한 이벤트 처리시 자동으로 리드로우 사이클을 관리하기 때문에  m.prop ‘더이상 필요없게’되어서 빠진 것이다.

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

다음은 입력을 받는 부분을 만들자. 입력부는 텍스트 필드 하나와 버튼으로 구성된다. 텍스트 필드의 값이 변하면 컨트롤러의 desc 속성의 값이 변경되고, 버튼은 컨트롤러의 add를 호출한다.

comp-inputs = do
  m \.inputs,
  * m \input, do
      oninput: m.with-attr \value !-> ctrl.desc = it
      value: ctrl.desc
    m \button, do
      onclick: ctrl.add
    , \Add

다음은 할일 목록의 개별 항목을 렌더링하는 영역이다. 개별 항목을 렌더링하기 위해서는 m.component()가 아니라 그냥 m() 을 사용할 것이다. 이 때 각 항이 사용할 할일 아이템을 인자로 전달한다. view() 함수는 전달된 인자를 기본적으로 vnode.attrs로 받는다. 만약 인자에 특정한 이름을 지정해주면 vnode.attrs.<key>로 액세스하게 된다.

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

Put Together

이제 마지막으로 입력단과 리스팅단을 조합해서 앱을 만들면 된다.

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

m.mount document.body, app

See the Pen Minimal Todo with Mithril 1.0 by Stripe_Q (@stripe-q) on CodePen.0