2015年1月6日 星期二

Kendo UI Grid 全AJAX的CRUD功能範例

Grid有許多的套件都有提供,今天小艾要介紹一套,Kendo UI的Grid使用方式,先附上官網
Kendo UI

1.   首先套用css和javascript

<link rel="stylesheet" href="styles/kendo.common.min.css" />
<link rel="stylesheet" href="styles/kendo.default.min.css" />
<link rel="stylesheet" href="styles/kendo.dataviz.min.css" />
<link rel="stylesheet" href="styles/kendo.dataviz.default.min.css" />

<script src="js/jquery.min.js"></script>
<script src="js/kendo.all.min.js"></script>

2. 加入html
<div id="example">
    <div id="grid"></div>

</div>

3. 接下來都是javascript的處理了

設定dataSource
var dataSource = new kendo.data.DataSource({
        transport: {
            read: {
                type: "POST",
                url: "/PeopleData/PeopleList",
                dataType: "json",
                contentType: "application/json"
            },
            update: {
                type: "POST",
                url: "/PeopleData/Edit",
                dataType: "json",
                contentType: "application/json"
            },
            destroy: {
                type: "POST",
                url: "/PeopleData/Delete",
                dataType: "json",
                contentType: "application/json"
            },
            create: {
                type: "POST",
                url: "/PeopleData/Create",
                dataType: "json",
                contentType: "application/json"
            },
            parameterMap: function (data, operation) {
                if (operation === "read") {
                    return JSON.stringify({ skip: data.skip, take: data.take });
                }
                else if ((operation === "update" || operation === "create") && data) {
                    return JSON.stringify({ peopleData: data });
                }
                else if (operation === "destroy" && data.PeopleID) {
                    return JSON.stringify({ personId: data.PeopleID });
                }
                return data;
            }
        },
        //batch: true,
        schema: {
            //取出資料陣列
            data: function (d) { return d.PeopleDataList; },
            //取出資料總筆數(計算頁數用)
            total: function (d) { return d.Count; },
            model: {
                id: "PeopleID",
                fields: {
                    PeopleID: { editable: false, nullable: true },
                    CN: { validation: { required: true } },
                    Depart: { defaultValue: { DepartID: 0, DepartName: "Please wait" } },
                    Pasd: { validation: { required: true } },
                    Name: { validation: { required: true } },
                    Mail: { type: "email", validation: { required: true } },
                }
            }
        },
        pageSize: 10,
        serverPaging: true,
        serverSorting: true
    });

transport裡的read,update,destroy,create分別對應到讀取,修改,新增,刪除的動作。
parameterMap裡偵對不同的指令,把值傳入後端做處理。
schema設定grid顯示對應的資料,還可以加上vaildation的設定

設定好Datasource後,就要準備把資料塞給kendo ui grid了

$("#grid").kendoGrid({
        dataSource: dataSource,
        pageable: true,
        height: 550,
        toolbar: ["create"],
        columns: [
            "Name",
            { field: "CN", title: "CN" },
            { field: "Depart", title: "Depart", width: "180px", editor: departDropDownEditor, template: "#=Depart.DepartName#" },
            { field: "Pasd", title: "Pasd" },
            { field: "Mail", title: "Mail" },
            { command: ["edit", "destroy"], title: " ", width: "250px" }],
        editable: "inline"
    });

值得注意的是,Depart以DropDownList的方式呈現,所以需要設定departDropDownEditor,到後端去取得Depart List的資料
PS. 下面的 $('input  應該是  $('<input,不過blogger會顯示成text…所以就把 < 拿掉了,複製code時別忘了加回去哦!

function departDropDownEditor(container, options) {
        $('input data-bind="value:' + options.field + '" data-text-field="DepartName" data-value-field="DepartID" required="" />')
            .appendTo(container)
            .kendoDropDownList({
                autoBind: false,
                dataSource: {
                    type: "json",
                    transport: {
                        read: {
                            type: "POST",
                            url: "/PeopleData/GetDepartList",
                            dataType: "json",
                            contentType: "application/json"
                        },
                    }
                }
            });
    }

departDropDownEditor去後端取出資料後,把name和id bind給list就大功告成囉!!簡單明瞭,出來的效果也不錯,完全不需要導頁,全AJAX就搞定CRUD功能。

附上範例程式:請點我

最後推薦個新創日本求職網站
Trails會慢慢的提供一些有用的資訊給想到日本去工作的朋友,只要簡單的註冊會員後就可以免費看文章,找工作囉~~目前日本企業職缺正在募集中,會陸陸續續更新上來!

2015年1月2日 星期五

jQuery UI Sortable 拖曳更改順序並記錄

jQuery UI有個很好用的功能,可以使用拖曳的方式,直接調整畫面的順序,請見jQuery UI官網 jqueryui.com

但拖曳完後,要怎麼把排列順序存入後端呢?

資料庫設計了CategoryId、CategoryName、CategoryOrder三個欄位(CategoryOrder記錄順序)

首先先處理html的部份

1. 先加入jvavscript (因為套bootstrap畫面較好看,所以順便加入)
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery-ui-1.11.2.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>

2. 加入css (可省略,只是為了加入bootstrap畫面較好看)
<link href="~/Content/bootstrap.min.css" rel="stylesheet" type="text/css" />

3. 設計表格,Sortable 也可支援<ul></ul>不一定要使用table
<table id="mytable" class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.CategoryName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.CategoryOrder)
        </th>
        <th></th>
    </tr>
    <tbody id="myfruit">
        @foreach (var item in Model.OrderBy(r => r.CategoryOrder))
        {
            <tr id="@Html.DisplayFor(modelItem => item.CategoryOrder)">
                <td>
                    @Html.DisplayFor(modelItem => item.CategoryName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.CategoryOrder)
                </td>
                <td>
                    @Html.ActionLink("Edit", "Edit", new { id = item.CategoryId }) |
                    @Html.ActionLink("Details", "Details", new { id = item.CategoryId }) |
                    @Html.ActionLink("Delete", "Delete", new { id = item.CategoryId })
                </td>
            </tr>
        }
    </tbody>
</table>

4.套入jQuery UI Sortable效果,在update裡使用$(this).sortable('toArray').toString();將表格裡的<tr id="@Html.DisplayFor(modelItem => item.CategoryOrder)">串成字串,但此方法只能將id轉成字串,較好的方法應該是取td裡的CategoryOrder欄位,但sortable好像沒辦法直接取到,可能要用jquery想辦法去取…就沒有做測試了

最後將組好的字串傳到後端處理,存進資料庫就大功告成囉~~
另外,因為沒有使用Angular或Knockout來做Data binding,而且傳到後端的是取tr的id…所以每次必需Reload畫面,讓id更新才行,較好的方法應該是使用Data binding,讓畫面上的CategoryOrder會即時更改,並取出傳至後端,就不需要每次重load了。

$(function () {
    $('#mytable tbody').sortable({
        opacity: 0.6,
        cursor: 'move',
        axis: 'y',
        update: function (event, ui) {
            var productOrder = $(this).sortable('toArray').toString();
            $.ajax({
                type: 'post',
                url: '/Home/DragItem',
                data: {
                    orders: productOrder
                },
                success: function (result) {
                    window.location.href = result.redirectToUrl;
                }
            });
        }
    });
});
-------------------------2015.01.17更新------------------------------------------------

更新jQuery UI Sortable取得oldIndex和newIndex的方法,只需要傳兩個值到後端,就能夠偵對order進行排序,無需傳入一整個list囉。
$('#grid tbody').sortable({
        opacity: 0.6,
        cursor: 'move',
        axis: 'y',
        start: function (event, ui) {
            var start_pos = ui.item.index();
            ui.item.data('start_pos', start_pos);
        },
        update: function (event, ui) {
            //var productOrder = $(this).sortable('toArray').toString();
            var oldIndex = ui.item.data('start_pos');
            var newIndex = ui.item.context.rowIndex;
            $.ajax({
                type: 'post',
                url: '/PeopleGroups/DropOrderItem',
                data: {
                    oldIndex: oldIndex + 1,
                    newIndex: newIndex + 1,
                    page: currPage,
                    pageSize: pageSize
                }
            });
        }
    });


1. start,當拖曳動作開始,就會先執行這一段,這使用ui.item.index(),就可以取得目前使用者拖曳的item的index,在用ui.item.data('start_pos', start_pos),把index填進此item的'start_pos'(這個名字可以自訂),tag中,產生出來的html會變成 <tr start_pos = "index"></tr>

2. 在update時,就可以使用ui.item.data('start_pos'),將剛才存下來的index取出來,在使用ui.item.context.rowIndex取得最新的index,將這兩個index傳到後端就大空告成了!!

3.  順便附上後端的c# code供大家參考

if (oldIndex < newIndex)
            {
                var currGroup = ESHCloudsContext.PeopleGroups.SingleOrDefault(r => r.GroupOrder == oldIndex);
                if (currGroup == null)
                    return false;

                var peopleGroupList = ESHCloudsContext.PeopleGroups
                    .Where(r =>
                        r.GroupOrder <= newIndex &&
                        r.GroupOrder > oldIndex &&
                        r.GroupID != currGroup.GroupID
                    ).ToList();

                foreach (var peopleGroup in peopleGroupList)
                    peopleGroup.GroupOrder--;

                currGroup.GroupOrder = newIndex;
                ESHCloudsContext.SaveChanges();
            }
            else
            {
                var currGroup = ESHCloudsContext.PeopleGroups.SingleOrDefault(r => r.GroupOrder == oldIndex);
                if (currGroup == null)
                    return false;

                var peopleGroupList = ESHCloudsContext.PeopleGroups
                    .Where(r =>
                        r.GroupOrder < oldIndex &&
                        r.GroupOrder >= newIndex &&
                        r.GroupID != currGroup.GroupID
                    ).ToList();

                foreach (var peopleGroup in peopleGroupList)
                    peopleGroup.GroupOrder++;

                currGroup.GroupOrder = newIndex;
                ESHCloudsContext.SaveChanges();
            }


比上次的方法容易且合理多了,如果grid有設定分頁的話,別忘了把page和pagesize也傳到後端進行判斷囉!!

最後推薦個新創日本求職網站
Trails會慢慢的提供一些有用的資訊給想到日本去工作的朋友,只要簡單的註冊會員後就可以免費看文章,找工作囉~~目前日本企業職缺正在募集中,會陸陸續續更新上來!

2014年11月13日 星期四

[峇里島] 峇里島自助旅行注意事項、行前準備、行程簡介

雖然不是第一次自助旅行,不過之前自助都是到日本,是一個語文能通的國家,而這次的《峇里島》只能使用英文,可以說是一大挑戰,秉持著不喜歡跟團的理念,想為自己安排個美好的《蜜月》~~因為開始了一連串的google~~

以下都是google、看書來的資訊,已經完成峇里島的蜜月之旅,非常圓滿的結束啦~~意外的其實不困難,而且自助花費節省不少,還能去自己想去的地方,較有彈性,這篇文章希望可以幫助其他的朋友~~

自助不難,英文爛沒關係!只要有心,就能到峇里島自助!!

一、花費
機票:
長榮 14365元
11/05 上午10:00 -> 下午3:20
11/11 下午4:20 -> 下午9:35

包車:
Komang
包一天400000印尼盾,共包三天
機場 -> 庫塔接送100000盧比
努沙杜瓦 -> 機場接送120000盧比
共1420000 盧比

訂飯店:
John
Inata Hotel 3天,附早餐 189美金
Bali Orchid Spa按摩2小時 30美金
泛舟 + 按摩  65美金
水上活動 (Jet ski for 15 minute, Parasailing for one round , Banana Boat for 15 minute,  1 x dive at Nusa Dua, snorkeling)      60美金

Koma
肉桂(Kayumanis) 2天,附早餐、下午茶、30分鐘按摩、免費接送Nusa dua & Jimbaran,送晚餐or 90分鐘按摩 872美金



二、注意事項
飛機上填寫入境卡 和 通關卡,通關時入境卡會還回來,要留著,出境會用到,不用弄丟
落地簽(VOA Visa On Arrival) 一人 35美金
離境稅(Departure) 一人20萬盧比(只能付盧比,不找零)
插座是220v,圓頭,需轉接頭
小費:床頭、check in、heck out、spa,1美金
餐廳的menu上的價錢通上要在加上20%(稅和服務費)
藍島計程車Blue bird 0361-701111
1美金約120000盧比(烏布的匯率比較好,建議在烏布換),找比較大間的換錢較保險,綠色招牌寫著Money changer



三、行程
第一天,    庫塔散步小旅行
3:20到峇里島機場,出境約需1小時 -> 換錢(先換一些就好,其他到烏布換) ->飯店 -> (就在旁邊)庫塔廣場逛街(Kuta Square)(知名的太陽百貨(Matahari department Store)也在這) -> 晚餐 -> 庫塔藝往市場(Kuta Art Market)就在這條路上(卡地卡廣場路逛街(Jl. Kartika Plaza)) ->
按摩 or 繼續往到 庫塔海灘看海 逛 探索購物中心(Discovery Shopping Mall)

晚餐:阿甘蝦餐廳(Bubba Gump Shrimp)

Komplek Pertokoan Kuta Centre, Blok A1 No. 1
JL Kartika Plaza No. 8X, Kuta, Bali 80361
Tel 011 62 361 754 028
(一人約300 ~)


按摩:ROSE GARDEN 玫瑰園
地址:JL. KEDIRI NO. 50.ABCD TUBAN-KUTA-BALI Pepito超市斜對面
訂位電話:0361-7427898 說國語
2人含接送,限KUTA、SEMINYAK、JIMBARAN

與agent訂的spa較高級,二小時(一小時按摩,一小時spa)30美金,在烏布按摩約一小時60000印尼盾起,價差很多,庫塔價格未比較,路上按摩店很多,建議不需要跟agent訂,可直接在街上找

晚上可去”雷根街(Jl.Legian)”有很多夜店



第二天,    包車玩水明漾(Seminyak),看海一日遊
10:00出發 -> 庫塔海灘(kuta beach) 逛 探索購物中心(Discovery Shopping Mall) -> 午餐 -> 水明漾廣場(Seminyak Square) -> 庫德塔海灘俱樂部(Kudeta)(夠有錢也可以在這吃午餐) -> 飯店 -> 晚餐 -> 逛逛烏布的街(飯店就在最熱鬧的街上),可到烏布王宮(Puri Saren Agung)看表演

午餐:馬爹小吃店(Made’s Warung)
(Kuta)
Br. Pande Mas, Kuta, Bali, Indonesia
+62-361-755297
(Seminyak)
Br. Seminyak, Kuta, Bali, Indonesia
+62-361-732130
(一人約300 ~)

KU DE TA
Jalan Kayu Aya No.9, Seminyak, Bali 80361, Indonesia
+62 361 736969
(一杯酒約300 ~)

晚餐:拉瑪餐廳(Lamak Restaurant)
(一人約350 ~)




第三天,    泛舟、烏布(Ubud)自遊行
9:30接送到泛舟地點(約1個半小時) -> 泛舟(約2小時) -> 午餐(泛舟套餐裡面有包含) -> 飯店 -> 烏布市場(Pasar Ubud),要狂殺價才行 -> 晚餐 -> 按摩 or 在飯店發呆 or 逛coco超市

晚餐:歐卡媽媽烤豬飯(Babi Guling lbu Oka)
推薦:Babi Guling Special
地址:Jl. Suweta (烏布王宮對面)
電話:0361-976345
(一人約150,但是可能中午就賣完了…)

SPECIAL PACKAGE RAFTING + SPA
Dewata rafting / Payung rafting / Bali International Rafting ( BIR )+ 2 Hours spa at baliorchidspa (www.baliorchidspa.com) 
* SPA MENU
*Thallaso foot wash
*Balinese massage
*Body scrub(lulur)
*Yogurt moisturizer
*Flower bath

* PICK UP TIMES:
Nusa Dua/Jimbaranà 07:45am-08:45am  
Kuta         à 08:00am-08:30am
Sanur        à 08:30am-09:00am
Ubud         à 09:45am-10:15am
US$. 65/person




第四天,    包車玩塔巴南(Tabanan),包半天就夠了(5小時)
10:00出發 -> (約1小時)孟威王廟(Taman Ayun Temple) -> (約半小時)海神廟(tanah lot temple),東西便宜,可以買,午餐在這裡吃 -> 回飯店約下午3:00,可去神聖猴子森林保護區(Sacred Monkey Forest Sactuary)(走路5~10分可到) -> 晚餐 -> 按摩(太便宜不按不行) or 回飯店發呆

聖猴森林(Sacred Monkey Forest Sanctuary)
Jalan Monkey Forest, Padangtegal, Ubud, Bali 80571, Indonesia
+62 361 971304

晚餐:Bebek Bengil(smoked duck必吃)
Jalan Hanoman | Padang Tegal, Ubud, Bali, Indonesia
(62-361) 975-489
(一人約400~)




第五天,    包車玩克龍宮(Klungkung),包半天就夠了(5小時)
10:00飯店出發 -> (約1小時)司法亭(kerta gosa museum) -> tukad unda水壩(就在司法亭旁),可看到最真實的裸體 -> 午餐(不餓其實可不吃,一到飯店有蜜月蛋糕和下午茶可吃…超飽) -> 飯店

晚餐:飯店吃




第六天,    努沙杜瓦、金巴蘭
6:00吃日出早餐 -> 9:00出發玩水上活動 -> (約20分鐘) Nusa dua水上活動 -> (約20分鐘,泛舟套餐送的) Bali Orchid Spa -> 飯店下午茶 -> (可跟飯店借腳踏車去,或請飯店接送,開車只要2分鐘)Bali Collection -> 金巴蘭吃海鮮大餐

WATER ACTIVITY
MARINE & WATER SPORT
Jet ski for 15 minute, Parasailing for one round , Banana Boat for 15 minute,  1 x dive at Nusa Dua, snorkeling

晚餐:里雅(Lia cafe)
Jl Pemalisan Agung, Jimbaran, Bali, Indonesia
(一人約500~)



第七天,    在飯店享受最後的悠閒

[泰國] 芭達雅大城八日遊 Day7、8 - 瑪哈泰寺、Wat Ratchaburana、帕蒙空博碧寺、帕席桑碧寺、Hua Ro market、Chantharakasem National Museum、Amporn Department Store

第七天行程,早上吃飯店早餐,算不錯吃,只是有螞蟻,但吃完沒拉,所以應該還好 吃飽後飽嘟嘟車,一小時 200 泰銖,比自己叫還便宜,終於要來世界遺產之旅了 第一站:瑪哈泰寺,應該是大城最有名的景點了,入門票大人 120 ,小孩免費,其實不便宜 大城指標性景點...