2014年10月15日 星期三

JQuery 的 on() 原理


在JavaScript中,大多數事件會在DOM裡往上一層一層的泡浮,也就是說,當一個元素觸發一個事件時,她會在DOM一直往上泡浮到 document 層級

舉例,現在有個基本的html:
<div>
   <span>1</span>
   <span>2</span>
</div>
現在,我們採用事件委託:
$('div').on('click', 'span', fn);
該事件處理程序僅僅連接到 div 元素,由於 span 是在 div 裡面,對 span click 會往上泡浮到 div,並觸發 div 的 click 事件處理器,同時,剩下要做的就是檢查 event.target 是否符合我們指定的目標(範例中為 span)

看看更複雜點的範例:
<div id="parent">
    <span>1</span>
    <span>2 <b>another nested element inside span</b></span>
    <p>paragraph won't fire delegated handler</p>
</div>
下面是一些基礎邏輯:

// 對祖先附加處理程序
document.getElementById('parent').addEventListener('click', function(e) {
    // 過濾 event target
    if (e.target.tagName.toLowerCase() === 'span') {
        console.log('span inside parent clicked');
    }
});
上面的程式中,當 event.target 是被嵌套在過濾器裡面時就無法匹配(例如第二個span裡面有b,click她時,會被上面的程式過濾掉),所以我們需要一些迭代邏輯
document.getElementById('parent').addEventListener('click', function(e) {
    var failsFilter = true,
        el = e.target;
    while (el !== this && (failsFilter = el.tagName.toLowerCase() !== 'span') && (el = el.parentNode));
    if (!failsFilter) {
        console.log('span inside parent clicked');
    }
});












2014年10月2日 星期四

迭代(iterate)資料表的每一個row

現在一個資料表用來記錄網頁瀏覽率:
























欄位[Views]為累加的瀏覽率, ItemId & ItemType 為頁面物件

現在想要詳細記錄每一個使用者的瀏覽時間, 因為之前沒有記錄使用者, 為了讓舊的瀏覽記錄沿用, 所以必須製作假資料, 例如資料表中的第二筆資料的[Views]為4, 則 insert 4筆假資料









備註 :

    1. 為了可以加入到entity framework, 所以加了 Id 當主鍵
    2. UserId 用 -1 代表匿名使用者, 表示沒有登入狀態下瀏覽網頁


T-SQL :


declare @i int
declare @max int -- 要產生幾筆資料
declare @itemId nvarchar(50)
declare @itemType nvarchar(50)
declare @createdOn datetime
declare cur CURSOR LOCAL for
    select ItemId, ItemType,[Views],ModifiedOn from PageViews

open cur
fetch next from cur into @itemId, @itemType, @max,@createdOn
while @@FETCH_STATUS = 0 begin
    set @i = 0
        while (@i<@max) begin
            insert into UserPageView (UserId,ItemId,ItemType,CreatedOn)
                 values (-1,@itemId,@itemType,@createdOn)
                 set @i = @i+-- 累加
        end
    fetch next from cur into @itemId, @itemType, @max,@createdOn
end
close cur
deallocate cur








2014年9月29日 星期一

JQuery的套件Uploadify, 無法使用的替代方法

FireFox必須額外安裝flash player才能使用Uploadify套件, 在要使用該套件的情況下, 遇到不能使用該套件的時後, 自行改寫ajax上傳功能 :


// 上傳頭圖 (上傳圖片到資料夾, 不進行存檔到資料庫, 上傳的圖片名稱會經由程式改成和電影名稱一樣
$('#file_upload').uploadify({
    // .... 省略 uploadify 部分的設定 ....
    onSWFReady: function () {
        // 可以使用 uploadify
    },
    onFallback: function () {
        // 無法使用 uploadify
        // console.log('Flash was not detected or flash version is not supported.');
 
        // 新增一個可上傳檔案的 form
        $('#file_upload').after('<form enctype="multipart/form-data" method="post" name="filefox" id="filefox" style="display: initial;">' +
            // 可加入一些必要的數值到 type="hidden" 欄位
            '<input type="file" name="pic" id="pic">' + // 選圖檔案
            '</form>').remove();
        // 選擇圖片後就自動上傳
        $('#pic').change(function () {
            var fd = new FormData($('#filefox')[0]); // your form element, 使用FormData對象發送文件
            // fd.append("CustomField", "This is some extra data"); // 額外添加對象
            $.ajax({
                type: 'POST',
                url: '/upload/test/',
                data: fd,
                // 如果在 Chrome 上顯示下面這個錯誤 
                // Uncaught TypeError: Illegal invocation (未捕獲類型錯誤:非法調用)
                // 指jQuery的AJAX報錯:檢查jQuery的文檔後發現,如果它不是一個字符串,jQuery嘗試將數據轉換成一個字符串。
                processData: false, // 在這裡告訴jQuery不要碰我的數據
                contentType: false, // 防止jQuery來為你添加一個Content-Type頭
                success: function (data) {
                    changeBanner(true);
                }
            });
        });
    }
});

2014年9月22日 星期一

LINQ to Entities 使用 rank / row_number / dense_rank 技巧


T-SQL

    rank

        遇到相同數值會給相同的排名, 其後的排名則跳過, 例如: 1,2,2,4 (會重複號碼, 也會跳號)

    row_number

        遇到相同數值會依其他的依據來排名, 例如: 1,2,3,4 (不重複號碼, 也不跳號)

    dense_rank

        遇到相同數值會給相同的排名, 其後的繼續排名, 例如: 1,2,2,3 (會重複號碼, 但不跳號)











































======================================================

LINQ to Entities

    rank 

   


    row_number 

          說明 :
TopicSortingRank.ToList() 後才能使用在 .Select 中使用索引, 否則會出現 NotSupportedException 的錯誤 :
LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[<>f__AnonymousType0`3[System.Int32,System.Decimal,System.Int32]] Select[TopicSortingRank,<>f__AnonymousType0`3](System.Linq.IQueryable`1[HappyMovie.Model.TopicSortingRank], System.Linq.Expressions.Expression`1[System.Func`3[HappyMovie.Model.TopicSortingRank,System.Int32,<>f__AnonymousType0`3[System.Int32,System.Decimal,System.Int32]]])' method, and this method cannot be translated into a store expression. 
 

    dense_rank :

               








     


















2014年9月9日 星期二

使用 Group By 組合某一個欄位的數值成為一個字串

假設有一個資料表TopicItem :




















想要看VideoId有哪些TopicId, 所以想組合成:




















語法 :

select
    VideoId,
    STUFF
    (
        (
            select DISTINCT ',' + convert(varchar(10),TopicId) from TopicItem where VideoId = a.VideoId
             FOR XML PATH ('')
   ), 1, 1, ''
     ) as Topics
from TopicItem a
group by VideoId

2014年8月5日 星期二

Html.DropDownList 應用

1. 年齡選單

  • 預設值為空白(代表全部年紀)
  • 範圍 0 ~199
var ageList = new List<SelectListItem>();
ageList.Add(new SelectListItem { Text = "全部年紀", Value = "" });
ageList.AddRange(Enumerable.Range(0120).Select(x => new SelectListItem { Text = x.ToString(), Value = x.ToString() }));
ViewBag.age = new SelectList(ageList, "Value""Text", age);

頁面 :
@Html.DropDownList("age")

2. 英文字母選單

  • 預設值為空白(代表全部字母)
  • 範圍 A ~Z
var selectListAzItem = new List<SelectListItem>();
selectListAzItem.Add(new SelectListItem { Text = "字母", Value = "" });
selectListAzItem.AddRange(Enumerable.Range('A'26).Select(x => new SelectListItem { Text = ((char)x).ToString(), Value = ((char)x).ToString() }));
ViewBag.az = new SelectList(selectListAzItem, "Value""Text", az);

3. 自定內容

List<SelectListItem> ratingSorting = new List<SelectListItem>
{
    new SelectListItem{Text= "全部評分",Value= ""},
    new SelectListItem{Text= "沒有評分",Value= "0"},
    new SelectListItem{Text="有評分",Value= "1"}
};
ViewBag.rating = new SelectList(ratingSorting, "Value""Text", rating);

4. 從資料庫撈取資料

    客製化
  • 插入自定的資料到頂部當成預設資料
var locationList = _db.Location.OrderBy(x => x.Id).Select(x => new SelectListItem {
    Text = x.Name,
    Value = x.Id.ToString(),
}).ToList(); // 最後沒有 ToList() 則會得到型別為 IEnumerable<SelectListItem>, 只有 List 型別才能用 Insert 方法
locationList.Insert(0new SelectListItem { Text = "全部地區" });
ViewBag.location = new SelectList(locationList, "Value""Text", location);

    直接使用

  • 資料表欄位Id當Select的Vaule
  • 資料表欄位Name當Select當Text

ViewBag.location = new SelectList(_db.Location, "Id""Name");
     

5. 使用Enum

var reportTypeList = Enum.GetValues(typeof(ReportType)).Cast<ReportType>().Select(v => new SelectListItem
{
    Text = v.ToString(),
    Value = ((int)v).ToString()
}).ToList();
reportTypeList.Insert(0new SelectListItem { Text = "全部" });
ViewBag.reportType = new SelectList(reportTypeList, "Value""Text", reportType);

如果範例中的 enum ReportType 有 DiplayName, 並想要使用 DisplayName 做 Text 名稱
public enum ReportType
{
    [Display(Name = "訊息報錯")]
    Error,
    [Display(Name = "補充電影資料")] 
    Movie,
    [Display(Name = "回報問題")] 
    Problem,
    [Display(Name = "網站Bug修復")] 
    Bug,
    [Display(Name = "其他")]
    Other,
}

先做一個 function 來取她的 DiplayName
public string GetReportTypeDisplayName(ReportType value)
{
    var type = value.GetType();
    var members = type.GetMember(value.ToString());
    var member = members[0];
    var displayAttributes = member.GetCustomAttributes(typeof(DisplayAttribute), false);
    var displayAttribute = (DisplayAttribute)displayAttributes.FirstOrDefault();
    return displayAttribute == null ? value.ToString() : displayAttribute.GetName();
}

在 Select 出 SelectListem 時, 使用自定的方法
Text = GetReportTypeDisplayName(v),


=========================

頁面上抓取 selected 數值

string ageSelected = ((SelectList)ViewBag.age).Where(x => x.Selected).Select(x => x.Value).FirstOrDefault();






2014年8月3日 星期日

常用的 System.IO.Path 與範例

string FilePath = @"D:\test\test.rar";
Console.WriteLine("路徑 : {0}", FilePath);
// 變更副檔名
Console.WriteLine("變更副檔名 : {0}", System.IO.Path.ChangeExtension(FilePath, "dat")); // "D:\test\test.rar"
// 取得檔案路徑
Console.WriteLine("取得檔案路徑 : {0}", System.IO.Path.GetDirectoryName(FilePath)); // "D:\test"
// 取得副檔名
Console.WriteLine("取得副檔名 : {0}", System.IO.Path.GetExtension(FilePath)); // ".rar"
// 取得檔案名稱(包含副檔名)
Console.WriteLine("取得檔案名稱(包含副檔名) : {0}", System.IO.Path.GetFileName(FilePath)); // "test.rar"
// 取得檔案名稱不包含副檔名
Console.WriteLine("取得檔案名稱不包含副檔名 : {0}", System.IO.Path.GetFileNameWithoutExtension(FilePath)); // "test"
// 回傳最上層實體路徑
Console.WriteLine("回傳最上層實體路徑 : {0}", System.IO.Path.GetPathRoot(FilePath)); // "D:\"
// 建立隨機檔
Console.WriteLine("建立隨機檔 : {0}", System.IO.Path.GetRandomFileName()); // 例如 : "mvho5ulp.wrn"
// 建立暫存檔並回傳整路徑
Console.WriteLine("建立暫存檔並回傳整路徑 : {0}", System.IO.Path.GetTempFileName()); // 例如 : "C:\Users\ian\AppData\Local\Temp\tmp8DBA.tmp"
// 系統暫存檔路徑
Console.WriteLine("系統暫存檔路徑 : {0}", System.IO.Path.GetTempPath()); // "C:\Users\ian\AppData\Local\Temp\
// 是否包含副檔名
Console.WriteLine("是否包含副檔名 : {0}", System.IO.Path.HasExtension(FilePath)); // True
// 絕對路徑還是相對路徑
Console.WriteLine("絕對路徑還是相對路徑 : {0}",System.IO.Path.IsPathRooted(FilePath)); // True
// 取得完整路徑檔名
Console.WriteLine("取得完整路徑檔名 : {0}", System.IO.Path.GetFullPath(FilePath)); // "D:\test\test.rar"
// 將二個路徑合併
string FilePath1 = @"D:\";
string FilePath2 = @"test\test.rar";
Console.WriteLine("將二個路徑合併 : {0}", System.IO.Path.Combine(FilePath1, FilePath2)); // "D:\test\test.rar"

使用 Request 解析網址的說明與範例 :
http://blog.miniasp.com/post/2008/02/10/How-Do-I-Get-Paths-and-URL-fragments-from-the-HttpRequest-object.aspx