자바스크립트/Ext JS2012. 12. 16. 21:18

이전 강좌에서 우리는 좌측 panel안에 davaview를 삽입하여 최초 실행 시 dataview내부 첫번째 data가

선택 되도록 코딩하였습니다.

이번에는 선택 된 데이터뷰가 우측 영역에 어플리케이션으로 나오도록 하고 이 어플리케이션에 그리드와

form을 배치하여 보겠습니다.

우선 컨트롤러가 dataview에서 select한 이벤트를 케치할 수 있도록 아래와 같이 구현합니다.

Ext.define('ria.view.Viewport', {
    extend: 'Ext.container.Viewport',
    layout : 'border',
    items: [
    {
        region: 'center',
        // 기존 panel에서 여러개의 패널을 
        // 붙여야 하므로 tabpanel로 변경합니다.
        xtype: 'tabpanel'
    },{
        region: 'west',
        xtype : 'WestTabPanel',
        width: 200
    }]
});


Ext.define('ria.controller.FrameController', {
.
.
.

   init: function() {
        this.control({
            // step1. 좌측 매뉴에 추가된 패널 즉 시스템 패널에 대한 이벤트 추가.
            'WestMenuPanel > WestMenuDataViewPanel': {
                afterrender: this.firstSelect,
                expand: this.onItemClicked
            }, // select이벤트 잡기.
            'WestMenuDataViewPanel > dataview': {
                select: this.onProgramSelect
            }
         });
    },
    onProgramSelect: function(dataview, record) {
        this.onProgramSelect2(record.get('pgm_class'), record.get('title'));
    },
    /***
     * 최종 클래스명과 탭패널에 추가시 추가할 탭이름을 받는다.
     */
    onProgramSelect2: function(pgm_class, title) {
        var centerpanel =  Ext.ComponentQuery.query('viewport container[region="center"]')[0];
        var tab = centerpanel.down('[tabuniqid=' + pgm_class + title + ']');
        if (!tab) {
            // 아래 클래스를 통해 공통 기능을 구현하고 이 클래스의 item으로 인자로 받아온
            // 클래스를 추가하도록 한다.
            tab = Ext.create('ria.view.pgms.CommonPanel',{
            });
            tab.add(Ext.create(pgm_class,{ region : 'center'}));
            tab.title = title;
            tab.tabuniqid = pgm_class+title;
            centerpanel.add(tab);
        }

        centerpanel.setActiveTab(tab);
    },

위에서 ‘ria.view.pgms.CommonPanel은 모든 프로그램들이 공통적으로 동일한 공통 기능을 갖도록 하기 위해 이 클래스를 부모로 사용하도록 하였다. 이 클래스는 로그아웃, 도움말, 검색 등의 공통적인 기능 가지고 있고 구현해야한다.

Ext.define('ria.view.pgms.CommonPanel',{
    extend : 'Ext.panel.Panel',
    alias : 'widget.CommonPanel',
    layout : 'border',
    initComponent: function() {
        var me = this;

        Ext.apply(this, {
            dockedItems: [{
                xtype: 'toolbar',
                dock: 'top',
                items: [
                    { 
                        xtype: 'button', 
                        text: '도움말',
                        action : 'common.help',
                        listeners : {
                            click : function(a){
                                console.log('도움말 호출', me.uniqid);
                            }
                        }
                    },'-',
                    { 
                        xtype: 'button', 
                        text: 'MyPage',
                        action : 'common.help',
                        listeners : {
                            click : function(a){
                                console.log('도움말 호출', me.uniqid);
                            }
                        }
                    },'-',
                    { 
                        xtype: 'button', 
                        text: '로그아웃',
                        action : 'common.help',
                        listeners : {
                            click : function(a){
                                Ext.Msg.confirm('확인', '로그아웃하시겠습니까?', function(btn) {
                                    if(btn == 'yes') {
                                        console.log('도움말 호출', me.uniqid);
                                        Ext.create('Ext.ux.window.Notification', {
                                            position: 'tr',
                                            useXAxis: true,
                                            cls: 'ux-notification-light',
                                            iconCls: 'ux-notification-icon-information',
                                            closable: false,
                                            title: '확인',
                                            html: '로그아웃되었습니다.',
                                            slideInDuration: 800,
                                            slideBackDuration: 1500,
                                            autoCloseDelay: 4000,
                                            slideInAnimation: 'elasticIn',
                                            slideBackAnimation: 'elasticIn'
                                        }).show();
                                    }
                                });
                            }
                        }
                    },'-',
                    {
                        xtype: 'combo',
                        store: Ext.create('ria.store.system.Programs'),
                        displayField: 'title',
                        typeAhead: false,
                        hideLabel: false,
                        fieldLabel: '검색',
                        labelWidth: 40,
                        hideTrigger:true,
                        width: '400',
                        enableKeyEvents: true,
                        minChars: 2,
                        listConfig: {
                            loadingText: '검색 중입니다....',
                            emptyText: '검색어에 맞는 검색 결과가 없습니다.',

                            // Custom rendering template for each item
                            getInnerTpl: function() {
                                return '< h3 >< span >{[Ext.Date.format(values.input_date, "M j, Y")]}< br />by {input_user_name}< /span >{title}< /h3 >' +
                                    '{excerpt}';
                            }
                        },
                        pageSize: 10,
                        listeners: {
                            select: function(a, b) {
                                console.log(a,b)
                            }

                        }

                    }
                ]
            }]
        });
        me.callParent(arguments);
    }
});
이제 위의 CommonPanel안에 들어갈 즉 선택 되어 보여줘야할 어플리케이션을 구현해 보겠습니다.
위의 코드대로 실행하면 에러가 발생할 것입니다. 우선 아래의 json파일을 보겠습니다.
아래 파일은 dataview에 보여지고 있는 프로그램 리스트입니다. 그 중 첫번째 라인을 아래 소스와 같이 
수정합니다.
ria.view.pgms.project.ProjectMgrPanel은 우리가 구현할 프로그램으로 사내 프로젝트를 심플하게 관리하는
프로그램입니다.
/**
 ** Date : 2012.11.30
 ** Desc : 시스템이하 프로그램 리스트 제공
 ** Posn : /json/programlist.json
 **/
{"entitys":[{"pgm_class":"ria.view.pgms.project.ProjectMgrPanel","pgm_icon":"grid","pgm_nm":"나의 과제","title":"나의 과제"},
            {"pgm_class":"ria.view.pgms.RiaAppMain02","pgm_icon":"grid","pgm_nm":"하위 프로그램2","title":"프로그램2"},
            {"pgm_class":"ria.view.pgms.RiaAppMain03","pgm_icon":"grid","pgm_nm":"하위 프로그램3","title":"커뮤니케이션팀"},
            {"pgm_class":"ria.view.pgms.RiaAppMain04","pgm_icon":"grid","pgm_nm":"하위 프로그램4","title":"커뮤니케이션팀"},
            {"pgm_class":"ria.view.pgms.RiaAppMain05","pgm_icon":"grid","pgm_nm":"하위 프로그램5","title":"커뮤니케이션팀"},
            {"pgm_class":"ria.view.pgms.RiaAppMain06","pgm_icon":"grid","pgm_nm":"하위 프로그램6","title":"커뮤니케이션팀"}
            ],
            "errMsg":"","errTitle":"검색결과","message":"","success":true,"totalCount":"2"}



// ria.view.pgms.project.ProjectMgrPanel 구현 하기.
Ext.define('ria.view.pgms.project.ProjectMgrPanel',{
    extend : 'Ext.panel.Panel',
    alias : 'widget.ProjectMgrPanel',
    layout : 'border',
    initComponent: function() {
        var me = this;
        this.callParent(arguments);
    }
});

이제 실행해보면 아래와 같은 모양의 프로그램이 우측 패널에 보여지게 된다.

공통적으로 도움말, MyPage,로그아웃, 검색 등의 기능을 사용할 수 있는 구조이다.

각각의 기능은 나중에 구현하도록 하고 “나의과제”라는 프로그램을 구현해봅니다.

이 프로그램은 좌측에 그리드패널을 그 그리드의 데이터를 select하면 우측의 폼패널이 열리고

해당 과제의 내용을 보여주도록 구현하겠습니다.

/**
 ** Date : 2012.11.30
 ** Desc : 프로젝트 리스트 제공
 ** Posn : /json/projectlist.json
 **/
{"entitys":[{"prj_master_no":"PJ000001","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"},
            {"prj_master_no":"PJ000002","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"},
            {"prj_master_no":"PJ000003","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"},
            {"prj_master_no":"PJ000004","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"},
            {"prj_master_no":"PJ000005","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"},
            {"prj_master_no":"PJ000006","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"},
            {"prj_master_no":"PJ000007","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"},
            {"prj_master_no":"PJ000008","ytree_sgy_dtl_seq":"001","prj_leader":"쥐박이","prj_name":"1원가절감을 위한 공수산정","prj_bgrnd":"추진배경은 .....","prj_target":"프로젝트목표","prj_effect":"프로젝트효과","prj_std_dt":"2012.01.10","prj_end_dt":"2012.12.10","prj_status_cd":"A","prj_status_nm":"결재중","input_user_name":"홍길동","input_date":"2012.01.29"}
            ],
            "errMsg":"","errTitle":"검색결과","message":"","success":true,"totalCount":"340"}
/**
 * Date : 2012.11.30
 * Desc : 프로젝트 정보를 표현할 모델 클래스
 */
Ext.define('ria.model.ProjectMaster', {
    extend: 'Ext.data.Model',   // extend
    fields: [
        'prj_master_no',
        'ytree_sgy_dtl_seq',
        'prj_leader',
        'prj_name',
        'prj_bgrnd',
        'prj_target',
        'prj_effect',
        'prj_status_cd',
        'prj_status_nm',
        'prj_std_dt',
        'prj_end_dt',
        'input_user_name',
        'input_user_id',
        'input_date'
    ]
});

/**
 * Date : 2012.12.14
 * Desc : 프로젝트 리스트
 */
Ext.define('ria.store.project.Projects', {
    extend: 'Ext.data.Store',   // 당연히 store상속
    autoLoad : false,           // 자동 로드는 꺼놓자.
    model: 'ria.model.ProjectMaster',   // 모델은 동일하게 사용 세팅
    proxy: {
        type: 'ajax',
        url: '/json/project/projectlist.json',  
        reader: {
            type: 'json',
            root: 'entitys',
            totalProperty: 'totalCount',
            messageProperty: 'message'
        },
        listeners: {
            exception: function(proxy, response, operation){
                // 나중에 구현할 부분 모든 ajax 통신에 공통으로 쓸 수 있는
                // 에러 캐치 함수를 만들 것이다.
            }
        }
    }
});

Ext.define('ria.view.pgms.project.ProjectListPanel',{
    extend : 'Ext.grid.Panel',
    alias  : 'widget.ProjectListPanel',
    columnLines: true,
    initComponent: function() {
        var me = this;
        var store = Ext.create('ria.store.project.Projects');
        Ext.apply(this, {
            store: store,
            columns: [
            {
                text: '과제번호',
                width : 80,
                dataIndex: 'prj_master_no'
            },
            {
                text: '제목',
                flex : 1,
                dataIndex: 'prj_name'
            },
            { 
                text: '작성자',
                width: 70,
                sortable: false,
                dataIndex: 'input_user_name'
            },
            { 
                text: '시작일',
                width: 70,
                sortable: false,
                dataIndex: 'prj_std_dt'
            },
            { 
                text: '종료일',
                width: 70,
                sortable: false,
                dataIndex: 'prj_end_dt'
            },
            { 
                text: '작성일',
                width: 70,
                sortable: false,
                dataIndex: 'input_date'
            }],
            dockedItems: [
            {
                xtype: 'pagingtoolbar',
                store: store,
                //name : 'fnc003Main01',
                dock: 'bottom',
                displayInfo: true
            }],
            boardLoad : function(){
                me.store.load({             // 아직 로드전이므로 로드한다.이때 json파일 호출
                    params : {
                        km : 'A00000001'
                    }
                });
                //console.log('me.store:::', me.store)
            }
        });
        me.callParent(arguments);
        this.on('render', this.boardLoad, this);
    }
});

Ext.define('ria.view.pgms.project.ProjectMgrPanel',{
        extend : 'Ext.panel.Panel',
        alias : 'widget.ProjectMgrPanel',
        layout : 'border',
        initComponent: function() {
                var me = this;
                Ext.apply(this, {
                        items : [{
                                xtype : 'ProjectListPanel',
                                title : '과제리스트',
                                region: 'center'
                        }]
                });
                this.callParent(arguments);
        }
});

이제 실행해 봅니다. 우측에 프로젝트 리스트 패널이 실행되고 json파일의 내용이 출력되는 것을
확인 할 수 있습니다.

Posted by 1 베니94

댓글을 달아 주세요

  1. ExtJS 초보

    Benney님 작성하신 강좌를 처음부터 따라해보고 있는 초보입니다.
    ria.controller.FrameController 소스 내용 중 centerpanel.setActiveTab(tab); 에서 error가 발생해서 이것저것 삽질하던 중에 이전 강좌에서 ria.view.Viewport의 내용중에 아래와 같이 수정하니 정상동작하는 듯하여 제가 수정한 것이 맞는지 문의드립니다. ^^

    Ext.define('ria.view.Viewport', {
    extend: 'Ext.container.Viewport',
    layout : 'border',
    items: [
    {
    region: 'center',
    xtype: 'tabpanel' <-- 이전강좌에는는 'panel'로 되어 있음.
    <-- title: '중간' 삭제
    },{
    region: 'west',
    xtype : 'WestMenuPanel',
    width: 200
    }]
    });

    친절한 강좌 감사드려요 ^^

    2012.12.18 16:43 [ ADDR : EDIT/ DEL : REPLY ]
    • 아 제가 그부분을 설명 안들렸나보군요.
      처음에는 panel을 사용해서 하나의 프로그램만 띄울수
      있게 했으나 이후에 tabpanel로 변경해서 여러개의 프로그램을
      띄울수 있게 수정했습니다.
      지적하신 부분이 맞습니다. 내용을 좀 수정하도록 하겠습니다.
      감사합니다.^^

      2012.12.19 12:40 신고 [ ADDR : EDIT/ DEL ]
  2. 초보ExtJs

    안녕하세요
    ~ 강좌진행은 계속되시는건가요,.,^^;;
    기다리고있겠습니다.

    2013.01.15 18:23 [ ADDR : EDIT/ DEL : REPLY ]
    • benneykwag@gmail.com

      네 계속하죠 근데 강좌가 중간에 짤렸네요.
      이상합니다. 복구하겠습니다. ㅠㅠ

      가끔 이렇게 리플달아주신 분들이 계셔서
      힘이 납니다.
      직딩이 강좌하는게 이리 어려운건지
      때려치우고 강사나 했으면 좋겠습니다. ㅋㅋ

      2013.01.17 09:24 [ ADDR : EDIT/ DEL ]
  3. 리핀

    안녕하세요 ~
    저역시 배니님의 강좌를 기대하고 있습니다 ~~^^
    화이팅~ 항상 알찬 내용 감사합니다..~
    더불어 질문이 하나 있는데..
    저 같은 경우 xtype : 'WestMenuPanel' 을 'WestTabPanel' 로 변경할 경우
    ext-debug.js 에서 undefined 에러가 나는데.. ext-debug를 호출하는 시점이 언제쯤인지 궁금하여 연락드립니다.

    2013.01.15 18:49 [ ADDR : EDIT/ DEL : REPLY ]
    • 컨트롤러에 WestTabPanel이 명시되어있어야 합니다.
      Ext.define('ria.controller.FrameController', {
      .
      .
      views: ['ria.view.frame.WestMenuPanel',
      'ria.view.frame.WestMenuDataViewPanel',
      'ria.view.frame.WestTabPanel'], // 꼭 명시되어야함, 명시하지 않을 경우 require를 이용해야합.

      감사합니다. ^^

      2013.01.17 10:15 신고 [ ADDR : EDIT/ DEL ]
  4. 초보초보extjs

    안녕하세요.
    시간이 되신다면 서버단 관련해서 샘플 자료 하나 올려주실수 없으신가요.^^;;
    맨땅에 헤딩하려니 너무 힘드네요..ㅠㅠ
    강좌 잘보고 있습니다.

    2013.08.20 18:01 [ ADDR : EDIT/ DEL : REPLY ]

자바스크립트/Ext JS2012. 12. 12. 12:43

이제 어플리케이션의 틀이 완성되었으니 내용을 채울 차례입니다.

아래 그림은 앞으로 만들어볼 화면입니다.

"프로그램"탭에는 자신이 가지고 있는 권한내에서 필요한 프로그램이 보여지고

그 옆 "지식관리"라는 탭은 모두 공통적으로 사용하는 게시판성 프로그램입니다.

각각이 패널과 그리드, 상속관계, 레이아웃, 버튼, PropertyGrid 등의 요소를 포함하고 

있어 좋은 예제로 생각됩니다.

금주내로 아래 프로그램에 대해 강좌를 진행하도록 하겠습니다.


Posted by 1 베니94
TAG extjs, ExtJS4

댓글을 달아 주세요

  1. 최종록

    ^^잘 부탁드립니다.
    혹시 전에 했던 예제는 끝난건가요?

    2012.12.13 13:21 [ ADDR : EDIT/ DEL : REPLY ]
    • 그 예제를 활용해서 쭉 붙여나가는거죠 만들짐 프레임에서 확장한다고 보시면됩니다

      2012.12.13 18:24 신고 [ ADDR : EDIT/ DEL ]
  2. 궁금이

    오.. 궁금해요.. 기다리고있습니다!

    2012.12.13 14:48 [ ADDR : EDIT/ DEL : REPLY ]

자바스크립트/Ext JS2012. 12. 7. 13:23

이번에는 지금까지 코드를 정리 하는 시간을 좀 갖도록 하겠습니다. 실제 시스템을 ExtJS로 구축하도보면 

특히나 MVC모델로 구현할 경우 Controller가 비대해지는 현상이 발생합니다.


이는 MVC를 오해해서 생기는 현상이 아닌가 생각되는데요. MVC에서 V는 View를 의미하는데 이러한 이유로 

View안에는 기능적인 코드가 다 빠져있고 그 것들이 모두 Controller안에 들어가 있게 됩니다. 


Controller역할을 로직의 구현으로 이해하는 경우인것 입니다. 결과적으로 Controller안에 모든 관련 View의 기능이

 구현되어 있고 View는 껍데기만 존재하는 것이죠.


이렇게 비대해진 Controller는 유지보수 입장에서 굉장히 길고 파악하기 힘들게 되고 View자제의 재활용성이 

기능을 포함하지 않은 단순 껍데기만 재활용하게 되어 반쪽짜리 클래스로 전락하게 되는 것이죠.


제 생각이지만 이게 아니라 View은 일종의 클래스 (화면을 기준으로 화면제어 등의 기능이 포함된.)로 생각하고

UI와 그에 따른 제어기능도 포함되도록 해야합니다. 그래야만 재활용 측면에서도 해당 View Class를 가져다 쓸때

 기능도 함께 쓸 수 있게됩니다.


 기능이 모두 Controller에 구현될 경우 재활용은 Controller까지 신경써야하니 활용도가 떨어지게 되는 것입니다.


그래서 아래 코드는 View안에서는 자신과 관련된 기능에 대해 구현을 하고 Controller는 View에서 구현 된 

기능을 함수 단위로 호출 만 하도록 하게끔 리팩토링 작업을 한 것이니 참고하고 봐주시기 바랍니다.


아래 코드의 요점은 Controller에 구현된 로직을 각 뷰 클래스로 옮기고 Controller에서는 함수단위로 호출만

 하도록 변경한것입니다.


// app/controller/FrameController.js 를 수정한다.
// views, refs, onLaunch를 확인하자.
Ext.define('ria.controller.FrameController', {
    extend: 'Ext.app.Controller',
    //stores: ['system.Systems'],
    views: ['ria.view.frame.WestMenuPanel',
            'ria.view.frame.WestMenuDataViewPanel'], // 꼭 명시되어야함, 명시하지 않을 경우 require를 이용해야합.
    refs: [
            {ref: 'westMenu', selector: 'WestMenuPanel'}
        ],
    init: function() {
    	this.control({
    		// step1. 좌측 매뉴에 추가된 패널 즉 시스템 패널에 대한 이벤트 추가.
    		'WestMenuPanel > WestMenuDataViewPanel': {
    			afterrender: this.firstSelect,
    			expand: this.onItemClicked
            }
         });
    },
    /**
     *  step2. afterrender는 추가된 패널 별로 render된 이후에 호출한다.
     *	추가된 시스템 패널 중에 열려 있는지 확인하면 맨처음 하나만 열리게 된다.
     *	그 열려있는 시스템 패널에 하위 프로그램이 로딩되어 추가될 수 있도록 코딩해야한다.  
    **/
    firstSelect : function(panel){
    	panel.firstSelectDataView();
    },
    /**
     * Step3. 시스템 패널을 클릭 할 때 마다 expand이벤트가 호출 된다.
     * 이 때 클릭되어 expand된 패널 위에 하위 프로그램을 출력하면 된다.
     * @param a
     * @param b
     * @param c
     */
    onItemClicked : function(panel){
    	panel.onItemClicked();
    },
    onLaunch: function() {
        this.getWestMenu().setWestMenuDataViewPanel();
    }
});

// app/view/frame/WestMenuDataViewPanel.js 를 생성한다.
Ext.define('ria.view.frame.WestMenuDataViewPanel',{
    extend: 'Ext.panel.Panel',
    alias: 'widget.WestMenuDataViewPanel',
    animCollapse : true,
    collapsible : true,
    collapsed   : true,
    useArrows: true,
    rootVisible: false,
    multiSelect: false,
    initComponent: function() {
    	var me = this;
        Ext.apply(this, {
            items: [{
                xtype: 'dataview',
                trackOver: true,
                cls: 'feed-list',
                itemSelector: '.feed-list-item',
                overItemCls: 'feed-list-item-hover',
                tpl: '
{pgm_nm}

' }], header: { toolFirst: true }, /*** * Date : 2012.12.06 * Desc : dataview상에 출력된 리스트 중에 맨처음 프로그램이 * 선택되어지도록 한다. * @param store */ firstSelectDataView : function(){ if(me.collapsed) return; var store = this.onItemClicked(); if(store){ var task = new Ext.util.DelayedTask(function(){ me.down('dataview').getSelectionModel().select(store.getAt(0)); }); task.delay(1000); } }, /** * Step3. 시스템 패널을 클릭 할 때 마다 expand이벤트가 호출 된다. * 이 때 클릭되어 expand된 패널 위에 하위 프로그램을 출력하면 된다. * @param a * @param b * @param c */ onItemClicked : function(){ if(me.collapsed) return // 패널이 접히지 않은 놈을 찾는다. if(me.store) return; me.store = Ext.create('ria.store.system.Programs'); // 재활용 되는 것을 막는다. me.store.load({ params: { // 아래 코드는 시스템 패널이 가지고 있는 시스템 아이디를 프로그램 store에 전달하는 // 코드다 이렇게 해야 각기 시스템 패널별로 해당 시스템 이하의 프로그램을 가져올수 있다. pgm_syscd: this.pgm_syscd } }); // 최종 시스템 패널 안으 dataview에 프로그램 store를 바인딩 한다. me.down('dataview').bindStore(me.store); return me.store; } }); this.callParent(arguments); } }); // app/view/frame/WestMenuPanel.js를 추가합니다. Ext.define('ria.view.frame.WestMenuPanel',{ extend : 'Ext.panel.Panel', alias : 'widget.WestMenuPanel', layout:'accordion', // 이놈 하위에 추가될 dataview또한 accordion collapsible: true, split:true, title : '^^', activeItem: 0, initComponent: function() { var me = this; Ext.apply(this, { /*** * Date : 2012.12.07 * Desc : 최초 첫번째 프로그램 선택. */ setWestMenuDataViewPanel: function(){ var store = Ext.create('ria.store.system.Systems'); store.load(function(record, b, c){ // 아직 로드전이므로 로드한다.이때 json파일 호출 store.each(function(rec){ // store를 탐색하여 me.add({ // 메뉴가 추가될 패널에 아래와 같이 패널을 추가. xtype:'WestMenuDataViewPanel', title:rec.get('pgm_sysnm'), // 시스템명 pgm_syscd:rec.get('pgm_syscd'), // 시스템 코드 iconCls:rec.get('pgm_sysicon') // 아이콘이 있다면 표기 }); }); }); } }); this.callParent(arguments); } });

이제 프로그램을 다시 확인해보면 동일하게 작동하는 것을 알수 있습니다. 앞으로는 Controller에 기능을 구현하고 구현된 기능을 어디로 옮겨야할지 생각해 본 후 각 뷰클래스등에 구현하므로해서 코드의 밸런스를 맞춰가도록 하겠습니다.


Posted by 1 베니94

댓글을 달아 주세요

자바스크립트/Ext JS2012. 11. 30. 14:52

이번에는 이전 강좌에서 좌측 메뉴를 완성해보겠다.

좌측 메뉴는 이전강좌에서 panel을 하나 추가하여 "사용자 관리"라는 메뉴를 하나

강제로 생성 시켰다. 이번에는 ajax를 통해 메뉴정보를 가져올 수 있도록 store를 구성하고

해당 store에서 값을 가져와 메뉴를 구성하기까지 과정을 알아보자.

아래 그림처럼 store와 model폴더에 파일을 만들어 놓자.



/**
 * Date : 2012.11.30
 * Desc : 프로그램 정보를 표현할 모델 클래스
 */
Ext.define('ria.model.system.Program', {
	extend: 'Ext.data.Model',	// extend
    fields: [
		'pgm_id',
		'pgm_nm',
		'pgm_syscd',
		'pgm_sysnm',
		'pgm_class',
		'pgm_icon',
		'pgm_sysicon',
		'group_id',
		'group_nm',
		'group_status_cd',
		'group_status_nm',
		'group_pgm_status_nm'
    ]
});

/**
 * Date : 2012.11.30
 * Desc : 좌측 시스템 리스트
 * 		  여기서 중분류 정도의 시스템 리스틀 가져온다.
 */
Ext.define('ria.store.system.Systems', {
    extend: 'Ext.data.Store',	// 당연히 store상속
	autoLoad : false,			// 자동 로드는 꺼놓자.
    model: 'ria.model.system.Program',	// 모델 세팅
	proxy: {
        type: 'ajax',
        // json폴더를 루트에 만들고 systemlist.json이라는 파일를 통해 
        // 시스템 리스트를 받을 수 있다.
        url: '/json/systemlist.json',	
        reader: {
        	type: 'json',
        	root: 'entitys',
        	totalProperty: 'totalCount',
        	messageProperty: 'message'
        },
        listeners: {
            exception: function(proxy, response, operation){
            	// 나중에 구현할 부분 모든 ajax 통신에 공통으로 쓸 수 있는
            	// 에러 캐치 함수를 만들 것이다.
			}
	    }
    }
});
// 이제 위의 store에서 호출하는 json파일을 만듭니다.
// 현재는 아래와 같이 만들어져 있지만 실제로는 디비의 값을 가져와 이 파일의 내용을 출력하도록
// 만 서버쪽 개발만 하면 클라이언트쪽은 호출주소외에 전혀 손댈때가 없게 됩니다.
/**
 ** Date : 2012.11.30
 ** Desc : 시스템 리스트 제공
 ** Posn : /json/systemlist.json
 **/
{"entitys":[{"pgm_syscd":"F001","pgm_sysicon":"grid","pgm_sysnm":"거래처관리"},
			{"pgm_syscd":"F002","pgm_sysicon":"grid","pgm_sysnm":"영업일지"},
			{"pgm_syscd":"F003","pgm_sysicon":"grid","pgm_sysnm":"서류관리"},
			{"pgm_syscd":"F004","pgm_sysicon":"grid","pgm_sysnm":"통보서관리"},
			{"pgm_syscd":"F005","pgm_sysicon":"grid","pgm_sysnm":"현황관리"},
			{"pgm_syscd":"F007","pgm_sysicon":"grid","pgm_sysnm":"실적관리"},
			{"pgm_syscd":"S002","pgm_sysicon":"grid","pgm_sysnm":"패키지관리"}],
			"errMsg":"","errTitle":"검색결과","message":"","success":true,"totalCount":"8"}




이제 위에서 만들어진 store, model, json파일 등을 이용해서 좌측 메뉴가 나올 수 있도록 Controller를 변경해보겠다.
// app/controller/FrameController.js 를 수정한다.
// views, refs, onLaunch를 확인하자.
Ext.define('ria.controller.FrameController', {
    extend: 'Ext.app.Controller',
    stores: ['system.Systems'],
    views: ['ria.view.frame.WestMenuPanel',
            'ria.view.frame.WestMenuDataViewPanel'], // 꼭 명시되어야함, 명시하지 않을 경우 require를 이용해야합.
    refs: [
            {ref: 'westMenu', selector: 'WestMenuPanel'}
        ],
    init: function() {
        this.control({
             
        });
    },
    onLaunch: function() {
        // refs의 ref명으로 뷰를 찾아온다.
        var menu = this.getWestMenu();
        var store = this.getStore('system.Systems'); 	// store를 호출
        store.load(function(record, b, c){				// 아직 로드전이므로 로드한다.이때 json파일 호출
        	store.each(function(rec){		// store를 탐색하여
			    menu.add({					// 메뉴가 추가될 패널에 아래와 같이 패널을 추가.
			    	xtype:'WestMenuDataViewPanel',
			    	title:rec.get('pgm_sysnm'),	// 시스템명
			    	fnc_pgm_syscd:rec.get('pgm_syscd'),	// 시스템 코드
			    	iconCls:rec.get('pgm_sysicon')	// 아이콘이 있다면 표기
			    });
			});
        });
    }
});

// 위에서 사용한 메뉴 패널
// app/view/frame/WestMenuPanel.js를 추가합니다.
Ext.define('ria.view.frame.WestMenuPanel',{
    extend  : 'Ext.panel.Panel',
    alias   : 'widget.WestMenuPanel',
    layout:'accordion',	// 이놈 하위에 추가될 dataview또한 accordion
    collapsible: true,
    split:true,
    title : '^^',
    activeItem: 0,
    initComponent: function() {
         
        this.callParent(arguments);
    }
});
이제 실행해보자. 아래와 같이 좌측에 시스템리스트가 보일 것이다.


이제 추가된 시스템 패널 중에 열려 있는 패널이 어떤 패널인지 확인 해보자. westMenuPanel에 panel이 accodion레이아웃으로

추가되었으므로 그중 열려 있는 놈을 찾는 것이다.



Ext.define('ria.controller.FrameController', {
.
.
.
    init: function() {
    	this.control({
    		// step1. 좌측 매뉴에 추가된 패널 즉 시스템 패널에 대한 이벤트 추가.
    		'WestMenuPanel > WestMenuDataViewPanel': {
    			afterrender: this.firstSelect,
    			expand: this.onItemClicked
            }
         });
    },
    /**
     *  step2. afterrender는 추가된 패널 별로 render된 이후에 호출한다.
     *	추가된 시스템 패널 중에 열려 있는지 확인하면 맨처음 하나만 열리게 된다.
     *	그 열려있는 시스템 패널에 하위 프로그램이 로딩되어 추가될 수 있도록 코딩해야한다.  
    **/
    firstSelect : function(panel){
    	console.log('추가된 시스템 패널', panel.xtype, panel.title, panel.collapsed);
    	if(!panel.collapsed){
    		// accordion 레이아웃에 패널이 추가되면 디폴트로 맨처음 패널이
    		// 패널이 펼쳐져 있게 되고 이놈을 찾아서 해당 시스템 이하의 프로그램을 불러올 수 있도록 코딩한다.
    		console.log('추가된 시스템 패널 중 접히지 않은 패널 :', panel.title, panel.collapsed);
    	}
    },
    onItemClicked : function(a, b, c){
    	console.log(a,b,c);
    },

콘솔에 출력해 보면 좌측 시스템 패널중에 열려 있는 패널은 "거래처관리"라는 것을 알 수 있다.

다음으로는 추가된 패널을 클릭 했을 때 즉 현재는 click이 아니라 expand이벤트 이므로 이 이벤트가 전달하는 arguments가 뭔지 알아보자. doc.sencha.com에서 아래와 같이 api를 확인해 보자. 역시나 expand이벤트 또한 panel객체 자기자신을 전달하고 있다.


이제 expand이벤트를 구현할 함수 (onItemClick)을 구현해 보자.

프로그램 store를 준비한다.



/**
 ** Date : 2012.11.30
 ** Desc : 시스템이하 프로그램 리스트 제공
 ** Posn : /json/programlist.json
 **/
{"entitys":[{"pgm_class":"ria.view.pgms.RiaAppMain01","pgm_icon":"grid","pgm_nm":"하위 프로그램1"},
			{"pgm_class":"ria.view.pgms.RiaAppMain02","pgm_icon":"grid","pgm_nm":"하위 프로그램2"},
			{"pgm_class":"ria.view.pgms.RiaAppMain03","pgm_icon":"grid","pgm_nm":"하위 프로그램3"},
			{"pgm_class":"ria.view.pgms.RiaAppMain04","pgm_icon":"grid","pgm_nm":"하위 프로그램4"},
			{"pgm_class":"ria.view.pgms.RiaAppMain05","pgm_icon":"grid","pgm_nm":"하위 프로그램5"},
			{"pgm_class":"ria.view.pgms.RiaAppMain06","pgm_icon":"grid","pgm_nm":"하위 프로그램6"}
			],
			"errMsg":"","errTitle":"검색결과","message":"","success":true,"totalCount":"2"}

/**
 * Date : 2012.11.30
 * Desc : 좌측 시스템 이하 프로그램 리스트
 * 		  여기서 최하위 단 프로그램 리스트를 가져온다.
 */
Ext.define('ria.store.system.Programs', {
    extend: 'Ext.data.Store',	// 당연히 store상속
	autoLoad : false,			// 자동 로드는 꺼놓자.
    model: 'ria.model.system.Program',	// 모델은 동일하게 사용 세팅
	proxy: {
        type: 'ajax',
        // json폴더를 루트에 만들고 programlist.json이라는 파일를 통해 
        // 시스템 리스트를 받을 수 있다.
        url: '/json/programlist.json',	
        reader: {
        	type: 'json',
        	root: 'entitys',
        	totalProperty: 'totalCount',
        	messageProperty: 'message'
        },
        listeners: {
            exception: function(proxy, response, operation){
            	// 나중에 구현할 부분 모든 ajax 통신에 공통으로 쓸 수 있는
            	// 에러 캐치 함수를 만들 것이다.
			}
	    }
    }
});

// 이하 컨트롤러의 onItemClicked 함수 구현
    /**
     * Step3. 시스템 패널을 클릭 할 때 마다 expand이벤트가 호출 된다.
     * 이 때 클릭되어 expand된 패널 위에 하위 프로그램을 출력하면 된다.
     * @param a
     * @param b
     * @param c
     */
    onItemClicked : function(panel){
    	var store ;
    	if(!panel.collapsed){	// 패널이 접히지 않은 놈을 찾는다.
    		// 아래 코드를 보면 시스템 패널은 dataview를 가지고 있다. 이 dataview는
    		// 해당 패널이 가지고 있는 시스템 아이디에 해당하는 프로그램을 표현하게 된다.
    		// dataview는 expand될 때 하위 프로그램을 가져오도록 했기 때문에 
    		// 이미 가져왔다면 다시 서버에 로드 되지 않도록 한다. 굳이 매번 쓸데없이
    		// 서버에 다녀오지 않게 하기 위함.
    		if(panel.down('dataview').store.getTotalCount() > 0) return;
    		// 아래 코드에서는 Ext.create를 사용하였다.
    		// 이는 컨트롤러에 아래 스토어를 명시하지 않았기 때문인데 명시하지 않은 것은.
    		// 프로그램 리스트 store가 시스템별로 여러개 존재하므로 컨트롤러에 명시할 경우
    		// 모든 시스템 패널이 동일한 프로그램을 보게 되므로 각기 다르게 생성하여
    		// 공유하지 못하도록 하기 위함이다.
    		store = Ext.create('ria.store.system.Programs');	// 재활용 되는 것을 막는다.
	    	store.load({
	    		params: {
	    			// 아래 코드는 시스템 패널이 가지고 있는 시스템 아이디를 프로그램 store에 전달하는
	    			// 코드다 이렇게 해야 각기 시스템 패널별로 해당 시스템 이하의 프로그램을 가져올수 있다.
	    			pgm_syscd: panel.pgm_syscd
	    		}
	    	});
	    	// 최종 시스템 패널 안으 dataview에 프로그램 store를 바인딩 한다.
	    	panel.down('dataview').bindStore(store);
	   	}
	   	return store;
    },
이제 실행하고 열려 있지 않은 패널을 클릭하여 열어보도록 한다. 그럼 시스템 패널에 프로그램들이 출력 되는 것을 볼 수 있다.
크롬에 개발자 도구를 꼭 사용해야 한다.


그런데 최초에는 거래처 관리에 프로그램이 비어 있다. 클릭 하고 다시 클릭하면 프로그램이 보이지만 처음엔 보이지 않는다.

이 부분은 firstSelect 함수에서 해결해 보자. 이 함수는 afterrender로 가 될 때 한번 호출 되므로 이 때 열려진 패널에 프로그램이

세팅되도록 해보겠다.


   /**
     *  step2. afterrender는 추가된 패널 별로 render된 이후에 호출한다.
     *	추가된 시스템 패널 중에 열려 있는지 확인하면 맨처음 하나만 열리게 된다.
     *	그 열려있는 시스템 패널에 하위 프로그램이 로딩되어 추가될 수 있도록 코딩해야한다.  
    **/
    firstSelect : function(panel){
    	console.log('추가된 시스템 패널', panel.xtype, panel.title, panel.collapsed);
    	if(!panel.collapsed){
    		// accordion 레이아웃에 패널이 추가되면 디폴트로 맨처음 패널이
    		// 패널이 펼쳐져 있게 되고 이놈을 찾아서 해당 시스템 이하의 프로그램을 불러올 수 있도록 코딩한다.
    		console.log('추가된 시스템 패널 중 접히지 않은 패널 :', panel.title, panel.collapsed);
    		
    		// Step4. 
    		// 이제 시스템 패널이 rendering된 후에 열려있는 맨처음 시스템 패널에 프로그램이 자동세팅되도록 해야한다.
    		// expand이벤트를 통해 클릭 시마다 프로그램이 추가되지만 맨처음 시스템 패널은 비어 있으므로 채우도록 코딩한다.
    		// onItemClicked함수는 시스템 패널의 dataview에 store를 바인딩하는 기능을 한다. 
    		var store = this.onItemClicked(panel); 
    	}
    },



이제 main.html파일을 열고 하위프로그램에서 사용할 css를 추가합니다.


// main.html
    < script type="text/javascript" src="app.js" >< /script >
    < style type="text/css" >
	    .feed {
			width: 16px;
			height: 16px;
			background-image: url(/common/images/icon/rss.gif) !important;
		}
		.feed-picker-url {
			 float: left;
			 width: 425px;
		}
		.feed-picker-title {
			/*    float: left;*/
			 color: #777;
			 font-size: 10px;
		}
		.feed-list {
		 	padding: 0 3px 0 3px;
		}
		.feed-list-item {
			 margin-top: 3px;
			 padding-left: 20px;
			 font-size: 11px;
			 line-height: 20px;
			 cursor: pointer;
			 background: url(/common/images/icon/rss.gif) no-repeat 0 2px;
			 border: 1px solid #fff;
		}
		.feed-list .x-item-selected {
			 font-weight: bold;
			 color: #15428B;
			 background-color: #DFE8F6;
			 border: 1px dotted #A3BAE9;
		}
		.feed-list-item-hover {
			
		}
    < /style >
< /head >
< body >


이제 프로그램에 예쁘게 css가 적용되었다. ^^


Posted by 1 베니94

댓글을 달아 주세요

  1. jongoks

    작성해주신 글 너무나도 유용하게 잘 보았습니다.
    그런데 전 그대로 따라했는데 CSS가 제대로 안먹히는 이유는 어떤이유일까요? ;;
    .feed-list .x-item-selected 이부분도 안되는 것 같고, feed-list-item도 안되어서 feed-list-itemgrid로 고치니 반영되네요..
    css 적용하기 위해 .x-item-selected 이런 클래스들이 생기는 건 어떤 문서를 봐야 알 수 있는 부분인가요?
    혹시 시간 되실때 답변도 주시면 감사합니다. ^^

    2013.01.17 16:07 [ ADDR : EDIT/ DEL : REPLY ]
  2. benneykwag@gmail.com

    소스를 아예 올려드려야겠어요
    좀만 기다려주세요

    2013.01.18 09:04 [ ADDR : EDIT/ DEL : REPLY ]
  3. choiys6031@naver.com

    Extjs4 학습중에 많은 도움얻고있습니다.
    궁금한점이 있는데
    store.load({
    params: {
    // 아래 코드는 시스템 패널이 가지고 있는 시스템 아이디를 프로그램 store에 전달하는
    // 코드다 이렇게 해야 각기 시스템 패널별로 해당 시스템 이하의 프로그램을 가져올수 있다.
    pgm_syscd: panel.pgm_syscd
    }
    })
    위소스에서 store(Programs.js) 에 파라미터로 pgm_syscd 를 넘기고 있는데 실제 store에서는 pgm_syscd 값을 어떤방법으로 얻을수 있나요?

    2013.08.14 13:04 [ ADDR : EDIT/ DEL : REPLY ]
  4. lee

    이것좀 봐주세요
    Ext.onReady(function(){
    var selNodeObj=null;


    var store = Ext.create('Ext.data.TreeStore', {
    id: 'store',
    autoHeight:true,


    autoLoad: false,
    // autoSync: true,
    root :{
    text : '프로젝트명',
    name : '1단',
    expanded : false,
    },
    proxy : {
    type : 'ajax',
    api: {
    read : '/auto/tree/json/jsonobject.do',
    create: '/auto/tree/EgovTreeCreateInsert.do',
    update: '/auto/tree/EgovTreeCreateUpdate.do',
    destroy: '/auto/tree/EgovTreeCreateDelete.do'

    },
    reader: {
    type: 'json',
    successProperty:'success',
    rootProperty: 'children',
    // rootProperty: 'items',
    messageProperty:'message'
    // ,root:'tree'
    }
    ,writer:{
    type:'json',
    writeAllFields:true,
    // root:'auto'
    encode:true,
    rootProperty:'children'
    }

    },
    listeners: {



    }







    });

    var tree = Ext.create('Ext.tree.Panel', {
    title: '에스제이테크시스템',
    id: 'tree',
    rootVisible: true,
    multiSelect: true,
    store: store,
    viewConfig: {
    plugins: {
    ptype: 'treeviewdragdrop',
    enableDrag: true,
    enableDrop: true
    }
    },
    multiSelect: true,
    plugins: 'cellediting',
    columns: [{
    header:'프로젝트명',
    xtype: 'treecolumn',
    dataIndex: 'text',
    flex: 1,
    editor: {
    xtype: 'textfield',
    allowBlank: false,
    allowOnlyWhitespace: false
    }
    },{header:'합계',dataIndex:'disable',flex:1, editor: {
    xtype: 'textfield',
    allowBlank: false,
    allowOnlyWhitespace: false
    },width:500}],
    renderTo: Ext.get('treeList'),
    listeners:{
    itemcontextmenu : function( object, record, item, index, e){
    e.stopEvent();
    var menu = Ext.create('Ext.menu.Menu',{
    items : [
    {
    text: '추가',
    handler: onItemClick,
    iconCls: 'icon-edit'
    },
    {
    text: '삭제',

    handler: onItemClick
    }
    ]
    });
    menu.showAt(e.getXY());
    }
    }

    });
    function onItemClick(item){
    node = store.getNodeById("Node1");
    var treePanel = Ext.getCmp('tree');
    if(item.text=='삭제'){

    var record = treePanel.getSelectionModel().getSelection()[0];
    record.remove(true);
    store.sync();

    }else if(item.text=='추가'){


    var selNode = treePanel.getSelectionModel().getSelection()[0];
    selNodeObj=selNode;
    var appendedChild = selNode.appendChild({
    // task: 'Task1',
    // user: 'Name',
    // duration: '10',
    text : '추가',
    name : '1단',
    leaf: true
    });
    var newRecords = store.getNewRecords();
    Ext.each(newRecords, function(record,index){
    console.log('New (',index,')',record.get('name'));
    });
    store.sync();

    }

    }

    });

    여기서 proxy를 사용했는데요 아래에 api를 지정하고 하면 삭제시에 destroy 수정시 update, 트리 추가시에 create롤 타겠끔 할려고 합니다 어떻게 해줘야 타는지요 ?

    이것에 대한 방법을 아시면 메일로 좀 보내주세요
    ldongkyu@hanmail.net 입니다
    감사합니다

    2015.07.15 12:32 [ ADDR : EDIT/ DEL : REPLY ]

자바스크립트/Ext JS2011. 12. 22. 23:39
오늘 부터 연재할 글은 Sencha사이트의 내용을 기준으로 ExtJs를 설명하도록 하겠습니다.
(http://docs.sencha.com/ext-js/4-0)


1. Requirements


1.1. Web Browsers
Ext JS 4는 IE6에서 크롬까지 모든 브라우저를 지원한다. 뭐 모두 지원한다고 하지만 실제로는 아시는분은 아시겠지만 IE계열이 제일 형편없고 나머지 크롬이나 FF에 경우는 상당히 좋은 성능을 내고 있습니다.
IE6에 경우에는 아예 포기하는 것이 좋습니다. 저의 경우도 고객에게 IE6는 절대 사용하면 안되는 브라우저로 설득하고 꼭 업데이트 하여 최소 IE7도 아니고 IE8을 사용하도록 권고 아닌 강제하고 있습니다. 뭐 고객이 할아버지 일 경우도 있어서 아무리 강제해도 말을 듯지 않는 경우도 있습니다

1.2. Web Server
웹서버에 경우 뭘 쓰든 상관이 없습니다. Apache보다는 톰캣을 설치? 아니 설치하지 마시고 파일로 받아 압축 푸시고 사용하시는게 좋겠죠. 따로 설명하지 않겠습니다. 별게 없으니까요!!
1.3. Ext JS 4 SDK
일단 아래 주소에서 다운 받아 설치하자
http://www.sencha.com/products/sdk-tools/download/

  
2. Application Structure

2.1. Basic Structure
강제 사항은 아니지만 ExtJS 의 디렉토리 구조는 아래와 같이 하라고 권고 하고 있다.

- Document Root 
- app
       - Class1.js
       - Class2.js
- extjs
- resources
      - css
      - images
      - ... 

- app.js

- index.html


일단 Document Root아래 index.html을 생성하고 아래와 같이 코딩하자.

<html>
<head>
    <title>Hello Ext</title>

    <link rel="stylesheet" type="text/css" href="/resources/css/ext-all.css">
    <script type="text/javascript" src="/ext-debug.js"></script>
    <script type="text/javascript" src="app.js"></script>
</head>
<body></body>
</html>

이제 app.js를 아래와 같이 코딩합니다.

Ext.application({
    name: 'HelloExt',
    launch: function() {
        Ext.create('Ext.container.Viewport', {
            layout: 'fit',
            items: [
                {
                    title: 'Hello Ext',
                    html : 'Hello! Welcome to Ext JS.'
                }
            ]
        });
    }
});

우선 코드를 실행합니다. 뷰포트위에 패널을 올리고 패널이름은 'Hello Ext'이고 패널의 내용부분에 'Hello! Welcome to Ext JS'라고 보여집니다.
이제 빌드를 해보겠습니다. 위에서 설치한 Sencha SDK가 정상적으로 설치되어 있어야 합니다.
확인은 cmd창에서 sencha라고 입력해보자.  아래와 같이 보여지면 정삭적으로 설치된것입니다.

Sencha Command v1.2.2

Copyright (c) 2011 Sencha Inc.


usage: sencha COMMAND [ARGS]


The available commands are:

   build                build a JSB project

   create jsb           generate a minimal JSB project for an application

   slice theme          slice a custom theme's images for IE


See 'sencha help COMMAND' for more information on a specific command.

 
빌드 전에 jsb파일을 생성하자. index.html파일이 있는 폴더로 이동해서 아래와 같이 실행하자.
index.html파일을 검사하고 관련 된 클래스등을 참조하여 jsb3파일을 만들게 됩니다.

D:\AppTeam\03_Project\02_eMarket\01_DevRoot\extDesigner\war\study>sencha create jsb -a http://localhost:8080/study/index.html -p app.jsb3

 
이제 jsb3파일을 이용해 빌드 작업을 해봅니다.

sencha build -p app.jsb3 -d .

 
이제 위의 작업을 실행한 폴더에 아래와 같은 두개의 파일이 생성되는 것을 볼수 있습니다.
1. all-classes.js  이 파일은 어플리케이션에서 사용할 클래스들을 모아놓는다. 현재는 비어 있을 것이다.
2. app-all.js 이 파일은  열어보시면 알겠지만 우리가 코딩한 app.js를 최소화 버전으로 만들어 은 것이다. 실제 배포시에는 이런식에 공백을 제가한 최소화빌드를 하게 되고 더 나아가면 최적화를 해서 용량을 더 줄이기도 한다.

기존 index.html파일을 카피하여 index-prod.html을 만들고 빌드 된 app-all.js파일을 이용해 실행해 보자.

<html>
<head>
    <title>Hello Ext</title>

    <link rel="stylesheet" type="text/css" href="/resources/css/ext-all.css">
    <script type="text/javascript" src="ext.js"></script>
    <script type="text/javascript" src="app-all.js"></script>
</head>
<body></body>
</html>

동일한 실행 결과를 얻을 것이다. 

'자바스크립트 > Ext JS' 카테고리의 다른 글

Ext JS 4.1 beta Doc 어플리케이션 분석1  (0) 2011.12.30
Ext JS 4.1 Beta 출시  (0) 2011.12.30
[ExtJS4] Gestting Started  (0) 2011.12.22
ExtJS 기반 시스템 구성도  (2) 2011.10.05
ExtJS4 모바일 스크롤 문제 해결  (1) 2011.10.04
Extjs AutoID  (0) 2011.08.13
Posted by 1 베니94
TAG Ext JS4, extjs

댓글을 달아 주세요

자바스크립트/Ext JS2011. 10. 5. 22:21
지난 9월 1차 오픈된 시스템의 시스템 구성도이다.
ExtJS를 UI프레임웍으로 정하고 3달 정도 고생해서 완성된 시스템이다. 아직도 수개월을 더 고생해야 하지만.

개인적으로 ExtJS는 흥미로운 구석이 아주 많은 놈이지만 마냥 믿고 쓰기에는 아직 우리 현실에 어울리지
 않거나 버전 4의 자질구레한 버그를 감뇌해야 한다.

Gxt (GWT+EXT)에 비해서 성능은 떨어지지만 핸들링 면에서 java기반의 Gxt보다는 잇점이 많은 듯하다.

그러나 GWT기반 개발에 경우 최종 컴파일된 소스를 운영단에 넘겨 ExtJS(최적화 하지 않은 상태)와 성능을
비교하면
상대적으로 GWT App가 훨씬 & 상당히 빠른 성능을 보인다. 이는 아마도 GWT가 컴파일 시
상당히 뛰어난
최적화 작업을 하여 결과물을 토해 난다는 결론이다.
ExtJS또는 최적화가 가능하지만 개인적인 생각이나 최적화를 아무리 잘해도 GWT보다는 못할 듯 하다.

시간 날 때 강좌나 하나 해보려고 한다. ... Gxt 강좌도 못하고 있는지라 뭐가 우선인지는 모르지만
휘발되기 전에 남겨 두어야 할텐데...

'자바스크립트 > Ext JS' 카테고리의 다른 글

Ext JS 4.1 Beta 출시  (0) 2011.12.30
[ExtJS4] Gestting Started  (0) 2011.12.22
ExtJS 기반 시스템 구성도  (2) 2011.10.05
ExtJS4 모바일 스크롤 문제 해결  (1) 2011.10.04
Extjs AutoID  (0) 2011.08.13
store에 object 삽입  (0) 2011.08.10
Posted by 1 베니94
TAG extjs

댓글을 달아 주세요

  1. goodJY

    안녕하세요..extJS를 배우려고 써칭 하다가 들르게 되었는데요...
    저는 이제 막 개발 입문하는 사람으로.. 신기술에 대한 관심이 많은데요..
    궁금한게 너무 많은데... 너무 혼자 끙끙앓기도 그렇고.. 조금은 배울수 있는 루트를 찾고자 합니다..
    혹시 가르침을 주실수 있는지..~~ㅠㅠ~

    2012.02.15 22:50 [ ADDR : EDIT/ DEL : REPLY ]
  2. 글쎄요 어찌 드려야할지 .. ㅋㅋ
    우선 예제를 모두 풀어보세요 하나하나 그리고 전체 어플리케이션 구조를
    파악하기 위해 feed viewer같은 어플리케이션을 분석해보면 좀 어찌 돌아가는지 알수 있을 겁니다.
    다른 궁금한거나 도와드릴게 있으시면 애기해주세요..
    저두 뭐 많이 알지 못하지만 알려드릴께요 ^^

    2012.02.19 21:55 신고 [ ADDR : EDIT/ DEL : REPLY ]

자바스크립트/Ext JS2011. 10. 4. 19:57

요구사항 : 고객은 현재 개발 된 시스템(Extjs기반)이 모바일에서도 작동되게 해달라고 한다.
               그러나 PC버전이 모바일(갤탭)에서 잘 돌아가리란 보장이 없는 관계로 테스트를 해보던 중
               결정적으로 스크롤 특히 그리드가 문제가 생겼다. PC에서는 우측 스크롤과 하단 스크롤이 
               보이지만 모바일로 넘어가면 스크롤이 없어지고 데이터가 묻혀버리는 현상이 발생한다.
               이 부분을 해결하기 위해서 구글링을 한 결과 2가지 대안을 찾았다. 

대안 1 : 모바일일 경우 Ext의 그리드를 override하여 터치모드로 작동되도록 변형할 수 있다.
           아래 링크를 통해 확인 할 수 있다. 아래 링크를 갤탭에서 실행하면 터치기능이 작동된다.
http://www.rahulsingla.com/sites/default/files/content/blog/extjs-iscroll/scrolling-ext-containers-on-touch-devices.htm
          소스를 잠깐 보면 Panel, Tree, Grid를 override하고 있다. 이렇게 되면 공통 js에 아래코드를 넣고 사용한다면
           모든 프로그램에 아래 내용이 적용되어 모바일에서는 자동으로 좌우스크롤이 생성되고 터치 기능으로 작동이 가능하다.
           직접 실행해보면 상당히 괜찮을 결과를 얻을 수 있다. 이는 모바일에서 사용되는 iScroll모듈을 Extjs에 적용한 것이다.
           인도 친구 인것 같은데 아이디어가 좋은 것 같다. 그러나 문제가 한가지 있다. 우리 시스템은 ExtJs4기반이고 아래
           소스는 Extjs3버전이다. 그래서 마이그레이션해서 버전을 올려보려 했으나 결정적으로 아래소스에서 보듣이
           Extjs3버전에서는 스크롤의 아이디가 '.x-grid3-scroller'로 정해져 있으나 ExtJS4에서는 이부분이 AutoId로 되어 있어
           스크롤 영역을 특정짓지 못하게 된다. 결국 삽질을 거듭하다 포기하고 다른 대안을 찾도록 했다.
			Ext.isiPad = navigator.userAgent.match(/iPad/i) != null;
			Ext.isiPhone = navigator.userAgent.match(/iPhone/i) != null;
			//TODO: Add support for more devices like Android etc. here.
			Ext.isMobileDevice = Ext.isiPad || Ext.isiPhone;

			///////////////////////////////////////////////////////////
			//iScroll Overrides
			Ext.override(Ext.Panel, {
				afterRender: Ext.Panel.prototype.afterRender.createSequence(function() {
					if (this.getXType() == 'panel') {
						this._getIScrollElement = function() {
							return (this.el.child('.x-panel-body', true));
						}
					}

					//Uncomment below to use iScroll only on mobile devices but use regular scrolling on PCs.
					if (this.autoScroll /*&& Ext.isMobileDevice*/) {
						if (this._getIScrollElement) {
							this._updateIScroll();
							this.on('afterlayout', this._updateIScroll);
						}
					}
				}),

				_ensureIScroll: function() {
					if (!this.iScroll) {
						var el = this._getIScrollElement();
						if (el.children.length > 0) {
							this.iScroll = new iScroll(el);
							this.iScrollTask = new Ext.util.DelayedTask(this._refreshIScroll, this);
						}
					}
				},

				_updateIScroll: function() {
					this._ensureIScroll();
					if (this.iScroll) {
						this.iScrollTask.delay(1000);
					}
				},

				_refreshIScroll: function() {
					this.iScroll.refresh();
					//Refresh one more time.
					this.iScrollTask.delay(1000);
				}
			});

			Ext.override(Ext.tree.TreePanel, {
				_getIScrollElement: function() {
					return (this.el.child('.x-panel-body', true));
				}
			});

			Ext.override(Ext.grid.GridPanel, {
				_getIScrollElement: function() {  // 아래 부분이 Extjs에서 그리드위에 생성되는 스크롤이다. 
					return (this.el.child('.x-grid3-scroller', true)); // 이부분이 스크롤 된다.
				},

				afterRender: Ext.grid.GridPanel.prototype.afterRender.createSequence(function() {
					//TODO: need to hook into more events and to update iScroll.
					this.view.on('refresh', this._updateIScroll, this);
				})
			});


대안 2 : 최초 고객은 두손가락 스크롤을 원했다. 즉 패드종류에서는 기존의 스크롤 대신 두 손가락으로 슬적 밀면 스크롤이 되도록
            지원하고 있다. 개인적으로 절대 이 기능으로 실사용자들이 만족하지 못할 거라는 판단하에 이부분을 첨부터 알아보지
            않고 대안1에 치중하였으나 대안1이 어려우니 이거라도 구현해주려고 한다.
            일단 이 것이 가능하려면 약간 수정 해줘야 한다. 아래의 autoScroll부분이 true일 경우 모바일에서 두손가락 스크롤이
            가능하다.
    createGridPanel: function(){
        this.gridPanel = Ext.create('widget.EmStock.gridPanel', {
            region: 'center',
            store : this.store,
            pageSessionId : this.pageSessionId,
            floatable: false,
            defaults:{ autoScroll:Ext.isiPad || Ext.isiPhone },  // 이 부분이 꼭 필요하다. 패드나 폰일 경우 true를 리턴한다. 갤탭일 경우 그냥 true
            padding: '10 0 0 0',
            totalCount : this.totalCount, 
            split: 	true,
            listeners: {
                scope: this,
                ongridselect: this.onGridSelect,
                columnhide : this.onColumnHide,
                refreshgrid : this.refreshGrid
            }
        });
        
        return this.gridPanel;
    },

'자바스크립트 > Ext JS' 카테고리의 다른 글

[ExtJS4] Gestting Started  (0) 2011.12.22
ExtJS 기반 시스템 구성도  (2) 2011.10.05
ExtJS4 모바일 스크롤 문제 해결  (1) 2011.10.04
Extjs AutoID  (0) 2011.08.13
store에 object 삽입  (0) 2011.08.10
extjs4 무한 스크롤 (infinite scroll)  (0) 2011.08.07
Posted by 1 베니94
TAG extjs, scroll

댓글을 달아 주세요

  1. 그리드 컬럼헤드가 같이 따라가지 않는 문제가 있네요!~
    방법을 찾아야겠습니다.

    2011.10.05 17:37 신고 [ ADDR : EDIT/ DEL : REPLY ]

자바스크립트/Ext JS2011. 6. 22. 10:12
익스플로러에서 extjs를 테스트하다 사파리에서는 보이지 않던 에러를 보였다.
구글링과 삽질을 좀 한 결과 코딩을 좀 변경해주므로서 해결되었다.


// 최초 소스에 Model을 정의한 부분이 있는데 이부분을 밖으로 빼주니 잘 동작한다.
Ext.define('FeedViewer.App', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.FeedViewer',
    height:600,
    initComponent: function(){
        // feed model 정의
        Ext.define('Feed', {
            extend: 'Ext.data.Model',
            fields: ['title', 'pgm']
        });
		
        // viewport item set
        Ext.apply(this, {
            layout: 'border',
            //padding: 5,
            items: [ this.createFeedPanel()]
        });
       
        this.callParent(arguments);
    },

///////////////////////////////////////////
 // feed model 정의
Ext.define('Feed', {
    extend: 'Ext.data.Model',
    fields: ['title', 'pgm']
});

Ext.define('FeedViewer.App', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.FeedViewer',
    height:600,
    initComponent: function(){
         // viewport item set
        Ext.apply(this, {
            layout: 'border',
            //padding: 5,
            items: [ this.createFeedPanel()]
        });
       
        this.callParent(arguments);
    },
Posted by 1 베니94
TAG extjs

댓글을 달아 주세요

  1. Dick subculture is exactly what the majority of the jerkdescribed as younger rebellion and also distinct sartorial variations オロビアンコ 財布 http://www.queenbei.net/ オロビアンコ 財布 新作,ポーター バッグ 新作 2014 http://www.raceweb.org/ ポーター バッグ 新作 2014, ガガミラノ 店舗 http://www.brazelsa.com/ ガガミラノ 時計 レディース 人気,コーチ バッグ メンズ http://www.southernsandstonepublishing.com/ コーチ アウトレット,グローブトロッター JET http://www.cargofortright.com/ グローブトロッター アウトレット,オークリー メガネ http://www.kenadkinsquarterhorses.com/ オークリー サングラス 人気,trend in addition to punk hair styles rely on. This handles the particular varieties of outfits, makeup products,オロビアンコ 財布 新作 [url=http://www.queenbei.net/]オロビアンコ バッグ メンズ[/url] オロビアンコ 時計, hair-styles, body customization and in many cases jewelry. You will find broad variesinvolving fashions which might be existing through the Vivienne Westwood variations for the ガガミラノ 時計 メンズ 新作 [url=http://www.brazelsa.com/]ガガミラノ 時計 レディース[/url] ガガミラノ 店舗,variations circumstance modeled about dissimilar rings such as Spotted. コーチ 財布 [url=http://www.southernsandstonepublishing.com/]コーチ バッグ メンズ[/url] コーチ 財布,Typically the jerk vogue can also be unjust グローブトロッター サファリ [url=http://www.cargofortright.com/]グローブトロッター バッグ[/url] グローブトロッター JET,from many other cultures as well as fine art movements like the skinheads,rozzo boys, glam stone, greasers, skill institution scholars and also emotional balance.オークリー メガネ 新作 [url=http://www.kenadkinsquarterhorses.com/]オークリー サングラス 人気[/url] オークリー サングラス, Jerk Hair Styles are usually exceptionally prejudiced from the Punk customs with the 1970s.ポーター 財布 メンズ [url=http://www.raceweb.org/]ポーター 財布 メンズ[/url] ポーター 財布 メンズ, Jerk subculture is usually and also a wide selection of anti-authoritarian ideologies.オロビアンコ 時計www.queenbei.net オロビアンコ 財布,ポーター 財布 メンズwww.raceweb.orgポーター 財布 メンズ, ガガミラノ 時計 レディース 人気www.brazelsa.comガガミラノ 時計 メンズ 新作,コーチ アウトレットwww.southernsandstonepublishing.com コーチ バッグ,グローブトロッター バッグwww.cargofortright.comグローブトロッター アウトレット,オークリー アウトレットwww.kenadkinsquarterhorses.comオークリーゴルフStrange reductions, stunning appearance and also use of wild colors are the typical popular features of A-hole hair-styles.

    2014.05.30 15:15 [ ADDR : EDIT/ DEL : REPLY ]
  2. Wearing their full capacity Harrods-sponsored clothes, トゥミ バッグ http://www.photographybyanacia.com/ トゥミ 財布,all these poochesトゥミ 財布 [url=http://www.photographybyanacia.com/]tumi アウトレット[/url] トゥミ バッグ, are generally bent about altering the catwalk to a dog wander. アナスイ 財布 http://www.logbarnoutfitters.com/ アナスイ バッグ,What アナスイ アウトレット [url=http://www.logbarnoutfitters.com/]アナスイ バッグ 2014[/url] アナスイ アウトレット,could you assume during the Harrods Puppy Vogue March? Toxic combination celebrations. オロビアンコ 財布 http://www.onlyjav.com/ オロビアンコ 時計,Ahead of start of dog manner indicate, most people are handled オロビアンコ バッグ メンズ [url=http://www.onlyjav.com/]オロビアンコ 時計[/url] オロビアンコ バッグ,for their complete regarding champagnes along with cheese. Naturally , the celebrities from the present gained continue to serve us just yet because they will be backstage getting yourself ready for their particular dogwalk as soon as possible. オロビアンコ バッグ メンズ http://www.lakesofjolliff.com/ オロビアンコ アウトレット,Special variety of high-classオロビアンコ アウトレット [url=http://www.lakesofjolliff.com/]オロビアンコ 時計[/url] オロビアンコ バッグ メンズ, puppy outfits. If you wish to catch the most up-to-date as well as the trendiest doggy outfits accessible, ensure not to miss the particular Harrods style display. フルラ バッグ http://www.tuckaleecheeapiaries.com/ フルラ 財布,Your canine outfits comprisesフルラ バッグ [url=http://www.tuckaleecheeapiaries.com/] フルラ 財布 2014[/url] フルラ 財布, models by Vivienne Westwood and Rob Lauren. You can also become the very first to select the freshest types サマンサタバサ アウトレット http://www.woolrich-tactical.com/ サマンサタバサ バッグ 新作, manufactured by Succulent サマンサタバサ バッグ 新作 [url=http://www.woolrich-tactical.com/] サマンサタバサ アウトレット[/url] サマンサタバサ バッグ 人気,Disposition as well as Puppia. Puppy luggage. Lastly, put on miss to buying several fabulous サマンサタバサ バッグ 人気 http://www.humidorcigarclub.com/ サマンサタバサ バッグ 新作, doggy hand bags サマンサタバサ アウトレット [url=http://www.humidorcigarclub.com/] サマンサタバサ アウトレット[/url] サマンサタバサ バッグ 人気,all of via Harrods. That they have each of the most ポーター 新作 2014 http://www.gc3online.org/ ポーター アウトレット,deluxe products for ones doggie, ポーター アウトレット [url=http://www.gc3online.org/] ポーター 財布 メンズ[/url] ポーター 財布 メンズ, such as the must-haves in the year.

    2014.06.03 23:26 [ ADDR : EDIT/ DEL : REPLY ]
  3. 이용약관위배로 관리자 삭제된 댓글입니다.

    2014.07.11 19:28 [ ADDR : EDIT/ DEL : REPLY ]

자바스크립트/Ext JS2011. 5. 16. 10:33
// 아래의 함수에서 전달받는 인자는 extjs에 정의된 인자들이다 . 이렇게 extjs가 
// 정의하고 전달하는 인자가 무엇인지 궁금할 경우 arguments를 아래 처럼 이용하면 
// 좋을 듯 하다.
/**
 *** Grid에 renderer를 설정한다. 위치는 onReady밖에 있어도 상관없음.
 *** 아래 함수는 Grid내 column의 renderer에서 호출하게 된다. 기본 7개 인자넘김.
 *** Ext.grid.column.Column 참고할 것.
 */	
function renderTopic(value, p, record, rowIndex , colIndex , store, view) {
	for(var i=0; i< arguments.length; i++)
   		console.log(arguments[i]);
    		//console.log(rowIndex, colIndex, store.data.items[0], view);
		//console.log( view);
        	return Ext.String.format(
            	'{0}{1} Forum',
            	value,
            	record.data.forumtitle,
            	record.getId(),
            	record.data.forumid
        );
}
Posted by 1 베니94
TAG extjs

댓글을 달아 주세요

자바스크립트/Ext JS2011. 5. 15. 16:34
java 환경
- 버전 : 1.6X  여기를 클릭하여 다운로드 받고 아래의 환경변수를 설정하도록 압축풀고 카피해 넣자.
- 환경변수 : JAVA_HOME  / C:\Program Files\Java\jdk1.6.0_20

이클립스 환경
다운로드 :
helios로 다운받고 아래를 참고하여 aptana플러그인을 설치하자.

http://cafe.naver.com/javachobostudy.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=52330&social=1
위의 게시물 중 apnata를 설치하는 과정까지만 하자. 즉 "이클립스 재시작"까지만 하고 다음은 
플러그인 파일을 eclipse / dropins 폴더에 카피하자. 폴더가 없다면 만들자.

플러그인 다운받기

이클립스 재실행하고 window->preferences -> Aptana -> Editors -> Javascript -> Code Assist -> Ext 3.2.1를 체크하자.

뭐 4.0이 있었으면 좋겠지만 이거라두 있은게 어딘가~~ 걍 써보자.

다음 기본 프로젝트 설정이다 모두 통일하도록 하자.

1. 프로젝트 생성하기
    - File -> New -> other -> Web -> Dynamic Web Project -> eMarketWeb -> Next ->
      Default output folder를 war/WEB-INF/classes -> Web Module의 Content directory를 war로 변경하고
      Generate web.xml deployment descriptor에 체크 -> Finish
   
2. Text fild encoding 변경
  - 프로젝트 root에서 마우스 우측 클릭하고 Properties -> Resource -> Text file encoding -> Other -> UTF-8 -> Ok

3. 톰캣 설치는 아래에서
http://blog.naver.com/bench87?Redirect=Log&logNo=90111051568






Posted by 1 베니94
TAG extjs

댓글을 달아 주세요