Ext JS - Learning Center

Tutorial:Extending Ext2 Class (Korean)

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: Ext2 클래스를 확장하는 데 필요한 단계를 살펴봅니다.
Author: Jozef Sakalos (번역:윤재홍)
Published: January 2, 2008
Ext Version: 2.0+
Languages: en.png English kr.png Korean

Contents

목표

Intended resulting IconCombo
Intended resulting IconCombo

텍스트 앞에 아이콘을 보여주는 Ext.form.Combobox 확장 클래스를 만들어봅시다. 예를 들자면, 이런 콤보박스는 국가 선택을 할 때 나라 이름 앞에 국기를 보여주는 경우에 유용할 겁니다.

우리 확장 클래스에게 Ext.ux.IconCombo라는 이름을 지어줍시다. 그리고, xtype iconcombo로 등록시킬 것입니다.

Ext 1.x에 익숙한 사용자들에게

Ext 1.x에서 Ext 클래스들을 확장하는 것은 어려운 작업이 아니었습니다. 그런데 Ext 2.x에서는 더 쉬워졌고, 전체적으로 크게 바뀌지 않았습니다. 심지어, 여러분은 Ext 1.x에서 했던 것과 동일한 방법으로 확장할 수도 있습니다. 하지만, 여러분이 타이핑할 필요가 없는 코드 한줄 한줄이 코드 관리, 가독성에 영향을 미치고 발생가능한 버그의 수를 줄여줍니다. (역자주: 이 부분 원문이 다소 이상합니다.) 따라서, 저는 가장 쉽고, 간결하고, 짧은 방법을 여기에서 보여드리겠습니다.

파일 만들기

첫번째 단계는 개발 과정에 필요할 파일을 준비하는 겁니다. 아마 이런 파일들을 필요로 할겁니다.

  • iconcombo.html: 우리의 새로운 확장 클래스를 이용할 어플리케이션을 위한 HTML 파일. 이 튜토리얼을 가능한 한 간결하게 하기 위해서, 이 파일은 자바스크립트 코드와 스타일시트를 포함합니다. 실제 개발을 할 때는, 자바스크립트와 스타일(시트)를 별도의 파일로 만드셔도 됩니다. (역자주: Saki는 Ext 1.x용 튜토리얼에서 이 파일들을 따로 분리했었습니다.)
  • Ext.ux.IconCombo.js: 확장 클래스의 자바스크립트 파일

iconcombo.html

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../extjs-2.0/resources/css/ext-all.css">
    <script type="text/javascript" src="../extjs-2.0/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../extjs-2.0/ext-all-debug.js"></script>
    <script type="text/javascript" src="Ext.ux.IconCombo.js"></script>
 
    <style type="text/css">
    .ux-flag-us {
        background-image:url(../img/flags/us.png) ! important;
    }
    .ux-flag-de {
        background-image:url(../img/flags/de.png) ! important;
    }
    .ux-flag-fr {
        background-image:url(../img/flags/fr.png) ! important;
    }
    .ux-icon-combo-icon {
        background-repeat: no-repeat;
        background-position: 0 50%;
        width: 18px;
        height: 14px;
    }
    .ux-icon-combo-input {
        padding-left: 25px;
    }
    .x-form-field-wrap .ux-icon-combo-icon {
        top: 3px;
        left: 5px;
    }
    .ux-icon-combo-item {
        background-repeat: no-repeat ! important;
        background-position: 3px 50% ! important;
        padding-left: 24px ! important;
    }
    </style>
 
    <script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../extjs-2.0/resources/images/default/s.gif';
Ext.onReady(function() {
    var win = new Ext.Window({
        title:'Icon Combo Ext 2.0 Extension Class Example',
        width:400,
        height:300,
        layout:'form',
        bodyStyle:'padding:10px',
        labelWidth:70,
        defaults:{anchor:'100%'},
        items:[{
            xtype:'iconcombo',
            fieldLabel:'IconCombo',
            store: new Ext.data.SimpleStore({
                    fields: ['countryCode', 'countryName', 'countryFlag'],
                    data: [
                        ['US', 'United States', 'ux-flag-us'],
                        ['DE', 'Germany', 'ux-flag-de'],
                        ['FR', 'France', 'ux-flag-fr']
                    ]
            }),
            valueField: 'countryCode',
            displayField: 'countryName',
            iconClsField: 'countryFlag',
            triggerAction: 'all',
            mode: 'local'
        }]
    });
    win.show();
});
    </script>
    <title>Icon Combo Ext 2.0 Extension Class Example</title>
</head>
<body>
</body>
</html>

이 파일 안에는 필요한 HTML 태그 외에도 onReady 함수가 있습니다. 이 함수에서 우리가 만들 iconcombo 만을 포함하는 form 레이아웃(layout)으로 구성된 윈도우를 생성합니다. 주의하셔야 할 점은, 실제적인 form을 이런 방식으로 생성하지 않으니 이 예제를 실제로 form들을 생성할 때 사용하지는 마세요. iconcombo의 store는 테스트 목적으로 인라인 데이터를 이용하고 있습니다.

여러분은 위 예제에서 Ext JS 라이브러리 파일들을 참조하는 경로를 여러분이 Ext 패키지를 설치할 때 지정한 위치로 수정해야 할 것입니다.

또한 국기 이미지 참조 경로도 여러분들이 저장한 위치에 따라 적절하게 수정하셔야 합니다.국기 이미지들은 famfamfam.com에서 다운로드 받으시면 됩니다.

Ext.ux.IconCombo.js

// vim: ts=4:sw=4:nu:fdc=2:nospell
/**
  * Ext.ux.IconCombo Extension Class for Ext 2.x Library
  *
  * @author  Ing. Jozef Sakalos
  * @version $Id: Ext.ux.IconCombo.js 617 2007-12-20 11:29:56Z jozo $
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  */
Ext.ux.IconCombo = Ext.extend(Ext.form.ComboBox, {
    initComponent:function() {
 
        // call parent initComponent
        Ext.ux.IconCombo.superclass.initComponent.call(this);
 
    } // end of function initComponent
});
 
// register xtype
Ext.reg('iconcombo', Ext.ux.IconCombo);
 
// end of file

클래스 확장을 위한 첫번째 단계는 부모 클래스인 Ext.form.ComboBox로부터 확장된 클래스를 생성하는 것입니다. 이 확장 클래스는 부모 클래스에 기능 외에 어떤 추가 기능도 갖고 있지 않습니다. 이렇게 해서 여러분은 이 확장 패턴이 동작한다는 것을 확인하고 나서 기능을 추가하기 시작할 수 있습니다.

위의 자바스크립트 파일은 정확하게 그 역할을 하고 있습니다.

이론

Ext 클래스를 확장하기 위해서 생성자 함수를 생성할 필요는 없습니다. 여러분이 할 일이라고는 Ext.extend 호출의 반환값을 우리의 네임스페이스에 있는 변수에 할당하는 것 뿐입니다. Ext.extend 함수는 부모 클래스와 config 객체를 인자로 받아서 우리의 확장 클래스를 반환합니다.

Ext 1.x에서 커스텀(custom) 생성자 함수에서 이루어졌던 모든 작업들이 이제는 initComponent 함수에서 처리됩니다. 이 함수는 대부분의 경우 오버라이드됩니다. initComponent 함수는 부모 클래스의 생성자 함수에서 초기에 호출됩니다.

하지만, 부모 클래스의 initComponent는 실행되어야 하는 유용한 코드들을 포함하고 있습니다. 여러분은 우리가 어떻게 부모 클래스의 initComponent 함수를 호출하고 있는지 위의 코드에서 확인할 수 있습니다. 위의 부모 클래스 함수들을 호출하는 패턴은 우리가 오버라이드하는 어떤 함수에도 똑같이 적용됩니다.

여러분의 확장 클래스를 위한 xtype을 등록하는 작업은 필수적인 것은 아닙니다만, 이렇게 하는 것은 아주 유용합니다. 이 등록 작업을 통해서 단지 한 단어의 xtype을 이용해서 새로 만든 확장 클래스를 간단하게 이용할 수 있습니다. 이 튜토리얼에서도 역시 이 방식을 따르고 있습니다.

시작해볼까요?

여기까지 아주 좋습니다. 인터넷 브라우져로 iconcombo.html을 열어보면, 여러분은 아마 한개의 일반적인 콤보박스를 보게 될 겁니다. 이 콤보박스는 세개의 아이템을 갖고 있고 독일이 선택되어 있을겁니다. 맞지요? 물론, 아직 아이콘은 없지요...

자 이제 작업을 시작해볼까요. 다음 코드를 Ext.ux.IconCombo.js 파일에 추가하시는데, 부모 클래스의 initComponent 함수 호출 바로 전에 추가하세요.

Ext.apply(this, {
            tpl:  '<tpl for=".">'
                + '<div class="x-combo-list-item ux-icon-combo-item '
                + '{' + this.iconClsField + '}">'
                + '{' + this.displayField + '}'
                + '</div></tpl>'
        });

여기서는 기본 콤보박스 아이템 템플릿을 iconClsField를 이용하는 우리의 템플릿으로 오버라이드 했습니다. 좋군요! 다음 테스트를 위한 준비가 되었으니 브라우져에 있는 페이지를 다시 불러보시죠. 멋지지 않습니까?

이제 리스트가 펼쳐졌을 때 멋진 아이콘들을 갖게 되었는데, 이게 접혔을 때도 국기가 보이게 하고 싶군요. 여러분도 그렇지요? 그럼 다음 코드를 생성자에 있는 initComponent 함수 다음에 넣어보세요.

onRender:function(ct, position) {
        // call parent onRender
        Ext.ux.IconCombo.superclass.onRender.call(this, ct, position);
 
        // adjust styles
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('ux-icon-combo-input');
 
        // add div for icon
        this.icon = Ext.DomHelper.append(this.el.up('div.x-form-field-wrap'), {
            tag: 'div', style:'position:absolute'
        });
    }, // end of function onRender
 
    setIconCls:function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.icon.className = 'ux-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    }, // end of function setIconCls
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    } // end of function setValue

onRender는 부모의 메써드를 먼저 호출한 후에 스타일을 적용하고 국기를 위한 div 콘테이너를 추가합니다.

우리는 setIconCls 함수를 추가하고 setValue 함수를 오버라이드했습니다. 당연히, 우리는 원래의 setValue 함수가 제 역할을 하기를 원하기 때문에, 먼저 부모의 setValue 함수를 호출하고 나서 우리가 만든 setIconCls 함수를 호출합니다.

드디어 마지막

자 이제 마지막 테스트입니다. HTML 페이지를 다시 불러보세요. 갖다 붙이는 데 실수만 하지 않았다면, 여러분은 이제 자신만의 새로운 Ext.ux.IconCombo 확장 클래스를 갖게 된 겁니다. 여러분이 여기까지 한 내용은 Ext 클래스를 확장하는 가장 기본적인 것들이었고, 여러분은 더 개선할 수 있을 것입니다.

완성된 코드

여러분이 참조하실 수 있도록 여기에 IconCombo 확장 클래스를 위한 전체 코드를 첨부합니다.

// vim: ts=4:sw=4:nu:fdc=2:nospell
/**
  * Ext.ux.IconCombo Extension Class for Ext 2.x Library
  *
  * @author  Ing. Jozef Sakalos
  * @version $Id: Ext.ux.IconCombo.js 617 2007-12-20 11:29:56Z jozo $
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  */
Ext.ux.IconCombo = Ext.extend(Ext.form.ComboBox, {
    initComponent:function() {
 
        Ext.apply(this, {
            tpl:  '<tpl for=".">'
                + '<div class="x-combo-list-item ux-icon-combo-item '
                + '{' + this.iconClsField + '}">'
                + '{' + this.displayField + '}'
                + '</div></tpl>'
        });
 
        // call parent initComponent
        Ext.ux.IconCombo.superclass.initComponent.call(this);
 
    }, // end of function initComponent
 
    onRender:function(ct, position) {
        // call parent onRender
        Ext.ux.IconCombo.superclass.onRender.call(this, ct, position);
 
        // adjust styles
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('ux-icon-combo-input');
 
        // add div for icon
        this.icon = Ext.DomHelper.append(this.el.up('div.x-form-field-wrap'), {
            tag: 'div', style:'position:absolute'
        });
    }, // end of function onRender
 
    setIconCls:function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.icon.className = 'ux-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    }, // end of function setIconCls
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    } // end of function setValue
});
 
// register xtype
Ext.reg('iconcombo', Ext.ux.IconCombo);
 
// end of file
  • This page was last modified 21:02, 4 May 2008.
  • This page has been accessed 526 times.