Header

  1. View current page

    saillinux님의 노트

Profile_img_60x60_01
6

ExtJS 노트 정리

ExtJS로 하는 개발 일지


파일 다운받기

ext-2.0.1.zip

 

 

Javascript Object Oriented

ExtJS에 대해 알아 보기 앞서 ExtJs에서 채택한 Javascript으로 하는 OOP에 대한 설명:

 

그전에 우선 기본 Javascript에서 제공하는 OOP에 대해 알아 보도록 하겠다.

원문: http://www.permadi.com/tutori

ExtJS로 하는 개발 일지


파일 다운받기

ext-2.0.1.zip

 

 

Javascript Object Oriented

ExtJS에 대해 알아 보기 앞서 ExtJs에서 채택한 Javascript으로 하는 OOP에 대한 설명:

 

그전에 우선 기본 Javascript에서 제공하는 OOP에 대해 알아 보도록 하겠다.

원문: http://www.permadi.com/tutorial/jsFunc/index.html

 

A function can be used as a blueprint for a data type.  This feature is commonly used in object oriented programming to simulate user defined data type.  Objects created with user defined data type is usually referred to as user defined objects.

 

  1.           function Ball()

    {

    }

    var ball0=new Ball(); // ball0 now points to a new object



    alert(ball0); // prints "Object" because ball0 is now an Object

 

The "new" keyword creates a new object (named ball0)of type Object.  It then executes: Ball(), passing the reference to ball0 as the calling object.

 

  1.           function Ball(message)

    {

    alert(message);

    }

  2.           var ball0=new Object();

    ball0.construct=Ball;

    ball0.construct("creating new ball"); // executes ball0.Ball("creating..");
              ball0.name="ball-0";                      

    alert(ball0.name);

 

When we create an object using the new keyword like above, a new Object is created.   We can add properties to the object after the creation (such as when I added "name" property above.  The problem with that approach is that if we create another instance of the object, we need to add the property again to the new object like below.

 

  1.           function Ball(message, specifiedName)

    {

    alert(message);

    this.name=specifiedName;

    }

    var ball0=new Ball("creating new Ball", "Soccer Ball");

    alert(ball0.name); // prints "Soccer Ball"

 

Remember that the "new" keyword eventually causes the constructor function to be executed.  In this case, it will executel Ball("creating new Ball", "Soccer Ball"); and thekeyword this will refer to ball0


Therefore, the line: this.name=specifiedName becomes ball0.name="Soccer Ball".  
It basically said: add "name" property to ball0, with the value of "Soccer Ball."

 

  1.           function Employee(name, salary)

    {

    this.name=name;

    this.salary=salary;



    this.addSalary=addSalaryFunction;
    this.getSalary=function()

    {

    return this.salary;

    };
    }
              function addSalaryFunction(addition)

    {

    this.salary=this.salary+addition;

    }
    var boss=new Employee("John", 200000);var boss2=new Employee("Joan", 200000);

    var boss3=new Employee("Kim", 200000);

 

When you create more instances of the objects (boss2 and boss3), each of those instances will have a separate copy of the getSalary code; whereas addSalary points to only one location (which is the addSalaryFunction).

boss.gif

 

Object Prototype (나중에 파생에 관해서도 다루어야겠다)

Every constructor function has a property named prototype.  This property is very useful to declare variables or functions that are common to a particular class.

 

As you've seen above, prototype is an object, therefore, you can add properties to it.  The properties you addedto prototype will become common properties of all objects created using the constructor function

 

  1.           function Fish(name, color)

    {

    this.name=name;

    this.color=color;

    }

    Fish.prototype.livesIn="water";

    Fish.prototype.price=20;
  2.  

  3.           var fish1=new Fish("mackarel", "gray");

    var fish2=new Fish("goldfish", "orange");

    var fish3=new Fish("salmon", "white");
  4.           for (i=1; i<=3; i++)

    {

    var fish=eval("fish"+i); // i'm just getting a pointer to the fish

    alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price);

    }

 

You see that all fish has the livesIn and price property, even though they are not specifically declared on each individual fish.   This is because when an object is created, the constructor function assigns its prototype property to the internal __proto__ property of the new object.  The __proto__ property is used by the object to look for properties. (순서에 대해서도...)

 

You can use prototype to assign functions that are common on all objects, too.  This has the benefit of not having to create and initialize the property every time you construct an object.

 

  1.           function Employee(name, salary)

    {

    this.name=name;

    this.salary=salary;

    }
              Employee.prototype.getSalary=function getSalaryFunction()

    {

    return this.salary;

    }



    Employee.prototype.addSalary=function addSalaryFunction(addition)

    {

    this.salary=this.salary+addition;

    }

 

prototype.gif

 

prototype을 이용한 확장

새로운 객체 클래스를 생성한 것이 아니라 기존 객체 클래스의 기능을 확장한 기능.

메소드에 접근할때 JS엔진은 처음으로 객체 구현에서 찾고 없으면 prototype집합에서 찾고 없으면 해당  변수에서 찾는다.

 

 

 

The new way

You define private functions and variables and return your public variables and functions as properties and methods of an anonymous object:

  1. var classicModulePattern = function(){
      var privateVar = 1;
      function privateFunction(){
        alert('private');
      }
      return {
        publicVar:2,
        publicFunction:function(){
          classicModulePattern.anotherPublicFunction(); 
        },
        anotherPublicFunction:function(){
          privateFunction();
        }
      }
    }();  // the parens here cause the anonymous function to execute and return

    classicModulePattern.publicFunction();

  2.  

 

 

 

 

생성과 체인과 속성

상 속은 다른객체의 메소드와 프로퍼티를 새로운 객체에 병합 또는 상속시키는 것이다.  새로운 클래스가 다른 클래스로 부터 상속받은 기능 중의 일부를 재 정의할 수 있기 때문이다.  JS 1.3부터 apply와 call함수를 이용하여 흉내 낼수 있게 되었다.

 

함수를 사용하여 객체를 정의를 하면 이 함수는 곧 객체 생성자가 되고, new 키워드를 생성할 때 호출된다.

  1. theobh = new DivObj(params);

 

apply, call 메소드를 사용하면 다른 객체의 Context 내에서 메소드를 적용하거나 호출할수 있게 된다.

자식 객체 생성자 안에서 사용하면 부모 객체의 모든 프로퍼티와 메소드를 상속 받도록 생성자들을 연결 시킨다.

 

call 메소드의 첫번째 인자는 this 두번째는 인자에는 부모 객체의 생성자에 전달 하려는 인자를 입련한다

obj.call(this, arg1, arg2, ..., argn)

 

apply 메소드에는 두 가지(자식 객체(this), 자식 객체의 인자 배열)를 넘겨 준다.

 

 

 

 

 

 

Object Extend (상속)

extendObject subclass, Object superclass, [Object overrides] ) : void

 

새로운 ExtJS Component를 상속하는 클래스 생성시 사용하게 될 형식.

  1. NewClass = function(arg1, arg2, config) {
       Ext.apply(this,config);
       NewClass.superclass.constructor.call(this);
    };

  2. Ext.extend(NewClass, BaseClass, {
       overriddenFunction: function(arg1,arg2) {
       // code
       },
       newFunction: function(arg) {
       // code
       }
    });

 

  1. SamplePanel = Ext.extend(Ext.Panel, {
        autoHeight: true,
        frame:true,
        collapsible: true,
        cls:'demos',

        afterRender : function(){
            SamplePanel.superclass.afterRender.call(this);
            this.tpl.overwrite(this.body, this);
        },

        tpl : new Ext.XTemplate(
            '<dl>',
                '<tpl for="samples">',
                '<dt><a href="{url}" target="_blank"><img src="shared/screens/{icon}"/></a><br/>',
                    '<span>{text}</span>',
                '</dt>',
                '</tpl>',
            '</dl><div style="clear:both"></div>'
        )
    });

SamplePanel이라는 Panel을 상속하는 클래스 선언.

 

 

Component Model

Component 클래스는 ExtJS 아키텍쳐를 구성하는 가장 기초적인 클래스가 되겠다.  Component는 통합된 모델을 제공하는데 이는 생성, 렌더링, 이벤트 핸들링, 상태 관리, 섬멸등 Ext에서 사용되는 모든 기능들이 여기에 정의 되겠다.

 

  • 명시적 생성자(constructor) 체이닝 및 오버라이딩

    Component 는 설정등을 하위 클래스에 적용할수 있도록 기본 생성자를 제공한다.  그리고 initComponent라는 함수를 통하여 커스텀 생성자를 제공하며 체인을 형성하는 상속의 구현을 가능케 하였다.  상속을 받는 클래스들은 initComponent를 통하여 임의로 받은 설정을 통해 안전하고 제데로 구현되겠다.

  • 관리하에 있는 렌더링

    모든 Component들은 즉각 요청되는 렌더링과 파이프라인들을 자동으로 관리 지원한다.  그리고 beforerender와 render 이벤트 등을 통해 더욱 유연하고 맞춤형식 렌더링을 지원한다.

  • 관리하에 있는 섬멸자

    각 Component는 destory라는 함수를 지원하며, Ext 자체가 garbage collection등 현대 사용되지 않는 Component를 자동으로 섬멸해주는 기능을 지원한다.  렌더링과 마찬가지로 beforedestory와 destory 이벤트를 지원하겠다.

  • 자동 상태(state) 관리자

    StateManager 객체가 state Provider를 통해 등록이 되면 각 Component의 설정 및 상태복구 기능을 지원하게 된다.

  • 변함없는 인터페이스 제공

    가장 기초적인 기능인 hiding, showing, enabling 그리고 disabling 을 Component를 통해 제공하며, 이기능들은 오버라이딩 되거나 커스터마이징이 가능하다.

  • ComponentMgr을 통한 유효성

    모든 Component들은 생성될때 ComponentMgr에 등록이 되며 Ext.getCmp('id') 함수를 통해 언제든지 어떤 Component를 불려 들이수 있다

  • Plugin 지원

    어 떤 Component들이건 plugin을 통해 확장이 가능하다.  plugin은 Compoent타입을 인자로 받는 init 함수를 지원하는 클래스이다.  plugin은 Component에 plugins 설정을 통해 더해지는게 가능하다.  Component가 생성될때 만약 여러 플러긴이 존재한다면 각 플러긴의 init 함수를 호출하여 Component의 reference값을 보낸다.  각 플러긴은 이를 통해 해당하는 이벤트에 적절한 함추를 호출할수 있게 되겠다.

 

 

Component Life Cycle

주로 Component를 확장하거나 커스터마이즈할때 Component Life Cycle을 참조하라고 하지만 결국에 기본적인 컴포넌트 생성 및 사용에 대해 좀더 좋은 이해가 필요하면 가장 참조 할만한 주제가 될수 있겠다.

 

Component를 기본으로 하는 모든 클래스가 가지는 life cycle이 가지는 가장 중요한 스테이지들에 대해 알아 보도록 하겠다.

 

Initialization

  1. The config object is applied

    Component를 확장하는 클래스들은 생성자 (constructor)를 제공할 필요가 없다.  Component 를 상속하는 클래스에 config을 넘겨 줌으로써서 객체를 생성할수 있겠다. (예제 확인)

  2. The base Component events are created

    Component가 가지는 이벤트 생성: enable, disable, beforeshow, show, beforehide, hide, beforerender, render, beforedestroy, destroy.

  3. The component is registered in ComponentMgr

    Ext.getCmp를 통해 유효한 Component 등록

  4. The initComponent method is called

    Component 를 상속받는 클래스 생성시 가장 중요한 부분이 되겠다.  일종의 상속자의 생성자를 구현할때 사용되는 템플레이트라고 생각 할수 있겠다.  상속자의 클래스가 먼저 호출이 되며 Component 클래스까지 거슬러 올라가 superclass.initComponent를 호출하게 된다.  이 함수는 클래스 생성을 손쉽게 해주며 생성자 오버라이딩을 어떤 스텝에서든지 가능케 도와준다.

  5. 상태(state)를 초기화 한다 (존재한다면)

    만약 Component가 상태(state)를 이용한다면 다시 올리도록 한다.

  6. 플러긴을 올린다 (존재한다면)

    만약 Config에 플러긴 사용 여부가 있다면 여기서 초기화 된다.

  7. The component is rendered (존재한다면)

    만약 renderTo 아니면 applyTo가 Config에 설정되어있다면 곧바로 렌더 될것이다.  아니면 Component를 담고 있는 Container가 명령을 하지 않는 이상 렌더 되지 않는다.

 

 

Rendering

  1. The beforerender event is fired

    이부분은 취소될수있는 이벤트이며 핸들러를 부여함으로써 렌더링을 막을수 있는 곳이 되겠다.

  2. The container is set

    container가 지정되어 있지 않다면, Component의 부모 노드의 DOM 객체가 container로 지정이된다.

  3. The onRender method is called

    Component 를 상속하는 클래스들한테는 중요한 스텝이 되겠다.  상속자가 렌더링에 필요한 로직을 템플레이트 제공으로 구현 할수 있게씀 도와준다.  생성된 클래스가 먼저 불려들여지고 상속하는 클래스들이 Component 클래스 까지 거슬러 올라가면서 각 superclass.onRender가 호출되게 된다.

  4. The Component is "unhidden"

    많은 Component들은 처음앤 CSS 클래스인 'x-hidden'으로 인해 감추어져있다가 autoShow Config값이 참으로 설정이되면 보이게된다.

  5. Custom class and/or style applied

    Component 를 상속하는 모든 상속자들은 config값인 cls와 style을 지원한다.  이를 통해 사용자 정의의 CSS class와 rule이 Component에 존재 하는 DOM 객체에 적용이된다.  CSS의 class는 Component의 markup을 감싸는 바로 윗단의 element에 적용된다.

  6. The render event is fired

    Component가 제데로 렌더 되었다고 알려주는 스텝이며 이 Component의 DOM 객체가 유효화되는 스텝이 되겠다.  만약 이 Component를 렌더링 전에 에세스 시도를 했다면 에러를 발생할 것이다.

  7. The afterRender method is called

    상속 클래스들을 위한 또 다른 템플레이트 형식의 함수가 되겠다.  렌더링후의 로직이 들어가는 부분인되 상속 클래스가 이를 이용하기 위해서는 superclass.afterRender를 이용해야 된다.

  8. The Component is hidden and/or disabled (if applicable)

    hidden 및 disable 설정값이 적용되는 시점이 되겠다.

  9. Any state-specific events are initialized (if applicable)

    상태(state)를 감지하는 Component들이 상태 로딩과 저장을 특정 이벤트로 정의 할수 있는 시점이 되겠다.

 

 

Destruction

  1. The beforedestroy event is fired

    Component가 섬멸되는 것을 취소할수 있는 이벤트가 되겠다.

  2. The beforeDestroy method is called

    상속 클래스들을 위한 또 다른 템플레이트 형식의 함수가 되겠다.  섬멸전의 로직이 들어가는 부분이며 상속 클래스가 이를 이용하기 위해서는 superclass.beforeDestroy를 이용해야 된다.

  3. Element and its listeners are removed

    만약 Component가 렌더된 상태이면 이를 생성하는 Element의 event listeners를 다 제거후 DOM에서 해당 Element가 삭제되는 시점이 되겠다.

  4. The onDestroy method is called

    상 속 클래스들을 위한 또 다른 템플레이트 형식의 함수가 되겠다.  섬멸후의 로직이 들어가는 부분이며 상속 클래스가 이를 이용하기 위해서는 superclass.onDestroy를 이용해야 된다.  주의 할점이 있다면 Container 클래스는 자동으로 Container가 가지는 items 콜렉션에 있는 Component를 불러와 destroy하는 onDestroy를 구현하고 있다.

  5. Component is unregistered from ComponentMgr

    Ext.getCmp로 통해 불려 들이지 못하게 된다.

  6. The destroy event is fired

    Component가 완전히 섬멸 되었다는 것을 알리는 시점이 되겠다.

  7. Event listeners on the Component are removed

    Component와 그에 해당하는 event가 따로 분리 되어있어 해당 이벤트가 존재하면 제거하는 시점이 되겠다.

 

 

Component XTypes

 

xtype 은 Ext가 2.0으로 되면서 새로 생긴 기능인데 이는 아래와 코드와 같이 직접 버튼 객체를 생성을 안해도 items에 xtype이 정의된 config 값을 주어주는 것만으로 Component를 생성할수 있는것이 되겠다.  최적화를 위해 구현된 기능인데 렌더링 파이프라인에 보내기전에 객체를 생성해서 내 보내지 않아 렌더링 및 오브젝트 생성에 시간 소모를 줄일수 있게 되었다.  이로 인해 메모리 및 리소스를 절약 할수 있게 되었으며 복잡한 레이아웃 생성시 좋은 속도를 보이고 있다.

 

  1. //Explicit creation of contained Components:
    var panel = new Ext.Panel({
       ...
       items: [
          new Ext.Button({
             text: 'OK'
          })
       ]
    };
     
    //Implicit creation using xtype:
    var panel = new Ext.Panel({
       ...
       items: [{
          xtype: 'button',
          text: 'OK'
       }]
    };

 

첫 번째 방법은 Panel이 생성되는 시점에서 버튼이 다른 Component들과 만들어 지는데 이로 인해 렌더링이 지연이된다.  두번째 방법에선 버튼이 Panel이 생성되어 브라우저에서 디스플레이되지않는 한 생성되고 렌더 되지 않는다.  만약 Panel이 디스플레이되지 않으면 Button은 생성되지 않으면 어떤 리소스도 소모 하지 않을것이다.

 

BoxComponent

가 장 기초가 되는 Component중 하나이며 Component 클래스를 확장하는 클래스가 되겠다.  일정하고 Cross-Browser를 지원하며 렌더가 가능하면서 레이아웃에 사용되는 Component이기도 하다.  크기와 위치를 처리해주는 Component이며 브라우저마다 다른 padding, margins, 그리고 borders를 일정하게 생성되도록해주는 Component가 되겠다.  모든 Container 클래스는 BoxComponent를 상속한다.

 

 

Container Model

Ext2-Container-hierarchy.gif

 

Container

Container 는 가장 기초가 되는 Component중 하나인데 다른 Componet들을 담는 Component로 주로 사용이 되겠다.  이 Component는 레이아웃과 렌더링을 다루고 있으며 Component들의 sizing과 nesting을 핸들링한다 그리고 일정하게 container에 component를 담는 메카니즘을 제공하기도 한다.  이 component는 직접적으로 사용되면 안돼는 Component중 하나가 되겠다.

 

Panel

Panel 은 Ext 2.0에서 존재하는 Component중에 주력으로 사용되는 Component이며 레이아웃 타스크에서 90%이상 사용된다.   레이아웃 형성을 위하여 보이지 않는 박스로 사용될수 있기도 하다.  UI window 디자인을 위한 가장 기본이 되는 Component이며 window의 위 아래에 존재하는 바에 툴바, 메뉴, 헤더, 풋터, 몸체 등을 더할수 있겠끔 해주는 것이 되겠다.  Panel에는 기본적으로 expandable과 collapsible 그리고 toolbar 기능이 있으며, 다른 툴들을 위해 기본적으로 버튼을 제공한다.  Panel은 Container나 layout에 쉽게 더해질수 있으며 레이아웃과 렌더링 로직은 완전히 Ext가 관리한다.

Ext 2.0의 주력 Component들이며 Panel의 상속 클래스 들이 되겠다.

 

Window

Window는 특별한 Panel인데 floated, minimized/maximized, restored, dragged, 등의 기능을 가진다.  데스크탑에서 사용되는 window 같은 UI를 구현하기 위한 클래스가 되겠다.

 

Viewport

 

Viewport 는 유틸리티 Container 클래스 인데 자동으로 document body에 브라우저 치수 사이즈를 맞추어 렌더 된다.  자동으로 resizing과 레이아웃 치수 계산이 되어 full-screen용 어플리케이션 작성시 좋겠다.  주의할점은 viewport는 document.body에 밖에 적용이 안됀다는 것이다.

 

Layouts

Ext2-Layout-hierarchy.gif

 

레 이아웃 객체는 new 키워드 통하여 생성되지 않으며 대신 Container에서 내부적으로 생성되고 사용된다.  Container 자체는 레이아웃에 대해 알지 못하며 Container에 들어가는 설정을 통해 모든 레이아웃에 대한 처리가 된다.  Container가 생성될때마다 레이아웃 스타일이나 해당 레이아웃 클래스에 대한 설정을 layoutConfig을 통해 할수 있겠다.  에를 들어:

 

  1.           var panel = new Panel({
    title: 'My Accordion',

    layout: 'accordion', // The layout style to use in this panel
    layoutConfig: {
    animate: true // Layout-specific config values go here
    }
    // additional Panel options...
    });

 

Panel 이 Panel 클래스를 담는 레이아웃을 생성할때 주의 해야 할점은 모든 레이아웃에 있는 Panel은 layout 속성이 정의 되어있어야 한다는것이 되겠다. 특별한 레이아웃인 border 아니면 accordian이 아닌 이상 fit을 정의하는게 좋겠다.

 

 

ExtJS를 사용하면서 주의 해야 할점들

 

  • ExtJS 라이브러리 자체가 덩치가 커서 php나 jsp등 페이지 엠베딩 방식으로 사용시 문제가 생김

    • 페이지의 모든 DOM객체가 로딩이 되어야 정상적으로 작동을 함.
    • php나 jsp로 페이지 로딩을 조금이라도 방해하는 문제가 있으면 라이브러리 동작이 정상적이지 않음
  • ExtJS를 사용시 모든 시작은 Ext.onReady 함수안에서 시작이된다 (에서 시작이 아닌 이 함수 인자로 들어가는 모든 것들을 말한다).

    • ExtJS에선 페이지의 모든 DOM객체가 올라온 다음에야 라이브러리가 정상적으로 동작하기에 onReady가 이를 체크해주는 큰 역할을 한다 (그래고 php, jsp에서 다이렉트로 불러지면 작은 딜레이로 인해 망가진다.)
    • 아마도 이벤트 등록 작업도 포함이 되어서 페이지가 다로딩이된후 동작을 원하는거 같다.
  • ExtJS를 사용할라면 프론트와 백엔드를 확실히 나누는 AJAX를 이용해야 한다 (애당초 새로운 프로젝트는 이 기술을 중점으로 써야 한다 동시에 서버쪽 부하를 줄이는데 많은 방법론을 구사할수 있겠다).

 

 

ExtJS를 이용한 Layout표현

trk_layout01 예로 들어 설명.

 

ExtJS를 이용한 AJAX구현

 

Panel의 함수인 load로 페이지를 AJAX로 가져올수 있겠다.

Store용 데이타를 가져올때는 DataProxy를 상속하는 객체들로 AJAX를 이용하여 Data를 가져올수 있다.

 

 

ExtJS Grid

Grid용 Data가 준비되는데까지의 순서

 

Store: a client side cache of Record objects which provide input data for Components such as the GridPanel, the ComboBox, or the DataView

 

 

Data Store

Ext.data.GroupingStore (grouping records by one of the available fields) 를 이용하여 dataset값을 준비함.

 

순서

Record.create() 로 필드 정의 -> proxy( Ext.data.HttpProxy ) or data( Ext.grid.dummyData ) -> reader ( array or json or xml ) -> Record로 변환? -> Store (GroupingStore)

 

하나의 GridPanel 객체를 생성하기 위해 필요한 객체들:

Grid 테이블을 하나 만들기 위해서 여러 객체가 생성되는데 이렇게 세분화하게 된 이유는 데이터를 가져오는 방식이라던지 언제나 다른 필드명과 갯수 그리고 어떤식으로 데이터를 읽어 들이던가등을 세분화 해두면 정의하기 편하고 유연성 있게 프로그램을 디자인 할수 있기 때문이다.

 

 

Ext.data.Record 클래스의 create()함수를 이용하여 데이타 형식을 정의한다.  여기서 필드명 및 형식등을 정의하게 된다.

 

인 기있는 페이지 리포트가 가지는 값들을 Ajax로 가져온 후 리더기로 읽어 들일때 사용하는 필드를 정의하는 코드가 되겠다. (서버측에서 데이터를 생성하여 가져오는 방법은 JSON 소개와 함께 나중에 예로 설명을 들도록하겠다).  필드값이 스트링이면 간단히 배얼안에 일치하는 필드 이름만 넣어주어도 된다.

  1. var LoggerData = Ext.data.Record.create([
            { name: 'url_name' },
            { name: 'url' },
            { name: 'hit' },
            { name: 'page_name' },
            { name: 'visit' },
            { name: 'seq' }
        ]);

좀 더 Record에 대해 설명 하자면 각 Grid안에 있는 아이템들은 우리가 정의한 필드 값을 가지고 Record 클래스를 이용해 생성된 객체를 이용하여 나타나게 된다. 즉 각 Row가 Record객체라고 생각하면 되겠고 우리가 생성한 LoggerData는 그 틀이라고 생각할수 있다.

 

 

ExtJS는 프론트 페이지와 백엔드를 나눔으로써 더욱 유연성있는 디자인을 구현할수 있기에 Ajax를 이용해 데이타를 가져와서 렌더 해주는 방식을 채택하기로 했다. Grid에서 사용하는 데이타를 가져올때  DataProxy를 계승하는 클래스를 이용해 데이타를 가져오는데 약 세가지정도의 방법이 있다.

HttpProxy, MemoryProxy, ScriptTagProxy 이중에서 HttpProxy를 이용하여 웹상에서 데이타를 가져오는 방법을 표준으로 정해서 사용하도록 하겠다.

 

HttpProxy의 사용 예를 들어 보겠다.

  1. var proxy = new Ext.data.HttpProxy({
                url: 'http://dev9.logger.co.kr/report/trk_sitepages_json.tsp',
                method: 'GET'
            });

 

 

이렇게 해서 가져온 데이터를 어떻게 읽어 드릴지 정의 할수 있는 DataReader에 대해 설명하도록 하겠다.

ExtJS에는 DataReade 계승 하는 세개의 클래스가 있다.

ArrayReader, JsonReader, XmlReader 여기서 우리는 JsonReader기를 이용하여 Ajax로 받아온 값들을 읽어드리기로 하겠다.

그외 DataReader를 계승하는 클래스를 우리가 정의하여 언제든 새로운 데이타 형식을 파싱을 할수 있는 매우 유용한 클래스가 되겠다.

 

  1. var reader = new Ext.data.JsonReader({
                root: 'trk_root',
                // totalProperty: 'totalCount',
                id: 'id'
            }, LoggerData);

여 기서 root는 json의 Root 노드 이름을 정의 하는곳이고 id는 받아들인 json 데이타에 값들의 id를 나타내는 필드 이름을 정의하면 된다 (Primary Key 라고 생각해도 무난할듯하다).  LoggerData는 우리가 아까 정의 했던 필드 형식을 답고 있는 객체가 되겠다.  LoggerData 객체에 정의 되어 있는 포멧에 맞추어 데이터가 맵핑이 됨으로 LoggerData 같은 필드 형식을 먼저 정의 해주도록 하자.

 

이제 이렇게 준비된 proxy와 reader객체를 이용하여 Grid용 데이타 형식으로 만들어 주는 Store 클래스에 대해 알아보도록 하겠다. 이 Store 클래스는 GridPanel에서 데이타를 참조 하는데 사용된다.  여기까지 왔으면 왜 이렇게 까지 여러작업을 하여 데이타를 생성하는지 대충 이해 했을거라 생각한다.

 

  1. var store = new Ext.data.Store({
            proxy: proxy,
            reader: reader,
            remoteSort: true
        });

 

우 리가 이미 정의 한 proxy와 reader 객체를 각 맞는 필드에 주도록 한다.  여기서 remoteSort 필드가 true일때는 서버측에서 정렬을 하게된다.  Ajax 콜을 할때 추가 파라미터를 더해 던진후 정렬된 데이터를 뿌려주겠는가에 대한 여부를 여기서 정하는 것이다 되겠다.  어떤이유가 있어 클라이언트에서 정령을 못하는 이유가 없는 이상 서버 로드를 줄이기 위해서 클라이언트 쪽에서 정렬를 해주는게 좋은 방침인듯하다.

 

난 필드를 정의를 해주면 자동으로 GridPanel에서 컬럼도 자동으로 생성 해 주는주 알았지만 안타깝게도 데이타 형식과 프레젠테이션 으로 나누어져 있는걸 확인 하였다.  새로운 객체를 ColumnModel에서 생성하여 이를 GridPanel 생성시 Store로 생성한 데이타 객체와 함께 건네 주어야 한다.

이 ColumnModel은 GridPanel객체가 생성될때 각 컬럼을 지정해 주는 객체가 되겠다.

  1. var cm = new Ext.grid.ColumnModel([{
               header: 'Page Name',
               dataIndex: 'page_name',
               width: 420
            },{
               header: "Url Name",
               dataIndex: 'url_name',
               width: 100
            },{
               header: "Hit",
               dataIndex: 'hit',
               width: 70,
               align: 'right'
            },{
               header: "visit",
               dataIndex: 'visit',
               width: 150
            }]);

여 기서 4개의 컬럼을 생성하는 뎨제를 설명 하겠다.  ColumnModel 클래스가 constructor로 받아들이는 값은 column config objects들을 담는 배열이 되겠다.  여기서 각 컬럼은 몇가지의 간단한 속성 값으로 정의가 되는데 header가 컬럼 이름이고 dataIndex가 우리가 Store에 저장한 필드값을 이 컬럼에 사용한다는 것이 되겠다.  그외 속성 값들을 본 메뉴얼에서 다루기엔 범위를 넘어서 예제를 보거나 API를 참조 하면서 습득하도록 하겠다.

 

이제 Store 클래스로 생성된 store객체와 ColumnModel로 생성된 cm객체가 준비가 되었으니 GridPanel을 생성하도록 하겠다.

 

GridPanel 생성에 필요한 대부분의 설정은 store와 cm이 담고 있으므로 GridPanel의 프레젠테이션을 설정하는 속성등을 설정해주면 되겠다.

  1. var grid = new Ext.grid.GridPanel({
            region:'south',
            margins: '2 2 2 2',autoExpandColumn: 'url_name',
            store: store,
            cm: cm,
            autoExpandColumn: 'page_name',
            height:350,
            width:400
        });

여 기서 store와 cm 속성에 우리가 정의한 store 및 cm값을 설정해 주도록 한다.  region은 만약 BorderLayout을 이용하여 브라우저에 우리가 생성한 Panel 객체들을 표시해주는 경의 정의 하면 된다.  autoExpandColumn은 자동으로 주어진 해당 컬럼에 길이를 자동으로 컬럼 값 길이에 맞추어 늘려준다.

 

렌더링 방법

render()를 호출하여 렌더 하는 방법

Panel 객체로 Viweport나 Panel을 인자로 받는 객체에 인자로 사용.

 

store.load()를 호출하지 않으면 초기 값이 나오지 않으니 store객체가 proxy를 가지고 생성된 후 load()함수를 호출해 주도록하자.

페이징을 사용시 start와 limit값을 정의해 주어야한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

al/jsFunc/index.html

 

A function can be used as a blueprint for a data type.  This feature is commonly used in object oriented programming to simulate user defined data type.  Objects created with user defined data type is usually referred to as user defined objects.

 

  1.           function Ball()
    {
    }
    var ball0=new Ball(); // ball0 now points to a new object

    alert(ball0); // prints "Object" because ball0 is now an Object

 

The "new" keyword creates a new object (named ball0)of type Object.  It then executes: Ball(), passing the reference to ball0 as the calling object.

 

  1.           function Ball(message)
    {
    alert(message);
    }

  2.           var ball0=new Object();
    ball0.construct=Ball;
    ball0.construct("creating new ball"); // executes ball0.Ball("creating..");
              ball0.name="ball-0";                      
    alert(ball0.name);

 

When we create an object using the new keyword like above, a new Object is created.   We can add properties to the object after the creation (such as when I added "name" property above.  The problem with that approach is that if we create another instance of the object, we need to add the property again to the new object like below.

 

  1.           function Ball(message, specifiedName)
    {
    alert(message);
    this.name=specifiedName;
    }
    var ball0=new Ball("creating new Ball", "Soccer Ball");
    alert(ball0.name); // prints "Soccer Ball"

 

Remember that the "new" keyword eventually causes the constructor function to be executed.  In this case, it will executel Ball("creating new Ball", "Soccer Ball"); and thekeyword this will refer to ball0


Therefore, the line: this.name=specifiedName becomes ball0.name="Soccer Ball".  
It basically said: add "name" property to ball0, with the value of "Soccer Ball."

 

  1.           function Employee(name, salary)
    {
    this.name=name;
    this.salary=salary;

    this.addSalary=addSalaryFunction;
    this.getSalary=function()
    {
    return this.salary;
    };
    }
              function addSalaryFunction(addition)
    {
    this.salary=this.salary+addition;
    }
    var boss=new Employee("John", 200000);var boss2=new Employee("Joan", 200000);
    var boss3=new Employee("Kim", 200000);

 

When you create more instances of the objects (boss2 and boss3), each of those instances will have a separate copy of the getSalary code; whereas addSalary points to only one location (which is the addSalaryFunction).

boss.gif

 

Object Prototype (나중에 파생에 관해서도 다루어야겠다)

Every constructor function has a property named prototype.  This property is very useful to declare variables or functions that are common to a particular class.

 

As you've seen above, prototype is an object, therefore, you can add properties to it.  The properties you addedto prototype will become common properties of all objects created using the constructor function

 

  1.           function Fish(name, color)
    {
    this.name=name;
    this.color=color;
    }
    Fish.prototype.livesIn="water";
    Fish.prototype.price=20;
  2.  

  3.           var fish1=new Fish("mackarel", "gray");
    var fish2=new Fish("goldfish", "orange");
    var fish3=new Fish("salmon", "white");
  4.           for (i=1; i<=3; i++)
    {
    var fish=eval("fish"+i); // i'm just getting a pointer to the fish
    alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price);
    }

 

You see that all fish has the livesIn and price property, even though they are not specifically declared on each individual fish.   This is because when an object is created, the constructor function assigns its prototype property to the internal __proto__ property of the new object.  The __proto__ property is used by the object to look for properties. (순서에 대해서도...)

 

You can use prototype to assign functions that are common on all objects, too.  This has the benefit of not having to create and initialize the property every time you construct an object.

 

  1.           function Employee(name, salary)
    {
    this.name=name;
    this.salary=salary;
    }
              Employee.prototype.getSalary=function getSalaryFunction()
    {
    return this.salary;
    }

    Employee.prototype.addSalary=function addSalaryFunction(addition)
    {
    this.salary=this.salary+addition;
    }

 

prototype.gif

 

prototype을 이용한 확장

새로운 객체 클래스를 생성한 것이 아니라 기존 객체 클래스의 기능을 확장한 기능.

메소드에 접근할때 JS엔진은 처음으로 객체 구현에서 찾고 없으면 prototype집합에서 찾고 없으면 해당  변수에서 찾는다.

 

 

 

The new way

You define private functions and variables and return your public variables and functions as properties and methods of an anonymous object:

  1. var classicModulePattern = function(){
      var privateVar = 1;
      function privateFunction(){
        alert('private');
      }
      return {
        publicVar:2,
        publicFunction:function(){
          classicModulePattern.anotherPublicFunction(); 
        },
        anotherPublicFunction:function(){
          privateFunction();
        }
      }
    }();  // the parens here cause the anonymous function to execute and return

    classicModulePattern.publicFunction();

  2.  

 

 

 

 

생성과 체인과 속성

상속은 다른객체의 메소드와 프로퍼티를 새로운 객체에 병합 또는 상속시키는 것이다.  새로운 클래스가 다른 클래스로 부터 상속받은 기능 중의 일부를 재 정의할 수 있기 때문이다.  JS 1.3부터 apply와 call함수를 이용하여 흉내 낼수 있게 되었다.

 

함수를 사용하여 객체를 정의를 하면 이 함수는 곧 객체 생성자가 되고, new 키워드를 생성할 때 호출된다.

  1. theobh = new DivObj(params);

 

apply, call 메소드를 사용하면 다른 객체의 Context 내에서 메소드를 적용하거나 호출할수 있게 된다.

자식 객체 생성자 안에서 사용하면 부모 객체의 모든 프로퍼티와 메소드를 상속 받도록 생성자들을 연결 시킨다.

 

call 메소드의 첫번째 인자는 this 두번째는 인자에는 부모 객체의 생성자에 전달 하려는 인자를 입련한다

obj.call(this, arg1, arg2, ..., argn)

 

apply 메소드에는 두 가지(자식 객체(this), 자식 객체의 인자 배열)를 넘겨 준다.

 

 

 

 

 

 

Object Extend (상속)

extendObject subclass, Object superclass, [Object overrides] ) : void

 

새로운 ExtJS Component를 상속하는 클래스 생성시 사용하게 될 형식.

  1. NewClass = function(arg1, arg2, config) {
       Ext.apply(this,config);
       NewClass.superclass.constructor.call(this);
    };

  2. Ext.extend(NewClass, BaseClass, {
       overriddenFunction: function(arg1,arg2) {
       // code
       },
       newFunction: function(arg) {
       // code
       }
    });

 

  1. SamplePanel = Ext.extend(Ext.Panel, {
        autoHeight: true,
        frame:true,
        collapsible: true,
        cls:'demos',

        afterRender : function(){
            SamplePanel.superclass.afterRender.call(this);
            this.tpl.overwrite(this.body, this);
        },

        tpl : new Ext.XTemplate(
            '<dl>',
                '<tpl for="samples">',
                '<dt><a href="{url}" target="_blank"><img src="shared/screens/{icon}"/></a><br/>',
                    '<span>{text}</span>',
                '</dt>',
                '</tpl>',
            '</dl><div style="clear:both"></div>'
        )
    });

SamplePanel이라는 Panel을 상속하는 클래스 선언.

 

 

Component Model

Component 클래스는 ExtJS 아키텍쳐를 구성하는 가장 기초적인 클래스가 되겠다.  Component는 통합된 모델을 제공하는데 이는 생성, 렌더링, 이벤트 핸들링, 상태 관리, 섬멸등 Ext에서 사용되는 모든 기능들이 여기에 정의 되겠다.

 

  • 명시적 생성자(constructor) 체이닝 및 오버라이딩

    Component는 설정등을 하위 클래스에 적용할수 있도록 기본 생성자를 제공한다.  그리고 initComponent라는 함수를 통하여 커스텀 생성자를 제공하며 체인을 형성하는 상속의 구현을 가능케 하였다.  상속을 받는 클래스들은 initComponent를 통하여 임의로 받은 설정을 통해 안전하고 제데로 구현되겠다.

  • 관리하에 있는 렌더링

    모든 Component들은 즉각 요청되는 렌더링과 파이프라인들을 자동으로 관리 지원한다.  그리고 beforerender와 render 이벤트 등을 통해 더욱 유연하고 맞춤형식 렌더링을 지원한다.

  • 관리하에 있는 섬멸자

    각 Component는 destory라는 함수를 지원하며, Ext 자체가 garbage collection등 현대 사용되지 않는 Component를 자동으로 섬멸해주는 기능을 지원한다.  렌더링과 마찬가지로 beforedestory와 destory 이벤트를 지원하겠다.

  • 자동 상태(state) 관리자

    StateManager 객체가 state Provider를 통해 등록이 되면 각 Component의 설정 및 상태복구 기능을 지원하게 된다.

  • 변함없는 인터페이스 제공

    가장 기초적인 기능인 hiding, showing, enabling 그리고 disabling 을 Component를 통해 제공하며, 이기능들은 오버라이딩 되거나 커스터마이징이 가능하다.

  • ComponentMgr을 통한 유효성

    모든 Component들은 생성될때 ComponentMgr에 등록이 되며 Ext.getCmp('id') 함수를 통해 언제든지 어떤 Component를 불려 들이수 있다

  • Plugin 지원

    어떤 Component들이건 plugin을 통해 확장이 가능하다.  plugin은 Compoent타입을 인자로 받는 init 함수를 지원하는 클래스이다.  plugin은 Component에 plugins 설정을 통해 더해지는게 가능하다.  Component가 생성될때 만약 여러 플러긴이 존재한다면 각 플러긴의 init 함수를 호출하여 Component의 reference값을 보낸다.  각 플러긴은 이를 통해 해당하는 이벤트에 적절한 함추를 호출할수 있게 되겠다.

 

 

Component Life Cycle

주로 Component를 확장하거나 커스터마이즈할때 Component Life Cycle을 참조하라고 하지만 결국에 기본적인 컴포넌트 생성 및 사용에 대해 좀더 좋은 이해가 필요하면 가장 참조 할만한 주제가 될수 있겠다.

 

Component를 기본으로 하는 모든 클래스가 가지는 life cycle이 가지는 가장 중요한 스테이지들에 대해 알아 보도록 하겠다.

 

Initialization

  1. The config object is applied

    Component를 확장하는 클래스들은 생성자 (constructor)를 제공할 필요가 없다.  Component 를 상속하는 클래스에 config을 넘겨 줌으로써서 객체를 생성할수 있겠다. (예제 확인)

  2. The base Component events are created

    Component가 가지는 이벤트 생성: enable, disable, beforeshow, show, beforehide, hide, beforerender, render, beforedestroy, destroy.

  3. The component is registered in ComponentMgr

    Ext.getCmp를 통해 유효한 Component 등록

  4. The initComponent method is called

    Component를 상속받는 클래스 생성시 가장 중요한 부분이 되겠다.  일종의 상속자의 생성자를 구현할때 사용되는 템플레이트라고 생각 할수 있겠다.  상속자의 클래스가 먼저 호출이 되며 Component 클래스까지 거슬러 올라가 superclass.initComponent를 호출하게 된다.  이 함수는 클래스 생성을 손쉽게 해주며 생성자 오버라이딩을 어떤 스텝에서든지 가능케 도와준다.

  5. 상태(state)를 초기화 한다 (존재한다면)

    만약 Component가 상태(state)를 이용한다면 다시 올리도록 한다.

  6. 플러긴을 올린다 (존재한다면)

    만약 Config에 플러긴 사용 여부가 있다면 여기서 초기화 된다.

  7. The component is rendered (존재한다면)

    만약 renderTo 아니면 applyTo가 Config에 설정되어있다면 곧바로 렌더 될것이다.  아니면 Component를 담고 있는 Container가 명령을 하지 않는 이상 렌더 되지 않는다.

 

 

Rendering

  1. The beforerender event is fired

    이부분은 취소될수있는 이벤트이며 핸들러를 부여함으로써 렌더링을 막을수 있는 곳이 되겠다.

  2. The container is set

    container가 지정되어 있지 않다면, Component의 부모 노드의 DOM 객체가 container로 지정이된다.

  3. The onRender method is called

    Component를 상속하는 클래스들한테는 중요한 스텝이 되겠다.  상속자가 렌더링에 필요한 로직을 템플레이트 제공으로 구현 할수 있게씀 도와준다.  생성된 클래스가 먼저 불려들여지고 상속하는 클래스들이 Component 클래스 까지 거슬러 올라가면서 각 superclass.onRender가 호출되게 된다.

  4. The Component is "unhidden"

    많은 Component들은 처음앤 CSS 클래스인 'x-hidden'으로 인해 감추어져있다가 autoShow Config값이 참으로 설정이되면 보이게된다.

  5. Custom class and/or style applied

    Component를 상속하는 모든 상속자들은 config값인 cls와 style을 지원한다.  이를 통해 사용자 정의의 CSS class와 rule이 Component에 존재 하는 DOM 객체에 적용이된다.  CSS의 class는 Component의 markup을 감싸는 바로 윗단의 element에 적용된다.

  6. The render event is fired

    Component가 제데로 렌더 되었다고 알려주는 스텝이며 이 Component의 DOM 객체가 유효화되는 스텝이 되겠다.  만약 이 Component를 렌더링 전에 에세스 시도를 했다면 에러를 발생할 것이다.

  7. The afterRender method is called

    상속 클래스들을 위한 또 다른 템플레이트 형식의 함수가 되겠다.  렌더링후의 로직이 들어가는 부분인되 상속 클래스가 이를 이용하기 위해서는 superclass.afterRender를 이용해야 된다.

  8. The Component is hidden and/or disabled (if applicable)

    hidden 및 disable 설정값이 적용되는 시점이 되겠다.

  9. Any state-specific events are initialized (if applicable)

    상태(state)를 감지하는 Component들이 상태 로딩과 저장을 특정 이벤트로 정의 할수 있는 시점이 되겠다.

 

 

Destruction

  1. The beforedestroy event is fired

    Component가 섬멸되는 것을 취소할수 있는 이벤트가 되겠다.

  2. The beforeDestroy method is called

    상속 클래스들을 위한 또 다른 템플레이트 형식의 함수가 되겠다.  섬멸전의 로직이 들어가는 부분이며 상속 클래스가 이를 이용하기 위해서는 superclass.beforeDestroy를 이용해야 된다.

  3. Element and its listeners are removed

    만약 Component가 렌더된 상태이면 이를 생성하는 Element의 event listeners를 다 제거후 DOM에서 해당 Element가 삭제되는 시점이 되겠다.

  4. The onDestroy method is called

    상속 클래스들을 위한 또 다른 템플레이트 형식의 함수가 되겠다.  섬멸후의 로직이 들어가는 부분이며 상속 클래스가 이를 이용하기 위해서는 superclass.onDestroy를 이용해야 된다.  주의 할점이 있다면 Container 클래스는 자동으로 Container가 가지는 items 콜렉션에 있는 Component를 불러와 destroy하는 onDestroy를 구현하고 있다.

  5. Component is unregistered from ComponentMgr

    Ext.getCmp로 통해 불려 들이지 못하게 된다.

  6. The destroy event is fired

    Component가 완전히 섬멸 되었다는 것을 알리는 시점이 되겠다.

  7. Event listeners on the Component are removed

    Component와 그에 해당하는 event가 따로 분리 되어있어 해당 이벤트가 존재하면 제거하는 시점이 되겠다.

 

 

Component XTypes

 

xtype은 Ext가 2.0으로 되면서 새로 생긴 기능인데 이는 아래와 코드와 같이 직접 버튼 객체를 생성을 안해도 items에 xtype이 정의된 config 값을 주어주는 것만으로 Component를 생성할수 있는것이 되겠다.  최적화를 위해 구현된 기능인데 렌더링 파이프라인에 보내기전에 객체를 생성해서 내 보내지 않아 렌더링 및 오브젝트 생성에 시간 소모를 줄일수 있게 되었다.  이로 인해 메모리 및 리소스를 절약 할수 있게 되었으며 복잡한 레이아웃 생성시 좋은 속도를 보이고 있다.

 

  1. //Explicit creation of contained Components:
    var panel = new Ext.Panel({
       ...
       items: [
          new Ext.Button({
             text: 'OK'
          })
       ]
    };
     
    //Implicit creation using xtype:
    var panel = new Ext.Panel({
       ...
       items: [{
          xtype: 'button',
          text: 'OK'
       }]
    };

 

첫번째 방법은 Panel이 생성되는 시점에서 버튼이 다른 Component들과 만들어 지는데 이로 인해 렌더링이 지연이된다.  두번째 방법에선 버튼이 Panel이 생성되어 브라우저에서 디스플레이되지않는 한 생성되고 렌더 되지 않는다.  만약 Panel이 디스플레이되지 않으면 Button은 생성되지 않으면 어떤 리소스도 소모 하지 않을것이다.

 

BoxComponent

가장 기초가 되는 Component중 하나이며 Component 클래스를 확장하는 클래스가 되겠다.  일정하고 Cross-Browser를 지원하며 렌더가 가능하면서 레이아웃에 사용되는 Component이기도 하다.  크기와 위치를 처리해주는 Component이며 브라우저마다 다른 padding, margins, 그리고 borders를 일정하게 생성되도록해주는 Component가 되겠다.  모든 Container 클래스는 BoxComponent를 상속한다.

 

 

Container Model

Ext2-Container-hierarchy.gif

 

Container

Container는 가장 기초가 되는 Component중 하나인데 다른 Componet들을 담는 Component로 주로 사용이 되겠다.  이 Component는 레이아웃과 렌더링을 다루고 있으며 Component들의 sizing과 nesting을 핸들링한다 그리고 일정하게 container에 component를 담는 메카니즘을 제공하기도 한다.  이 component는 직접적으로 사용되면 안돼는 Component중 하나가 되겠다.

 

Panel

Panel은 Ext 2.0에서 존재하는 Component중에 주력으로 사용되는 Component이며 레이아웃 타스크에서 90%이상 사용된다.   레이아웃 형성을 위하여 보이지 않는 박스로 사용될수 있기도 하다.  UI window 디자인을 위한 가장 기본이 되는 Component이며 window의 위 아래에 존재하는 바에 툴바, 메뉴, 헤더, 풋터, 몸체 등을 더할수 있겠끔 해주는 것이 되겠다.  Panel에는 기본적으로 expandable과 collapsible 그리고 toolbar 기능이 있으며, 다른 툴들을 위해 기본적으로 버튼을 제공한다.  Panel은 Container나 layout에 쉽게 더해질수 있으며 레이아웃과 렌더링 로직은 완전히 Ext가 관리한다.

Ext 2.0의 주력 Component들이며 Panel의 상속 클래스 들이 되겠다.

 

Window

Window는 특별한 Panel인데 floated, minimized/maximized, restored, dragged, 등의 기능을 가진다.  데스크탑에서 사용되는 window 같은 UI를 구현하기 위한 클래스가 되겠다.

 

Viewport

 

Viewport는 유틸리티 Container 클래스 인데 자동으로 document body에 브라우저 치수 사이즈를 맞추어 렌더 된다.  자동으로 resizing과 레이아웃 치수 계산이 되어 full-screen용 어플리케이션 작성시 좋겠다.  주의할점은 viewport는 document.body에 밖에 적용이 안됀다는 것이다.

 

Layouts

Ext2-Layout-hierarchy.gif

 

레이아웃 객체는 new 키워드 통하여 생성되지 않으며 대신 Container에서 내부적으로 생성되고 사용된다.  Container 자체는 레이아웃에 대해 알지 못하며 Container에 들어가는 설정을 통해 모든 레이아웃에 대한 처리가 된다.  Container가 생성될때마다 레이아웃 스타일이나 해당 레이아웃 클래스에 대한 설정을 layoutConfig을 통해 할수 있겠다.  에를 들어:

 

  1.           var panel = new Panel({
                  title: 'My Accordion',
    layout: 'accordion', // The layout style to use in this panel layoutConfig: { animate: true // Layout-specific config values go here } // additional Panel options... });

 

Panel이 Panel 클래스를 담는 레이아웃을 생성할때 주의 해야 할점은 모든 레이아웃에 있는 Panel은 layout 속성이 정의 되어있어야 한다는것이 되겠다. 특별한 레이아웃인 border 아니면 accordian이 아닌 이상 fit을 정의하는게 좋겠다.

 

 

ExtJS를 사용하면서 주의 해야 할점들

 

  • ExtJS 라이브러리 자체가 덩치가 커서 php나 jsp등 페이지 엠베딩 방식으로 사용시 문제가 생김

    • 페이지의 모든 DOM객체가 로딩이 되어야 정상적으로 작동을 함.
    • php나 jsp로 페이지 로딩을 조금이라도 방해하는 문제가 있으면 라이브러리 동작이 정상적이지 않음
  • ExtJS를 사용시 모든 시작은 Ext.onReady 함수안에서 시작이된다 (에서 시작이 아닌 이 함수 인자로 들어가는 모든 것들을 말한다).

    • ExtJS에선 페이지의 모든 DOM객체가 올라온 다음에야 라이브러리가 정상적으로 동작하기에 onReady가 이를 체크해주는 큰 역할을 한다 (그래고 php, jsp에서 다이렉트로 불러지면 작은 딜레이로 인해 망가진다.)
    • 아마도 이벤트 등록 작업도 포함이 되어서 페이지가 다로딩이된후 동작을 원하는거 같다.
  • ExtJS를 사용할라면 프론트와 백엔드를 확실히 나누는 AJAX를 이용해야 한다 (애당초 새로운 프로젝트는 이 기술을 중점으로 써야 한다 동시에 서버쪽 부하를 줄이는데 많은 방법론을 구사할수 있겠다).

 

 

ExtJS를 이용한 Layout표현

trk_layout01 예로 들어 설명.

 

ExtJS를 이용한 AJAX구현

 

Panel의 함수인 load로 페이지를 AJAX로 가져올수 있겠다.

Store용 데이타를 가져올때는 DataProxy를 상속하는 객체들로 AJAX를 이용하여 Data를 가져올수 있다.

 

 

ExtJS Grid

Grid용 Data가 준비되는데까지의 순서

 

Store: a client side cache of Record objects which provide input data for Components such as the GridPanel, the ComboBox, or the DataView

 

 

Data Store

Ext.data.GroupingStore (grouping records by one of the available fields) 를 이용하여 dataset값을 준비함.

순서

Record.create()로 필드 정의 -> proxy( Ext.data.HttpProxy ) or data( Ext.grid.dummyData ) -> reader ( array or json or xml ) -> Record로 변환? -> Store (GroupingStore)

 

하나의 GridPanel 객체를 생성하기 위해 필요한 객체들:

Grid 테이블을 하나 만들기 위해서 여러 객체가 생성되는데 이렇게 세분화하게 된 이유는 데이터를 가져오는 방식이라던지 언제나 다른 필드명과 갯수 그리고 어떤식으로 데이터를 읽어 들이던가등을 세분화 해두면 정의하기 편하고 유연성 있게 프로그램을 디자인 할수 있기 때문이다.

 

 

Ext.data.Record 클래스의 create()함수를 이용하여 데이타 형식을 정의한다.  여기서 필드명 및 형식등을 정의하게 된다.

 

인기있는 페이지 리포트가 가지는 값들을 Ajax로 가져온 후 리더기로 읽어 들일때 사용하는 필드를 정의하는 코드가 되겠다. (서버측에서 데이터를 생성하여 가져오는 방법은 JSON 소개와 함께 나중에 예로 설명을 들도록하겠다).  필드값이 스트링이면 간단히 배얼안에 일치하는 필드 이름만 넣어주어도 된다.

  1. var LoggerData = Ext.data.Record.create([
            { name: 'url_name' },
            { name: 'url' },
            { name: 'hit' },
            { name: 'page_name' },
            { name: 'visit' },
            { name: 'seq' }
        ]);

좀더 Record에 대해 설명 하자면 각 Grid안에 있는 아이템들은 우리가 정의한 필드 값을 가지고 Record 클래스를 이용해 생성된 객체를 이용하여 나타나게 된다. 즉 각 Row가 Record객체라고 생각하면 되겠고 우리가 생성한 LoggerData는 그 틀이라고 생각할수 있다.

 

 

ExtJS는 프론트 페이지와 백엔드를 나눔으로써 더욱 유연성있는 디자인을 구현할수 있기에 Ajax를 이용해 데이타를 가져와서 렌더 해주는 방식을 채택하기로 했다. Grid에서 사용하는 데이타를 가져올때  DataProxy를 계승하는 클래스를 이용해 데이타를 가져오는데 약 세가지정도의 방법이 있다.

HttpProxy, MemoryProxy, ScriptTagProxy 이중에서 HttpProxy를 이용하여 웹상에서 데이타를 가져오는 방법을 표준으로 정해서 사용하도록 하겠다.

 

HttpProxy의 사용 예를 들어 보겠다.

  1. var proxy = new Ext.data.HttpProxy({
                url: 'http://dev9.logger.co.kr/report/trk_sitepages_json.tsp',
                method: 'GET'
            });

 

 

이렇게 해서 가져온 데이터를 어떻게 읽어 드릴지 정의 할수 있는 DataReader에 대해 설명하도록 하겠다.

ExtJS에는 DataReade 계승 하는 세개의 클래스가 있다.

ArrayReader, JsonReader, XmlReader 여기서 우리는 JsonReader기를 이용하여 Ajax로 받아온 값들을 읽어드리기로 하겠다.

그외 DataReader를 계승하는 클래스를 우리가 정의하여 언제든 새로운 데이타 형식을 파싱을 할수 있는 매우 유용한 클래스가 되겠다.

 

  1. var reader = new Ext.data.JsonReader({
                root: 'trk_root',
                // totalProperty: 'totalCount',
                id: 'id'
            }, LoggerData);

여기서 root는 json의 Root 노드 이름을 정의 하는곳이고 id는 받아들인 json 데이타에 값들의 id를 나타내는 필드 이름을 정의하면 된다 (Primary Key 라고 생각해도 무난할듯하다).  LoggerData는 우리가 아까 정의 했던 필드 형식을 답고 있는 객체가 되겠다.  LoggerData 객체에 정의 되어 있는 포멧에 맞추어 데이터가 맵핑이 됨으로 LoggerData 같은 필드 형식을 먼저 정의 해주도록 하자.

 

이제 이렇게 준비된 proxy와 reader객체를 이용하여 Grid용 데이타 형식으로 만들어 주는 Store 클래스에 대해 알아보도록 하겠다. 이 Store 클래스는 GridPanel에서 데이타를 참조 하는데 사용된다.  여기까지 왔으면 왜 이렇게 까지 여러작업을 하여 데이타를 생성하는지 대충 이해 했을거라 생각한다.

 

  1. var store = new Ext.data.Store({
            proxy: proxy,
            reader: reader,
            remoteSort: true
        });

 

우리가 이미 정의 한 proxy와 reader 객체를 각 맞는 필드에 주도록 한다.  여기서 remoteSort 필드가 true일때는 서버측에서 정렬을 하게된다.  Ajax 콜을 할때 추가 파라미터를 더해 던진후 정렬된 데이터를 뿌려주겠는가에 대한 여부를 여기서 정하는 것이다 되겠다.  어떤이유가 있어 클라이언트에서 정령을 못하는 이유가 없는 이상 서버 로드를 줄이기 위해서 클라이언트 쪽에서 정렬를 해주는게 좋은 방침인듯하다.

 

난 필드를 정의를 해주면 자동으로 GridPanel에서 컬럼도 자동으로 생성 해 주는주 알았지만 안타깝게도 데이타 형식과 프레젠테이션 으로 나누어져 있는걸 확인 하였다.  새로운 객체를 ColumnModel에서 생성하여 이를 GridPanel 생성시 Store로 생성한 데이타 객체와 함께 건네 주어야 한다.

이 ColumnModel은 GridPanel객체가 생성될때 각 컬럼을 지정해 주는 객체가 되겠다.

  1. var cm = new Ext.grid.ColumnModel([{
               header: 'Page Name',
               dataIndex: 'page_name',
               width: 420
            },{
               header: "Url Name",
               dataIndex: 'url_name',
               width: 100
            },{
               header: "Hit",
               dataIndex: 'hit',
               width: 70,
               align: 'right'
            },{
               header: "visit",
               dataIndex: 'visit',
               width: 150
            }]);

여기서 4개의 컬럼을 생성하는 뎨제를 설명 하겠다.  ColumnModel 클래스가 constructor로 받아들이는 값은 column config objects들을 담는 배열이 되겠다.  여기서 각 컬럼은 몇가지의 간단한 속성 값으로 정의가 되는데 header가 컬럼 이름이고 dataIndex가 우리가 Store에 저장한 필드값을 이 컬럼에 사용한다는 것이 되겠다.  그외 속성 값들을 본 메뉴얼에서 다루기엔 범위를 넘어서 예제를 보거나 API를 참조 하면서 습득하도록 하겠다.

 

이제 Store 클래스로 생성된 store객체와 ColumnModel로 생성된 cm객체가 준비가 되었으니 GridPanel을 생성하도록 하겠다.

 

GridPanel 생성에 필요한 대부분의 설정은 store와 cm이 담고 있으므로 GridPanel의 프레젠테이션을 설정하는 속성등을 설정해주면 되겠다.

  1. var grid = new Ext.grid.GridPanel({
            region:'south',
            margins: '2 2 2 2',autoExpandColumn: 'url_name',
            store: store,
            cm: cm,
            autoExpandColumn: 'page_name',
            height:350,
            width:400
        });

여기서 store와 cm 속성에 우리가 정의한 store 및 cm값을 설정해 주도록 한다.  region은 만약 BorderLayout을 이용하여 브라우저에 우리가 생성한 Panel 객체들을 표시해주는 경의 정의 하면 된다.  autoExpandColumn은 자동으로 주어진 해당 컬럼에 길이를 자동으로 컬럼 값 길이에 맞추어 늘려준다.

 

렌더링 방법

render()를 호출하여 렌더 하는 방법

Panel 객체로 Viweport나 Panel을 인자로 받는 객체에 인자로 사용.

 

store.load()를 호출하지 않으면 초기 값이 나오지 않으니 store객체가 proxy를 가지고 생성된 후 load()함수를 호출해 주도록하자.

페이징을 사용시 start와 limit값을 정의해 주어야한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Tags

History

Last edited on 01/02/2009 22:51 by saillinux

Comments (1)

  • rich

    많기도 하다. 좋은 사이트 발견 allkorean.net

    03/23/2010 15:29
You must log in to leave a comment. Please sign in.