2014年2月5日 星期三

ASP.NET MVC 4 WebApi 與 Extjs 的結合 -- Combo 連動

兩個或更多的下拉式選項要做資料連動,前提就是要在這兩份資料必須要有關聯,不管是一對多還是多對一。

以往在做 WebForm 的時候,如果碰到要下拉選單連動的時候,都要在每次選項切換時,再去和資料庫撈一次資料,如果伺服器是自己的那倒無所謂,如果是使用雲端,使用多少算多少的計費方式,就不得不去計較小細節,因為這小細節很可能會變成大費用。

最理想的情況下,就是將連動的資料在 API 內就先做好,然後在頁面載入時,跟 API 要資料,也只要這麼一次,往後不管怎麼變動,都與資料庫無關。

所以現在就使用 Extjs 來實現 Combo 連動:

在此之前,若未建立資料庫和基本配置,請先參考 Visual Studio 2012 安裝 Northwind 資料庫並建立 Entity Framework Database First ( .edmx ) 以及 ASP.NET MVC 4 WebApi 與 Extjs 的結合 -- 基本配置

建立 Controller API

使用 Northwind 資料庫內產品類別和產品的一對多關聯的特性,來產生資料:
public class CategoriesController : BaseApiController
{
    public IEnumerable<Categories> Get()
    {
        var categories = db.Categories.Include(x => x.Products);

        foreach (Categories category in categories)
        {
            foreach (Products product in category.Products)
                product.Categories = null;
        }

        return db.Categories.AsEnumerable();
    }

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}

資料格式為:

建立 Ext Model

必須要注意兩個屬性 hasMany 和 belongsTo,記得要對應好,hasMany 可以想成是這些資料要去連動哪個 Model,belongsTo 資料要依據哪一個 Model 來產生。來看程式碼就會知道了:
Ext.define('Category', {
    extend: 'Ext.data.Model',
    fields: [
        'CategoryID', 'CategoryName'
    ],
    hasMany: { model: 'Product', name: 'Products' }
})

Ext.define('Product', {
    extend: 'Ext.data.Model',
    fields: [
        'ProductID', 'ProductName'
    ],
    belongsTo: 'Category',
})

接著將資料放到 Ext.data.JsonStore 物件內,請注意:產品資料內容不需要建立
var storeCategory = Ext.create('Ext.data.JsonStore', {
    storeId: 'storeCategory',
    model: 'Category',
    proxy: {
        type: 'ajax',
        url: 'http://localhost/api/Categories/',
        reader: {
            type: 'json',
        }
    },
    // 自動載入
    autoLoad: true, 
    listeners: {
        // sotre load 完成後載入這個fucntion  
        load: function (store, records, options) {
            
        }
    },
})

var storeProduct = Ext.create('Ext.data.JsonStore', {
    storeId: 'storeProduct',
    model: 'Product',
})

建立欄位

這裡與上面的 Ext.data.JsonStore 有關聯,為什麼不建立產品資料內容?就是要等選擇後再建立。

combobox 內有監看 ( listeners ) 事件,就等於 WebForm 的事件一樣,選擇後,先將產品下拉式選單清空,再將此資料下的 Product 資料放進去。

[
    {
        xtype: 'combobox',
        fieldLabel: '類別',
        name: 'Category',
        //queryMode: 'local',
        store: storeCategory,
        editable:false,
        valueField: 'CategoryID',
        displayField: 'CategoryName',
        listeners: {
            select: function (combo, record, index) {
                // raw 取得選取的資料
                var tempProducts = record[0].raw.Products; 
                // 清空 product combobox 的store
                storeProduct.removeAll();
                for (var i = 0; i < tempProducts.length; i++) {
                    // 加到 product combobox 的store
                    storeProduct.add(tempProducts[i]); 
                }
            }
        }
    },
    {
        xtype: 'combobox',
        fieldLabel: '產品',
        queryMode: 'local',
        name: 'Product',
        editable: false,
        store: storeProduct,
        valueField: 'ProductID',
        displayField: 'ProductName',
        
    }
]

最後結果就會如同以下畫面:

完整程式碼為:
// 載入會用到的程式
Ext.require([
    'Ext.form.*',
    'Ext.layout.container.Absolute',
    'Ext.window.Window',

    'Ext.Button'
]);

Ext.onReady(function () {
Ext.define('Category', {
    extend: 'Ext.data.Model',
    fields: [
        'CategoryID', 'CategoryName'
    ],
    // Model Category 有 list Product 
    hasMany: { model: 'Product', name: 'Products' }
})

Ext.define('Product', {
    extend: 'Ext.data.Model',
    fields: [
        'ProductID', 'ProductName'
    ],
    belongsTo: 'Category',
})

var storeCategory = Ext.create('Ext.data.JsonStore', {
    storeId: 'storeCategory',
    model: 'Category',
    proxy: {
        type: 'ajax',
        url: 'http://localhost:8090/api/Categories/',
        reader: {
            type: 'json',
        }
    },
    // 自動載入
    autoLoad: true, 
    listeners: {
        // sotre load 完成後載入這個fucntion  
        load: function (store, records, options) {
            
        }
    },
})

var storeProduct = Ext.create('Ext.data.JsonStore', {
    storeId: 'storeProduct',
    model: 'Product',
})

    //建立 form 框架
    var form = Ext.create('Ext.form.Panel', {
        // 預設 tpe (xtype) 沒有指定就是textfield
        defaultType: 'textfield', 
        // 不要外框
        border: false, 
        width: 300,
        // form 的形式顯示 items 自動填滿畫面
        layout: 'form', 
        // css padding 10 px
        padding: 10, 
        renderTo: Ext.getBody(),
        items:
        [
            {
                xtype: 'combobox',
                fieldLabel: '類別',
                name: 'Category',
                //queryMode: 'local',
                store: storeCategory,
                editable:false,
                valueField: 'CategoryID',
                displayField: 'CategoryName',
                listeners: {
                    select: function (combo, record, index) {
                        // raw 取得選取的資料
                        var tempProducts = record[0].raw.Products; 
                        // 清空 product combobox 的store
                        storeProduct.removeAll();
                        for (var i = 0; i < tempProducts.length; i++) {
                            // 加到 product combobox 的store
                            storeProduct.add(tempProducts[i]); 
                        }
                    }
                }
            },
            {
                xtype: 'combobox',
                fieldLabel: '產品',
                queryMode: 'local',
                name: 'Product',
                editable: false,
                store: storeProduct,
                valueField: 'ProductID',
                displayField: 'ProductName',
                
            },
            
        ],
        buttons: [{
            text: 'Send',
            // button 按下動作
            handler: function () {
                // 檢查form isValid  檢查條件是否符合
                this.up('form').getForm().isValid();
                // 取得from 所有欄位與值 name : value
                alert(JSON.stringify(this.up('form').getForm().getValues())) 
            }
        }, {
            text: 'Cancel'
        }]
    });

});


沒有留言 :

張貼留言

Related Posts Plugin for WordPress, Blogger...