본문 바로가기

Sencha Touch 2

7일차 : Sencha Touch 2 events!

센차 터치에서 제공하는 많은 components 들과 class 들은 다양한 events 들을 제공한다. events 들을 잘 활용하면 개발자가 원하는 순간에 유저를 통해, 혹은 instance 의 값에 변화가 일어남으로 인해 발생한 이벤트들을 효과적으로 핸들링 할 수 있다.


1. Events 란 무엇인가?

Events 란 클래스를 통해 만들어진 instance 에서 뭔가 흥미로운(?) 일이 생겼을 때 발생(fired) 된다. 

Ext.create('Ext.Panel', {
    html: 'My Panel',
    fullscreen: true,

    listeners: {
        painted: function() {
            Ext.Msg.alert('I was painted to the screen');
        }
    }
});


위의 코드를 실행하면, 처음 화면에 보여질 때, panel 이 그려지게 되고, 그럼 이 때 painted 라는 이벤트가 발생하게 된다. 그럼 해당 이벤트를 핸들링하기 위해 지정해 준 function 이 실행된다. (여기서는 메세지를 출력해줌)



Hover over the Events button to quickly see which events are availableHover over the Events button to quickly see which events are available

API 를 검색하게 되면 class 를 설명할 때, 위의 그림 처럼 맨 처음 부분에 Events 라고 번개 표시와 함께 써진 부분이 보일 것이다. 이 부분에 마우스를 올리면 어느 events 들이 있는지 확인할 수 있다.



2. 이벤트 나열하기

하나의 클래스가 두 개 이상의 events 를 듣고 싶어할 수 있다. 아래의 경우를 보자.


Ext.Viewport.add({
    xtype: 'button',
    centered: true,
    text: 'My Button',

    listeners: {
        tap: function() {
            this.hide();
        },
        hide: function() {
            //waits 1 second (1000ms) then shows the button again
            Ext.defer(function() {
                this.show();
            }, 1000, this);
        }
    }
});


코드에서 보는 것 처럼, tap 과 hide 라는 두 개의 event 를 각각 어떻게 핸들링 해야 하는 지에 대해서 나타낸 코드이다.

여기서 Ext.defer 는 어떤 함수를 몇 밀리초 뒤에 실행할 수 있도록 해주는 함수다. 위의 경우에는 this.show() 를 body 로 가지는 function 을 1000 밀리초, 즉 1초 뒤에 실행하라는 의미이다. 세 번째 전달인자로 this 를 넘겨주는데, 이때 this 는 scope 의 의미로 전달된다. (scope 에 대한 얘기는 곧 나온다.)



3. config 의 변화는 events 를 발생시킨다.

대부분의 classe instance 들은 run time 중에 다이나믹 하게 그 값이 바뀐다. 그 때 마다 대부분의 속성에 대해서 events 가 발생한다. 가령, Ext.Button 의 경우, width 와 height 라는 속성을 가지는데, 이들 속성의 값이 바뀌케 되면 각각 widthchange 와 heightchange 이벤트가 발생하게 된다. 아래의 코드를 보자.




4. event listener 를 나중에 추가하기.

지금 까지의 경우 components 가 만들어 질 때, listeners 라는 문법을 통해, 특정 event 에 대해서 listener 를 등록하는 법을 배웠다. 하지만, 실제로는 만들어지고 나서도 listeners 를 추가할 수 있다. 아래의 코드를 보자.

var myButton = Ext.Viewport.add({
    xtype: 'button',
    centered: true,
    text: 'Click me'
});

myButton.on('tap', function() {
    alert("Event listener attached by .on");
});

on 이라는 함수는 이벤트 핸들러 를 등록할 수 있도록 해 준다. 위의 코드에서 알 수 있듯이, on 의 첫번째 전달인자는 들으려는 event 이름이고, 두 번째 파라미터는 해당 이벤트가 발생했을 때 어떻게 핸들링 할 지에 대한 내용을 가진다. 


또한 하나의 이벤트에 대해서 두 개 이상의 handler(=listener) 가 있을 수 있다. 아래 코드를 보자.

var myButton = Ext.Viewport.add({
    xtype: 'button',
    centered: true,
    text: 'Click me',

    listeners: {
        tap: function() {
            alert('First tap listener');
        }
    }
});

myButton.on('tap', function() {
    alert("Second tap listener");
});

tap 이라는 이벤트에 대해서 두 개의 listeners 가 모두 들을려고 하고 있다. (이는 가능하다!) 


on 함수는 하나가 아니라 두 개 이상의 이벤트에 대해서도 동시에 핸들러를 지정할 수 있다. 아래 예를 보자.

var myButton = Ext.Viewport.add({
    xtype: 'button',
    centered: true,
    text: 'Click me'
});

myButton.on({
    tap: function() {
        var randomWidth = 100 + Math.round(Math.random() * 200);

        this.setWidth(randomWidth);
    },
    widthchange: function(button, newWidth, oldWidth) {
        alert('My width changed from ' + oldWidth + ' to ' + newWidth);
    }
});

위의 코드에서 봐서 알 수 있듯이 on 을 호출하면서 두 개의 이벤트에 대해서 listeners 를 등록했다. 



5. Listeners 없애기!

어떠한 event 에 대해서 이미 등록된 listeners 를 없애는 방법은 on 에서 했던 방식과 유사하다. 단지 un 이라는 메소드를 호출하며, 그리고 해당 이벤트에 대한 핸들러가 on 을 통해 등록됐을 때, 그 때 사용됐던 핸들러 함수를 그대로 un 의 두 번째 전달인자로 전달해야 한다는 점이 다르다.

아래 코드를 보자.

var doSomething = function() {
    alert('handler called');
};

var myButton = Ext.Viewport.add({
    xtype: 'button',
    text: 'My Button',
    centered: true,

    listeners: {
        tap: doSomething
    }
});

Ext.defer(function() {
    myButton.un('tap', doSomething);
}, 3000);

myButton 이 tap 이벤트를 핸들링 하기 위해서 사용했던 doSomething 을, tap 에 대한 이벤트 핸들러를 삭제할 때 그대로 사용하고 있다!



6. Listeners 가 가지고 있을 수 있는 options

1) Scope

어느 이벤트가 발생했을 때 그 이벤트를 핸들링하는 핸들러가 호출되어, 호출된 핸들러로 작업을 수행할 때, 이 때, 그 핸들러의 몸체에서 this 키워드를 쓰게 될 때, 그 때 this 가 누구를 가리킬 것인지를 결정지을 때 사용된다. 아래 예제를 보자.

var myButton = Ext.Viewport.add({
    xtype: 'button',
    centered: true,
    text: 'Click me'
});

var panel = Ext.create('Ext.Panel', {
    html: 'Panel HTML'
});

myButton.on({
    tap: {
        scope: panel,
        fn: function() {
            alert("Running in Panel's scope");
            alert(this.getHtml());
        }
    }
});

위의 code 를 보면, scope 을 panel 로 선택했기 때문에, tap 이벤트가 발생했을 때, this.getHtml() 을 호출할 수 있는 것이다. (이 때 this 는 panel 을 가리키기 때문이다.)


2) Single

동일한 이벤트가 여러 번 발생해도, 맨 처음 꺼만 핸들링하고 이후의 동일한 이벤트 발생에 대해서는 무시한다. 

var myButton = Ext.Viewport.add({
   xtype: 'button',
   centered: true,
   text: 'Click me',

   listeners: {
       tap: {
           single: true,
           fn: function() {
               alert("I will say this only once");
           }
       }
   }
});


3) Buffer

동일한 이벤트가 여러번 발생하면 이를 핸들링 해야 하는데, 이 때  일정한 시간 내에서 발생한 다수의 동일한 이벤트에 대해서는 한번만 핸들링 할 수 있도록 만들고 싶을 때 사용된다. 

var myButton = Ext.Viewport.add({
   xtype: 'button',
   centered: true,
   text: 'Click me',

   listeners: {
       tap: {
           buffer: 2000,
           fn: function() {
               alert("I will say this only once every 2 seconds");
           }
       }
   }
});

위의 코드는 tap 이벤트가 2초 사이에는 아무리 많이 일어나도 다 무시하고 한번만 핸들링하게 된다. 즉, 한 번만 알림 메세지를 띄우게 된다.



7. 자신이 정의한 이벤트를 발생시키기!

fireEvent 를 쓰면 자신만의 이벤트를 발생시킬 수 있다. 아래 코드를 보자.

var myButton = Ext.Viewport.add({
   xtype: 'button',
   centered: true,
   text: "Just wait 2 seconds",

   listeners: {
       myEvent: function(button, points) {
           alert('myEvent was fired! You score ' + points + ' points');
       }
   }
});

Ext.defer(function() {
    var number = Math.ceil(Math.random() * 100);

    myButton.fireEvent('myEvent', myButton, number);
}, 2000);

위의 코드에서 우선, myButton 은 myEvent 라는 독자적인 이벤트에 대해서 핸들링할 수 있도록 했다. 

그리고 나서 아랫 줄에서 myButton.fireEvent 를 통해 해당 이벤트를 실행시키도록 장치를 해놨다. 

이 때 처음 전달인자는 발생(fire) 시킬 이벤트의 이름이고, 두 번째 부터는, 해당 이벤트의 handler 에게 전달될 파라미터이다.