m.withAttr – 이벤트 핸들러 처리 – Mithril

m.withAttr() 함소는 가상노드로 만들어지는 DOM 요소에 이벤트 핸들러를 손쉽게 추가해주는 편의함수이다. 예를 들어 input 필드에 텍스트를 입력할 때 항상 소문자로만 입력을 받고 싶다고 하자. 그러면 oninput 이벤트 핸들러를 통해서 입력된 값을 소문자로 변환해서 어딘가에 저장하고, 이 값을 value 속성을 통해서 표시할 수 있다. 대략 다음과 같은 식으로 구현해볼 수 있을 것이다.

# javascript
let state = {desc: ''}

let test = {
  view: function() { 
    return m('input', {
      oninput: function (e) { state.desc = e.target.value.toLowerCase(); },
      value: state.desc
    });
  }
};

m.mount(document.body, test);

이벤트 핸들러는 이벤트 객체가 넘어가게되고 특정한 필드 값을 참조하기 위해서는 event.target.property 와 같은 식으로 접근해야하기 때문에 조금 번거롭다. m.withAttr() 함수는 이벤트가 발생한 요소의 속성 이름과 핸들러 함수(그 속성값을 받아서 처리하는)를 조합하여 이벤트 핸들러로 등록한다. 따라서 보다 범용적으로 만들어진 프로세스 함수를 간단하게 이벤트 핸들러로 편입할 수 있는 장점이 있다.  만약, m.withAttr() 함수를 사용한다면 위 코드는 아래와 같이 정리될 수 있다.

 

# JS
let state = {
  desc: '',
  setDesc: function(value){ state.desc = value.toLowerCase(); }
};

let test = {
  view: function() {
    return m('input', {
        oninput: m.withAttr('value', state.setDesc),
        value: state.desc
    });
  }
};

m.mount(document.body, test);

## LS equivalent
state = { desc: '' , set-desc: (v) !-> state.desc = v.to-lower-case! }
test = 
  view: -> m \input do
    oninput: m.with-attr \value state.set-desc
    value: state.desc

m.withAttr()의 장점은 주어진 속성을 읽어들이는 객체가 이벤트가 발생한 객체가 아닌, 이벤트핸들러가 바인드되는 객체라는 점이다. 다음과 같은 예를 살펴보자.

state = {desc: '...!'}
test = 
  view: -> 
    m 'div[href="/foo"]' do
      onclick: (e) !-> state.desc = e.target.href
    , m \span state.desc

m.mount document.body, test

위 앱에서 “…!”를 클릭하면 이는 span 요소를 클릭했기 때문에 e.target 은 span 요소를 가리키며, 이 요소의 href 속성은 undefined가 되기 때문에 텍스트가 사라진다. 이벤트 핸들러는 div 객체에 달려 있고, span 객체에서 발생한 이벤트가 전파되면서 div 객체에서 처리했기 때문에 발생하는 불일치이다. (이를 해결하려면 e.target이 아닌 e.currentTarget을 써야 한다.) m.withAttr()은 항상 e.currentTarget을 쓰기 때문에 이러한 불일치를 사전에 방지할 수 있다.


관련 글 목차

  1.  mithril 앱의 기본 구성 및 m()
  2.  m.render() – 가상 DOM 렌더링하기
  3. m.mount – 가상 노드를 마운트하기
  4. m.prop() – 양방향 바인딩을 위한 데이터 래퍼 – deprecated
  5. m.withAttr() 이벤트 핸들러 처리
  6. m.component – 가상노드를 컴포넌트로 사용하기
  7. Todo 앱 예제
  8. m.route() – 단일페이지 애플리케이션 및 라우팅 규칙
  9. m.request – 서버와의 통신