2009年8月12日 星期三

extjs - Ext.PagingToolbar簡介


隨著records的增加,Browser會花更多的時間在畫grid,Ext.PagingToolbar主要用來處理這樣的問題,透過傳遞參數的方式(start:第幾筆開始,limit:共要幾筆),告知Server要傳送哪些資料。
注意,Ext.PagingToolbar只是告知Server要顯示的資料為何,而Ext.PagingToolbar預設會顯示所有的資料。

因為要讀取Server的資料,所以Store.proxy改用Ext.data.HttpProxy。而讀取的格式我們打算用json,所以,store.reader要用Ext.data.JsonReader。
我們的json file(phone_num.json)如下:
{
    "success": true,
    "results": 12, // how many entry will be sent.
    "rows": [ // *Note: this must be an Array
        { "city": "台北市", "num": "02"},
        { "city": "新竹市", "num": "03"},
        { "city": "苗栗縣", "num": "037"},
        { "city": "台中市", "num": "04"},
        { "city": "南投縣", "num": "049"},
        { "city": "嘉義市", "num": "05"},
        { "city": "台南市", "num": "06"},
        { "city": "高雄市", "num": "07"},
        { "city": "屏東縣", "num": "08"},
        { "city": "台東縣", "num": "089"},
        { "city": "馬祖", "num": "0836"},
        { "city": "烏坵", "num": "082"}
    ]
}

Ext.onReady(function() {
    var cm = new Ext.grid.ColumnModel([
        new Ext.grid.RowNumberer(),
        {
            header: 'City',
            dataIndex: 'city'
        }, {
            header: 'Num',
            dataIndex: 'num'
        }
    ]);

    var store = new Ext.data.Store({
        proxy: new Ext.data.HttpProxy({url: 'phone_num.json'}),
        reader: new Ext.data.JsonReader({
            totalProperty: 'results',
            root: 'rows',
            fields: [{name: 'city'}, {name: 'num'}]
        })
    });
    store.load();

    var grid = new Ext.grid.GridPanel({
        renderTo: Ext.getBody(),
        store: store,
        cm: cm,
        sm: new Ext.grid.RowSelectionModel(),
        viewConfig: {
            forceFit: true
        },
        title: "區碼",
        loadMask: true,
        height: 200,
        width: 330,
        bbar: new Ext.PagingToolbar({
            pageSize: 5,
            store: store,
            displayInfo: true
        })
    });
});


由於,我們在Server-Side都只是把整個資料丟給client,所以,grid即便有Ext.PagingToolbar,但是還是會顯示所有由Server丟過來的資料。

Paging with Local Data
在local paging官方網站上有提到兩種方式:
  1. Ext.ux.data.PagingStore
  2. Paging Memory Proxy(examples/ux/PagingMemoryProxy.js)

根據Ext.ux.data.PagingStore作者的說法,PagingMemoryProxy缺點如下:
  1. You have to write extra code to remote load the data for the proxy.
  2. query, filter and collect only work on the current page. You have to write extra code to use the PagingMemoryProxy filter support.
  3. Local sorting works, but you need to set remoteSort:true. There is no remote sorting support.
  4. Added and removed records are only remembered for the current page.
  5. Changing the page is relatively slow (PagingMemoryProxy reprocesses all data).
檔案下載與詳細討論:
PagingStore.js for ext-js v3
PagingStore.js for ext-js v2

以下是v2的code:
Ext.onReady(function() {
    var cm = new Ext.grid.ColumnModel([
        new Ext.grid.RowNumberer(),
        {header: 'City', dataIndex: 'city'},
        {header: 'Num', dataIndex: 'num'}
    ]);

    var store = new Ext.ux.data.PagingStore({
        proxy: new Ext.data.HttpProxy({url: 'phone_num.json'}),
        reader: new Ext.data.JsonReader({
            root: 'rows',
            totalRecords: 'results',
            fields: [{name: 'city'}, {name: 'num'}]
        })
    });
    store.load({params:{start:0, limit: 4}});

    var grid = new Ext.grid.GridPanel({
        renderTo: Ext.getBody(),
        store: store,
        cm: cm,
        sm: new Ext.grid.RowSelectionModel(),
        viewConfig: {
            forceFit: true
        },
        title: "區碼",
        loadMask: true,
        height: 200,
        width: 330,
        bbar: new Ext.PagingToolbar({
            pageSize: 4,
            store: store,
            displayInfo: true
        })
    });
});


可以看到,Server一樣丟全部的資料,但是Grid已經可以以paging的方式顯示了。


2009年8月11日 星期二

誤用比不會用更可怕


最近因為研究extjs,所以花了些時間去研究一下Java Script, 才發現其實Java Script一直讓人誤解為非常簡單且基本的語言,原來是寫Java Script的大多應用在Web上,而且都只是執行非常簡單的功能,再加上大家都沒有花時間去研究這一語言,造成Java Script成為被誤解最深的語言。後來終於因為Ajax的流行,造成許多的Java Script Library的大量發展(如extjs或jquery),我們才有動力真正的想去了解Java Script。其實速食文化的興起,很多人都想(code)寫得少(function)做得多,很多都是抄來抄去的,根本就沒有去了解整個來龍去脈,進而導致誤用,很多也都沒被發現,甚至還為這個bug做workaround。 不過有時候這問題是沒有找到一本好的書,又是因為那該死的速食文化,造成輕鬆學會xxx或這24hr學會xxx之類的書大賣,而其他的書卻是又貴又不好賣,大師們也就不願意花時間去寫一本好書,更甚者,連課堂上也開始講求短時間內學會哪些東西,上了一個月的C,就可以在園區當RD,拚工時,拚廉價,那麼花大把時間在研究的人怎麼能堪的住哩,又有誰願意花時間去研究,畢竟大家都是夠用就好,而研究是想讓原本的東西更好。 總結上述,當您在使用任何東西時,應該要對其有一定程度的了解,至少先翻翻使用手冊吧,不要一在的抄襲前人的東西,而不知道為何要這樣做。好的書是值得大家支持的,不然好的書會越來越少。

extjs - Ext.grid.EditorGridPanel簡介


Ext.grid.EditorGridPanel繼承自Ext.grid.GridPanel,提供編輯Cell的能力。除了將Ext.grid.GridPanel改變成Ext.grid.EditorGridPanel外,還要設定Ext.grid.ColumnModel的欄位的editor。
Ext.onReady(function() {
    var data = [['Brook', '0921'], ['Rene', '0918']];

    var cm = new Ext.grid.ColumnModel([
        new Ext.grid.RowNumberer(),
        {header: 'Name', dataIndex: 'name',
            editor: new Ext.grid.GridEditor(new Ext.form.TextField())},
        {header: 'Tel', dataIndex: 'tel',
            editor: new Ext.grid.GridEditor(new Ext.form.TextField())}
    ]);

    var store = new Ext.data.Store({
        proxy: new Ext.data.MemoryProxy(data),
        reader: new Ext.data.ArrayReader({},[
            {name: 'name'},
            {name: 'tel'}
        ])
    });
    store.load();

    var grid = new Ext.grid.EditorGridPanel({
        renderTo: Ext.getBody(),
        store: store,
        cm: cm,
        sm: new Ext.grid.RowSelectionModel(),
        viewConfig: {
            forceFit: true
        },
        title: "Brook's address book",
        loadMask: true,
        height: 200,
        width: 330
    });
});



新增/刪除
我們在tbar新增兩個按鈕add/remove,add的流程如下:
  1. 停止grid的編輯。
  2. 接著插入一筆空白的資料到第一列的位置。
  3. 將第一行第一列變成編輯模式。

刪除的流程如下:
  1. 取得所有選取的列。
  2. 反覆的將所有選取列,移到store.removed(暫存起來,不然後面會遺失移除的列)。
Ext.onReady(function() {
    var record = Ext.data.Record.create([
        {name: 'name', type: 'string'},
        {name: 'tel', type: 'string'}
    ]);

    var data = [['Brook', '0921'], ['Rene', '0918']];

    var cm = new Ext.grid.ColumnModel([
        {header: 'Name', dataIndex: 'name', 
             editor: new Ext.grid.GridEditor(new Ext.form.TextField())},
        {header: 'Tel', dataIndex: 'tel', 
             editor: new Ext.grid.GridEditor(new Ext.form.TextField())}
    ]);

    var store = new Ext.data.Store({
        proxy: new Ext.data.MemoryProxy(data),
        reader: new Ext.data.ArrayReader({},[
            {name: 'name'},
            {name: 'tel'}
        ]),
        removed: [] /* 放置移除的列 */
    });
    store.load();

    var grid = new Ext.grid.EditorGridPanel({
        renderTo: Ext.getBody(),
        store: store,
        cm: cm,
        sm: new Ext.grid.RowSelectionModel(),
        viewConfig: {
            forceFit: true
        },
        title: "Brook's address book",
        loadMask: true,
        height: 200,
        width: 330,
        tbar: new Ext.Toolbar(['-', /* '-' 是按鈕分隔符號 */
            {
                text: 'add',
                handler: function() {
                    var r = new record({
                        name: '',
                        tel: ''
                    });
                    grid.stopEditing();
                    store.insert(0, r);
                    grid.startEditing(0,0);
                }
            }, {
                text: 'remove',
                handler: function() {
                    var rows = grid.getSelectionModel().getSelections();
                    for (var i = 0; i < rows.length; i++) {
                        store.removed.push(rows[i]); /* 暫存 */
                        store.remove(rows[i]); /* 移除 */
                    }
                }
            }
        ])
    });
});


修改
Ext.onReady(function() {
    var data = [['Brook', '0921'], ['Rene', '0918']];
    var cm = new Ext.grid.ColumnModel([
        new Ext.grid.RowNumberer(),
        {header: 'Name', dataIndex: 'name',
            editor: new Ext.grid.GridEditor(new Ext.form.TextField())},
        {header: 'Tel', dataIndex: 'tel',
            editor: new Ext.grid.GridEditor(new Ext.form.TextField())}
    ]);
    var store = new Ext.data.Store({
        proxy: new Ext.data.MemoryProxy(data),
        reader: new Ext.data.ArrayReader({},[{name: 'name'}, {name: 'tel'}])
    });
    store.load();
    var grid = new Ext.grid.EditorGridPanel({
        renderTo: Ext.getBody(),
        store: store,
        cm: cm,
        sm: new Ext.grid.RowSelectionModel(),
        viewConfig: {
            forceFit: true
        },
        title: "Brook's address book",
        loadMask: true,
        height: 200,
        width: 330,
        tbar: new Ext.Toolbar([{
            text: 'show modified',
            handler: function () {
                var records = store.getModifiedRecords();
                for (var i = 0; i < records.length; i++) {
                    alert(Ext.encode(records[i].getChanges()));
                }
            }
        }])
    });
});

Ext.grid.EditorGridPanel提供直接編輯Cell的能力,透過store.getModifiedRecords()可以取得修改過的rows,針對修改過的rows可以再透過getChanges()取得修改過的欄位,被修改的cell會出現紅色的標記。


限制輸入
cell通常都是由Ext.form.Field的Subclasses組成,而這些元件都具有regex的property可以限制使用者的輸入,比如regex:/[0-9]/就是限制只能輸入數字,一但輸入格式不對就會出現紅線啦。更多資訊可以參考一下Ext.form.Field。
Ext.onReady(function() {
    var data = [['Brook', '0921'], ['Rene', '0918']];
    var cm = new Ext.grid.ColumnModel([
        new Ext.grid.RowNumberer(),
        {
            header: 'Name', dataIndex: 'name',
            editor: new Ext.grid.GridEditor(
                    new Ext.form.TextField({allowBlank:false}))
        }, {
            header: 'Tel', dataIndex: 'tel',
            editor: new Ext.grid.GridEditor(
                    new Ext.form.TextField({regex:/[0-9]/}))
        }
    ]);
    var store = new Ext.data.Store({
        proxy: new Ext.data.MemoryProxy(data),
        reader: new Ext.data.ArrayReader(
                {},[{name: 'name'}, {name: 'tel'}])
    });
    store.load();
    var grid = new Ext.grid.EditorGridPanel({
        renderTo: Ext.getBody(),
        store: store,
        cm: cm,
        sm: new Ext.grid.RowSelectionModel(),
        viewConfig: {
            forceFit: true
        },
        title: "Brook's address book",
        loadMask: true,
        height: 200,
        width: 330
    });
});




熱門文章