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

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

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

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

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

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



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
 * 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를 변경해보겠다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 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레이아웃으로

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



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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를 준비한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
 ** 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로 가 될 때 한번 호출 되므로 이 때 열려진 패널에 프로그램이

세팅되도록 해보겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
  *  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를 추가합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 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 베니94
Benney Blogs