NOTICE 
올바른 성장과 따뜻한 나눔이 있는 넥스트리
그리드를 그리다 보면 기존 HTML을 이용해서 <thead>를 colspan, rowspan을 이용해서 컬럼을 그룹핑 해줄수 있었다. 그러나 extjs gridpanel에서 방법을 찾다가 해당 플러그인을 찾았다.

실제작성예
사용자 삽입 이미지

소스다운로드



마크업
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Example</title>
<link rel="stylesheet" type="text/css" href="http://techbug.tistory.com/resources/css/ext-all.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all.js"></script>
<script type="text/javascript" src="./GroupHeaderPlugin-HdMenu.js"></script>
<script type="text/javascript" src="./groupingHeader.js"></script>
<script type="text/javascript" src="./00_main.js"></script>
<style type="text/css">
    .ext-ie .x-grid3 table,.ext-safari .x-grid3 table {
          table-layout:auto;
    }
    .ux-grid-hd-group-cell {
          background: #f9f9f9 url(../../resources/images/default/grid/grid3-hrow.gif) repeat-x 0 bottom;
          height:24px;
          border-right: 1px solid rgb(208 208 208) !important;
    }
    .ux-grid-hd-group-nocolspan-cell {
          border-right: 1px solid rgb(208 208 208) !important;
    }
</style>
</head>
<body></body>
</html>


00_main.js
var techbugTestMain = function(){
    return {
        init: function(){

            //그리드판넬 그리기 ----------------------------------------
            this.gridPanel = new mainGridPanel();


            //메인화면 레이아웃 설정-----------------------------------
            this.mainViewPort = new Ext.Viewport({
                layout:'border',
                border:false,
                items:[     this.gridPanel ]
            });
            this.mainViewPort.doLayout();
            this.mainViewPort.syncSize();

        }// End of Init();


    }// End of return
}();
Ext.EventManager.onDocumentReady(techbugTestMain.init, techbugTestMain, true);


groupingHeader.js
mainGridPanel = function(){
    //실제 데이타 들어가기
    var cmm = new Ext.grid.ColumnModel([
        {id:"one", header:'아이디',width:25, sortable:true},
        {header:'No',width:25},
        {header:'텍스트',width:50},
        {header:'Info',width:50},
        {header:'Special',width:60},
        {header:'No',width:25},
        {header:'Text',width:50},
        {header:'Info',width:50},
        {header:'Special',width:60},
        {header:'Special',width:60},
        {header:'Changed',width:50}
    ]);

    //실제 만드는 부분
    cmm.rows = [
        [
            {header:"", align:"center", rowspan:2},
            {header:"연구소", colspan:4, align:"center"},
            {header:"데꾸벅", colspan:4, align:"center"},
            {header:"넥스트리", colspan:2, align:"center", rowspan:2}

        ],[
            {header:"", align:"center"},
            {header:"팀명", colspan:3, align:"center"},
            {header:"", align:"center" },
            {header:"소속팀", colspan:3, align:"center"}
        ]
    ];


    //그리드의 초기설정값을 저장한다.
     mainGridPanel.superclass.constructor.call(this, {
        region: 'center',
        border: false,
        margins:'0 0 0 0',
        cm: cmm,
        width: cmm.getTotalWidth(),
        store: new Ext.data.Store({
            reader: new Ext.data.JsonReader({ //데이타 들어가는 부분
                fields: []
            }),
            data: []
        }),
        enableColumnMove: false,
        enableDragDrop: false,
        enableHdMenu: false,
        height:100,
        view: new Ext.grid.GridView({forceFit:true}),
        title:'Array Grid',
        plugins: new Ext.ux.plugins.GroupHeaderGrid(),
        tbar: [
            {
                text:"저장",
                cls: 'x-btn-icon',
                scope:this,
                handler : function(){alert('저장')}
            }
        ]
    });
};
Ext.extend(mainGridPanel,Ext.grid.GridPanel, { });

GroupHeaderPlugin-HdMenu.js
/**
 *  Plugin for grouped column headers
 *  @class Ext.ux.plugins.GroupHeaderGrid
 *     @extends Ext.util.Observable
 *  @author ?vind Neshaug
 * 
 *  Based on the code in this thread: http://extjs.com/forum/showthread.php?t=12677
 *  Thanks to JEBriggs for starting up the code and resizing code from Clayton
 *  Thanks to JorisA for the idea of making this a plugin instead of an extension.
 * 
 *  Supports infinte number of grouped header rows
 *  Supports header group spanning of rows
 * 
 */
Ext.namespace("Ext.ux.plugins");

Ext.ux.plugins.GroupHeaderGrid = function(config) {
    Ext.apply(this, config);
};
Ext.extend(Ext.ux.plugins.GroupHeaderGrid, Ext.util.Observable, {
    // PLUGIN INIT
    init: function(grid){
        this.grid = grid;
        this.view = this.grid.getView();
        this.cm = this.grid.getColumnModel();
        this.initTemplates();
        this.view.renderHeaders.createInterceptor(this.renderHeaders(),this);
       
        // testing of linking bands up with headers control structure
        //this.linkBandsAndHeaders();
    },
    initTemplates: function(){
        this.view.initTemplates.call(this);
        if(!this.templates.groupedHeader){
            this.templates.groupedHeader = new Ext.Template(
                 '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
                 '<thead>{groupRows}',
                 '<tr class="x-grid3-hd-row">{cells}</tr></thead>',
                 '</table>'
            );
        }
        if (!this.templates.groupRow){
            this.templates.groupRow = new Ext.Template(
                '<tr class="x-grid3-hd-row">{groupCells}</tr>'
            );
        }    
        if(!this.templates.groupCell){
            this.templates.groupCell = new Ext.Template(
                 '<td id="{grId}" class="{cellClass}" rowspan="{rowspan}" colspan="{colspan}"><div class="x-grid3-hd-inner" unselectable="on" style="text-align:{align}">{header}</div></td>'
            );
        }
    },
    renderHeaders : function(cm){
        if (cm){
            this.cm = cm;
        }
        if(!this.cm.rows) {
            return true;
        }
        else {
            this.view.renderHeaders = this.renderGroupedHeaders.createDelegate(this);
           
            this.view.getHeaderCell = this.getHeaderCell.createDelegate(this);
            this.view.updateSortIcon = this.updateSortIcon.createDelegate(this);
            this.view.getColumnWidth = this.getColumnWidth.createDelegate(this);
            this.view.getColumnStyle = this.getColumnStyle.createDelegate(this);
            this.view.getTotalWidth = this.getTotalWidth.createDelegate(this);
            this.view.updateColumnHidden=this.updateColumnHidden.createDelegate(this);
           
            this.view.renderHeaders();
            this.colModel = this.cm;
            this.headerBandLinks = this.linkBandsAndHeaders();
           
            return false;
        }
    },
    renderGroupedHeaders : function() {
        var cm = this.cm;
        var rows = this.cm.rows;
        var groups;
       
        var cellTemplate = this.templates.hcell;

        var cellMarkup = [], sb = [], cellParams = {};
        var groupCellMarkup = [];
        var rowsMarkup = [];
       
        for (var i = 0; i < rows.length; i++) {//create markup for rows
            groups = rows[i];
            for (var j = 0; j < groups.length; j++) {//create markup for group cells
                groups[j].id="ext-ux-gen-"+i+"-"+j;
                groupCellMarkup[groupCellMarkup.length] = this.renderGroupCell(groups[j]);
            }
            rowsMarkup[rowsMarkup.length] = this.renderGroupRows(groupCellMarkup.join(""));
            var groupCellMarkup = [];
        }
        for(var i = 0, len = cm.getColumnCount(); i < len; i++){ // create markup for leaf cells
            cellMarkup[cellMarkup.length] = this.renderHeaderCell(cm, i);
        }
        // use a different template
        return this.templates.groupedHeader.apply({groupRows: rowsMarkup.join(""), cells: cellMarkup.join(""), tstyle:'width:'+this.view.getTotalWidth()+';'});
    },
    renderGroupCell : function(group,groupId) {
        var template = this.templates.groupCell;
        var cellClass;
        var rowspan;
        if (group.colspan < 2 || group.colspan === undefined){
            cellClass = "ux-grid-hd-group-nocolspan-cell";
        }
        else {
            cellClass = "ux-grid-hd-group-cell";
        }
        return template.apply({
            header: group.header,
            colspan: group.colspan,
            align: group.align,
            rowspan: group.rowspan,
            cellClass: cellClass,
            grId: group.id
        });
    },
    renderGroupRows : function(groupCellMarkup) {
        var template = this.templates.groupRow;
        return template.apply({groupCells: groupCellMarkup});
    },
    renderHeaderCell : function(cm,index){
        var template = this.templates.hcell;
        var params = {};
        params.id = cm.getColumnId(index);
        params.value = cm.getColumnHeader(index) || "";
        params.style = this.view.getColumnStyle(index, true);
        if(cm.config[index].align == 'right'){
            params.istyle = 'padding-right:16px';
        }
        return template.apply(params);
    },
    // from gridview, with minor fixes
    getHeaderCell : function(index){
        var hds = this.view.mainHd.select('.x-grid3-cell');
        return (hds.item(index).dom);
    },
    updateSortIcon : function(col, dir){
        var sc = this.view.sortClasses;
        var hds = this.view.mainHd.select('.x-grid3-cell').removeClass(sc);
        hds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);
    },
    getColumnWidth : function(col){
        var w = this.cm.getColumnWidth(col);
        if(typeof w == 'number'){
            return (Ext.isBorderBox ? w : (w-this.view.borderWidth > 0 ? w-this.view.borderWidth:0)) + 'px';
        }
        return w;
    },
    getColumnStyle : function(col, isHeader){
        var style = !isHeader ? (this.cm.config[col].css || '') : '';
        style += 'width:'+this.view.getColumnWidth(col)+';';
        if(this.cm.isHidden(col)){
            style += 'display:none;';
        }
        var align = this.cm.config[col].align;
        if(align){
            style += 'text-align:'+align+';';
        }
        return style;
    },
    getTotalWidth : function(){
        return this.cm.getTotalWidth()+'px';
    },
   
    updateColumnHidden : function(col, hidden){
        var tw = this.getTotalWidth();
        var bands = this.headerBandLinks[col]||[];
        this.view.innerHd.firstChild.firstChild.style.width = tw;

        var display = hidden ? 'none' : '';
       
       
        var hd = this.getHeaderCell(col);
        hd.style.display = display;

        var ns = this.view.getRows();
        for(var i = 0, len = ns.length; i < len; i++){
            ns[i].style.width = tw;
            ns[i].firstChild.style.width = tw;
            ns[i].firstChild.rows[0].childNodes[col].style.display = display;
        }

        for(var i = 0, len = bands.length; i < len; i++){
            var bandId = bands[i];
            var band = Ext.getDom(bandId);
           
            if (hidden){
                if (band.colSpan < 2 || band.colSpan === undefined){
                    band.style.display = 'none';
                }
                else{
                    band.colSpan += -1;
                }
            }
            else{
                if ((band.colSpan < 2 || band.colSpan === undefined)&&band.style.display === 'none'){
                    band.style.display = '';
                }
                else{
                    band.colSpan += 1;
                }
            }
           
           
        }
       
        this.view.onColumnHiddenUpdated(col, hidden, tw);

        delete this.view.lastViewWidth; // force recalc
        this.view.layout();
    },
   
    linkBandsAndHeaders : function(){
   
        var bandsWithHeader;
        var cm = this.grid.getColumnModel();
        var columnCount = this.cm.getColumnCount();
        var headers = new Array(columnCount);
        var headerBands = new Array(columnCount);
        for (var i = 0;i<columnCount;i++){
            headers[i] = i;
        }
        var nrOfRows = cm.rows.length;
        for (var i = 0;i<nrOfRows;i++){
            var headersInRow = cm.rows[i];
            var headersInRowCount = headersInRow.length;
            var headerCounter = 0;
            for (var j = 0;j<headersInRowCount;j++){
                while(headers[headerCounter] === null){
                    headerCounter++;
                }
                if (headersInRow[j].colspan < 2 || headersInRow[j].colspan === undefined){
                    headers[j] = null;
                    var bands = headerBands[headerCounter]||[];
                    bands[bands.length]=headersInRow[j].id;
                    headerBands[headerCounter]=bands;
                    headerCounter++;
                   
                }
                else {
                    for (var k = 0;k<headersInRow[j].colspan;k++){
                        var bands = headerBands[headerCounter]||[];
                        bands[bands.length]=headersInRow[j].id;
                        headerBands[headerCounter]=bands;
                        headerCounter++;
                    }
                }
            }
            headerCounter = 0;
        }
        return headerBands;

    }
});


출처 : extjs forum








이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback :: http://techbug.tistory.com/trackback/60
좋은 정보 감사드립니다. gwt-ext로 개발 중에 있는데 래퍼 클래스로 만들어봐야겠네요 >_<

혹시 그리드 컬럼을 2단으로 만드는 방법은 없을까요....
2008/03/06 11:52
ColumnModel에서 renderer 라는것이 있습니다.
rederer : function(value, p, record){
return String.format('<div class="topic"><strong>{0}</strong></div>', value);}
와 같이 쓰시면 됩니다.

2008/03/06 12:33
GWT-EXT에서는
# private Renderer renderLast = new Renderer() {
# public String render(Object value, CellMetadata cellMetadata, Record record, int rowIndex,
# int colNum, Store store) {
# Date lastPost = record.getAsDate("lastpost");
# String lastPostStr = DateUtil.format(lastPost, "M j, Y, g:i a");
# return Format.format("{0}<br/>by {1}", new String[]{lastPostStr, record.getAsString("lastposter")});
# }
# };
일케 쓰시면 되겠네요

2008/03/06 12:39

제가 이런 구조의 로우들을 구성하려고 하는데 맘처럼 쉽지는 않네요..
이벤트들도 각 컬럼들마다 걸어줘야 하는데.. 흠흠
데꾸뻑 님이 포스팅 해주신 컬럼헤더는 가능한데
한 로우를 구성하려면 ...
헤더쪽 js를 분석해봐야 할 것 같아요 ㅠ_ㅠ...
┌─┬─┬─────┬─┐
│ │ │ │ │
├─┼─┴─────┼─┤
│ │ │ │
└─┴───────┴─┘
(이런형식으로 한 로우를 구성하고 해당 컬럼마다 이벤트를 주려고 하고 있었습니다;;;;;)

아참 혹시 넥스트리 다니시나요??? 제가 아는 분도 거기 다니시는거 같아서요 ㅋㅋㅋ;;;;
2008/03/06 20:59

extjs 의 gridView에서는 colspan이나 rowspan을 지원하지 않습니다.
이참에 Ext.ux 플러그인을 함 만들어 보시는게...
사실 이 포스트에 쓰인 Grouping Header grid도 toolbar위에 여백에 css를 이용하여 그린것 밖에 되지 않습니다.columnModel의 format과 renderer를 적절히 이용하면 가능합니다. ^^ 워낙 노가다라...

잉 누구.....신지..?? ㅡ.,ㅡ; 넥스트리 다니는거 맞습니다... ㅡ.,ㅡ; 흠... 혹시 윤대리 친구???
2008/03/07 00:25

예전에 제가 다니던 회사 팀장님이셨는데요 박석재 팀장님이라고.... 아직도 다니실려나...
명함이 갑자기 생각이 나서요 ㅋㅋㅋ
2008/03/07 11:43
캬캬캬 박차장님 아시는 분이였구낭.. 얼마전에 차장승진하셨는데

2008/03/07 11:59

방금 석재차장님이랑 메신저로 이야기 나누었습니다. ㅎㅎㅎ

UI의 기술이 상당하시다고 소개를 해주셨어요~

미진한 실력이나마 기술을 공유하고 싶어용~~~ 잘 부탁드립니다.
2008/03/07 15:06

 이전  1 ... 555657585960616263 ... 118   다음 

최근댓글
fotowall :: ncloud RSS Feeds today : 20   yesterday : 221
total : 25,049