8 Mart 2012 Perşembe

Custom Jquery Category Autocomplete


Autocomplete arama web sitelerinde artık vazgeçilmez oldu diyebiliriz. Jquery nin Autocomplete eklentisi ise bu konuda gerçekten çok başarılı. Birde bunu istediğimiz gibi customize edibelmemiz işin çekiciliğini artırıyor.
Hazır azda olsa vakit bulmuşken, birazcık da biz oynayalım ve aramada kategorilemizi ve gösterilen sonuçlardaki datalara ait image varsa onlarıda gösterelim. Hatta kullanıcının aramasına göre farklı sayfalara yönledirelim. Mesela kullanıcı bir e-ticaret sitesinde ve autocomplete textbox ımızı kullanarak ürün arıyor, arama sonuçlarından herhangi birini seçmeden enter a basmışsa Ürün Arama sayfamıza, arama sonuçlarında bir kategori üzerindeyken enter tuşana basmışsa seçmiş olduğu kategoriye ait ürünlerimizi göstermek üzere Kategorisayfamıza, ürün seçmiş ise o ürünün detayını göstermek üzere Ürün Detaysayfamıza yönlendirecek şekilde AutoComplete textbox ımızı düzenleyelim. ;)
Bunun için öncelikle projemize JqueryUI templatelerinden istediğimiz birini ve jquery kütüphanesi eklememiz gerekiyor.
http://jqueryui.com/download buradan indirebilirsiniz.
Arama textbox ının projedeki tüm sayfalarda görünmesini istiyorum. Bu yüzden öncelikle projemize bir MasterPage ekleyelim. Diğer tüm sayfalarımızada bu MasterPage i uygulayacağız.



















Css ve Js dosylarımızı MasterPage imize ekleyelim.
<link href="../css/redmond/jquery-ui-1.8.18.custom.css" rel="stylesheet" type="text/css" />  
 <script src="<%=ResolveClientUrl("~/js/jquery-1.7.1.min.js") %>" type="text/javascript"></script>
 <script src="<%=ResolveClientUrl("~/js/jquery-ui-1.8.18.custom.min.js") %>" type="text/javascript"></script>

MasterPage imize bir div ekleyelim. Jquery AutoComplete eklentisinin bu div i kullanabilmesi için div in classını “ui-widget” olarak set etmemiz gerekiyor. Aramada kullanacağımız textbox ımızı ve kullanıcının kategori seçebilmesi için bir select objesini de div imizin içine ekleyelim.  Kategorileri ben html üzerinde elle ekleyeceğim, siz projenizin durumuna göre dinamik olarak yükleyebilirsiniz.

<div class="ui-widget">
            <input name="search" type="text" id="txtSearch" style="width: 500px;" placeholder="aramak için birşeyler yaz..." />
            <select id="cmbCategory">
                <option value="0">Kategori Seçiniz</option>
                <option value="1">BİLGİSAYAR</option>
                <option value="2">OEM</option>
                <option value="3">MONİTÖR</option>
                <option value="4">EKRAN KARTI</option>
                <option value="5">RAM</option>
                <option value="6">ANA KART</option>
            </select>
</div>

Kullanıcının arama sonuçlarında seçtiği item ın tipine göre farklı sayfalara yönlendirme yapacağız, bunun için MasterPage de tüm sayfalardan ulaşabileceğimiz bir javascript değişkeni oluşturuyoruz.

<script type="text/javascript">
        window.SearchType = -1; //Arama tipini bu değişkenden alacağız.
</script>

Arama işlemini yapmak için birde GenericHandler a ihtiyacımız olacak. Hemen projemize bir GenericHandler dosyası ekliyoruz.






















Yapacağımız işlemleri biraz daha kolaylaştırmak için projemize bir ProductEntity class ı ekleyelim. Ben hızlı ve basit olsun diye property ve constructor larını aşağıdaki gibi düzenledim. Birde database kullanmayacağım için hardcoded bazı ürünler girdim. GetDefaultProducts() methodumu da bana girmiş olduğum bu ürünleri Generic List olarak getirecek şekilde düzenledim. Siz bunu daha kapsamlı bir şekilde projenizin yapısına göre ürünlerinizi databaseden gelecek şekilde Business ve Entity katmanlarınızda istediğiniz gibi şekillendirebilirsiniz.
ProductEntity classımızın propertyleri.

    private int _productID;
    public int ProductID
    {
        get { return _productID; }
        set { _productID = value; }
    }

    private string _productName;
    public string ProductName
    {
        get { return _productName; }
        set { _productName = value; }
    }

    private string _productImageUrl;
    public string ProductImageUrl
    {
        get { return _productImageUrl; }
        set { _productImageUrl = value; }
    }

    private int _categoryID;
    public int CategoryID
    {
        get { return _categoryID; }
        set { _categoryID = value; }
    }

    private string _categoryName;
    public string CategoryName
    {
        get { return _categoryName; }
        set { _categoryName = value; }
    }


ProductEntity classımızın constructorları.

    public ProductEntity()
    {
        //
        // TODO: Add constructor logic here
        //
    }

    public ProductEntity(int productID,string productName, string productImageUrl,int categoryID, string categoryName)
    {
        this.ProductID = productID;
        this.ProductName = productName;
        this.ProductImageUrl = productImageUrl;
        this.CategoryID = categoryID;
        this.CategoryName = categoryName;
    }


Hardcoded olarak eklediğimiz ürünlerimizi getirecek  GetDefaultProducts() methodumuz.

    public static List<ProductEntity> GetDefaultProducts()
    {
        return new List<ProductEntity>() {
        new ProductEntity(1,"Packard Bell DOTSE3-V-571TK Intel Atom","../images/Bilgisayar_974893.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(2,"Lenovo Z570 Intel Core i7 2670QM","../images/Bilgisayar_1089542.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(3,"Samsung NP-N150-JP0WTR Intel Atom","../images/samsungnpn150.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(6,"TX Sonic 460W Kırmızı Led Fanlı","../images/txsonic.jpg",2,"BİLGİSAYAR KASALARI"),
        new ProductEntity(7,"Frisby 6905BS P4 350W Kulplu Atx Kasa","../images/frisby6905bs.jpg",2,"BİLGİSAYAR KASALARI"),
        new ProductEntity(8,"Thermaltake Level 10 GT Oyun Kasası","../images/thermaltake10gt.jpg",2,"BİLGİSAYAR KASALARI"),     
        new ProductEntity(11,"Philips 192E2SB2/62 18.5” 5ms Monitör","../images/philipsmonitor1.jpg",3,"MONİTÖR"),
        new ProductEntity(12,"Acer (Gamer Serisi) G195HQVBB 18.5” 5ms Monitör","../images/acermonitor1.jpg",3,"MONİTÖR"),
        new ProductEntity(13,"AOC F22S+ 21.5” 5ms Wide Screen LCD Monitör","../images/aocmonitor1.jpg",3,"MONİTÖR"),
        new ProductEntity(14,"Samsung B1930N 18.5” 5ms Wide Screen LCD Monitör","../images/samsungmonitor1.jpg",3,"MONİTÖR"),
        new ProductEntity(15,"LG E2251S-BN 21.5” 5ms Wide Screen LED Monitör","../images/lgmonitor1.jpg",3,"MONİTÖR"),
        new ProductEntity(16,"Sapphire Ati HD5570 1GB/2.8GB HM 128Bit DDR3 Ekran Kartı","../images/sapphireek1.jpg",4,"EKRAN KARTI"),
        new ProductEntity(17,"Volar Nvidia 9600GT 1GB 256Bit GDDR3 Ekran Kartı","../images/volarek1.jpg",4,"EKRAN KARTI"),
        new ProductEntity(18,"HIS Ati HD 4670 Iceq 1GB (128BIT) GDDR3 Ekran Kartı","../images/hisek1.jpg",4,"EKRAN KARTI"),
        new ProductEntity(19,"MSI N430GT-MD2GD3/OC 2GB 128Bit DDR3 Ekran Kartı","../images/misek1.jpg",4,"EKRAN KARTI"),
        new ProductEntity(20,"Zotac GT430 Synergy 1GB (128 Bit) GDDR3 Ekran Kartı","../images/zotacek1.jpg",4,"EKRAN KARTI"),
        new ProductEntity(21,"Team Xtreem 12GB 2000MHz DDR3 Ram","../images/teamextrem_ram1.jpg",5,"RAM"),
        new ProductEntity(22,"Geil Evo Corsa 16GB (2x8GB) DDR3 Ram","../images/geilevo_ram1.jpg",5,"RAM"),
        new ProductEntity(23,"Team Elite 16GB (2x8GB) DDR3 1333MHz Ram","../images/teamelite_ram1.jpg",5,"RAM"),
        new ProductEntity(24,"Kingston 4GB(2x2GB) 1066MHz DDR2 Hyperx Ram","../images/kingston_ram1.jpg",5,"RAM"),
        new ProductEntity(25,"Corsair XMS3 8GB(2x4GB) DDR3 1333MHz Ram","../images/corsair_ram1.jpg",5,"RAM"),
        new ProductEntity(26,"Gigabyte 990FXA-UD5 AMD AM3+ DDR3 1866MHz Anakart","../images/gigabyteak1.jpg",6,"ANA KART"),
        new ProductEntity(27,"Asus P8H61-M LE 3.0 H61 DDR3 Matx Gigalan Anakart","../images/asusak1.jpg",6,"ANA KART"),
        new ProductEntity(28,"MSI E350IA-E45 AMD Soket AM3 DDR3 Anakart","../images/msiak2.jpg",6,"ANA KART"),
        new ProductEntity(29,"MSI P67A-GD65 (B3) Intel P67 DDR3 2133MHz Anakart","../images/msiak1.jpg",6,"ANA KART"),
        new ProductEntity(30,"ECS MCP61M-M3 (7.1) 2000MT DDR3 1333MHz Anakart","../images/ecsak1.jpg",6,"ANA KART"),
        new ProductEntity(31,"Exper Action DR71D Core i5 2310","../images/experactiondr71d.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(32,"Asus EeePc 1015BX-WHI114S AMD C50","../images/asuseepc1015.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(33,"Samsung NP300E5A-S0BTR Intel Core i3 ","../images/samsungnp300.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(34,"Casper Nirvana CN.HBP950A Intel Core","../images/caspernirvanacnhbp950a.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(35,"Mobee Nett 7” T1200 Tablet","../images/mobeenetttablet.jpg",1,"BİLGİSAYAR"),
        new ProductEntity(36,"3R SYS R460Li LCD Ekranlı 120mm FANLI","../images/3rsysr460.jpg",2,"BİLGİSAYAR KASALARI"),
        new ProductEntity(37,"Aerocool XWarrior Mesh Panel","../images/aerocool1.jpg",2,"BİLGİSAYAR KASALARI"),
        new ProductEntity(38,"Aerocool CyborgX 600W Çift Fanlı","../images/aerocool2.jpg",2,"BİLGİSAYAR KASALARI"),
        new ProductEntity(39,"3R Sys L600 Fan Kontrolcülü 120mm","../images/3rsysr4602.jpg",2,"BİLGİSAYAR KASALARI"),
        new ProductEntity(40,"Gmc K-55 Kasa","../images/gmck55.jpg",2,"BİLGİSAYAR KASALARI")
        };
    }


Artık javascript tarafına geçerek AutoCompletimizi şekillendirmeye başlayabiliriz. Bunun için aramada kullanacağımız textbox ın id sini parametre alan bir javascript fonksiyonu yazabiliriz.

function autoComplete(objID) {
    var handlerUrl = '../Handlers/AutoCompleteSearch.ashx';   //Arama için kullanacağımız Generic Handler ımızın pathi
    var searchKeyword = '';   //Arama yapılan kelime }


Şimdi bu fonksiyonumuza id sini parametre olarak göndereceğimiz textbox ımızı autocomplete arama yapacak şekilde biraz geliştirelim. Jquery kütüphanesi ile ajax çağrısı yapmayı bildiğinizi düşünerek işin o kısımlarıyla ilgili açıklamada bulunmuyorum. Daha önce hiç Jquery kütüphanesi ile ajax kullanmamış olanlar internette bununla ilgili çok sayıda örnek bulabilirler.
Fonksiyonumuza aşağıdaki javascript kodlarını ekleyerek, textbox a girilen değer ve seçilen kategoriye göre arama yapması için eklemiş olduğumuz AutoCompleteSearch.ashx adlı Generic Handler ımıza yönlediriyoruz.

$("#" + objID).catcomplete({
        source: function (request, response) {
            $.ajax({
                url: handlerUrl, //arama işleminin yapılacağı .ashx dosyamızın pathi
                contentType: 'application/json; charset=utf8;',
                data: {
                    keyword: request.term, //arama textbox ımıza girilen değer.
                    categoryID: $('#cmbCategory').val() //dropdownlist imizden seçilen kategori
                },
                success: function (data) {
                    searchKeyword = request.term; //daha sonra kullanmak için arama yapılan kelimeyi bir değişken üzerinde tutuyoruz.
                    response($.map(data, function (item) {
                    /*gelen arama sonuçlarımızdaki datayı kullanmak istediğimiz şekilde mapliyoruz.*/
                        return {
                            label: item.ProductName,
                            value: item.ProductName,
                            productID: item.ProductID,
                            imageUrl: item.ProductImageUrl,
                            category: item.CategoryID,
                            categoryName: item.CategoryName
                        }
                    }));
                },
                error: function (xmlHttpRequest) {
                }
            });
        },        open: function () {
            $(this).removeClass('ui-corner-all').addClass('ui-corner-top');
        },
        close: function () {
            $(this).removeClass('ui-corner-top').addClass('ui-corner-all');
        }
    });


Şimdi AutoCompleteSearch.ashx isimli Generic Handler ımızı düzenlemeye başlayalım. Ürünleri arama işlemini burada yapacağız.
Kullanıcının arama textbox ına girdiği kelimeyi ve seçmiş olduğu kategoriyi javascript fonksiyonumuzdan parametre olarak göndermiştik. AutoCompleteSearch.ashx dosyamızda bulunan ProcessRequest methodunda QueryString den göndermiş olduğumuz bu parametreleri alacağız. ProcessRequest methodumuzun ilk hali aşağıdaki gibidir.
public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "application/json";
        string keyword = context.Request.QueryString["keyword"];
        int categoryID = !String.IsNullOrWhiteSpace(context.Request.QueryString["categoryID"]) ? Convert.ToInt32(context.Request.QueryString["categoryID"]) : 0;
              
        // TODO:  Devam edeceğiz...
    }


şimdi almış olduğumuz bu parametreleri kullanarak aramaya uyan ürünlerimizi getirecek methodumuzu yazalım. Bu methodumuz bizden keyword ve categoryID yi parametre olarak alıp bize bir ürün koleksiyonu döndürsün. Bunun için ben, daha önce yazdığımız ProductEntity classımızdaki GetDefaultProducts() methodundan faydalanarak filtreleme yapacağım. Burada Generic List ve filtreleme işleminde Linq kullanacağım için hemen System.Collections.Genericve System.Linq namespacelerim ekliyorum.

using System.Collections.Generic;
using System.Linq;


ve SearchProduct isimli filtreleme yapacağımız methodumuzu yazıyoruz.

/// <summary>
    /// ProductEntity classımızdaki GetDefaultProducts() methodundan dönen ürün listesi üzerinde girilen keyword ve categoryID parametrelerine göre ürünlerin adında ve kategorilerinde filtreleme yapar. categoryID nin değeri 0 ise bu kategori seçilmemiş demektir. Bu durumda filtrelemeyi sadece ürün adında göre yapar.
    /// </summary>
    /// <param name="keyword">Kullanıcının textbox a girdiği arama kelimesi</param>
    /// <param name="categoryID">Kullanıcının seçmiş olduğu kategori</param>
    /// <returns></returns>

    public List<ProductEntity> SearchProduct(string keyword, int categoryID)
    {
        if (categoryID > 0)
        {
            return ProductEntity.GetDefaultProducts().Where(p => p.ProductName.ToLower().Contains(keyword.ToLower()) && p.CategoryID == categoryID).OrderBy(p => p.CategoryID).ToList();
        }
        else
        {
            return ProductEntity.GetDefaultProducts().Where(p => p.ProductName.ToLower().Contains(keyword.ToLower())).OrderBy(p => p.CategoryID).ToList();
        }
    }


Şimdi de SearchProduct methodumuzdan dönen sonucumuzu json datası olarak serilaze edip ajax çağrımıza yanıt olarak dönelim. Bu işlemide yine ProcessRequest methodumuzda yapacağız. ProcessRequest methodumuza kaldığımız yerden devam edelim.

public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "application/json";
        string keyword = context.Request.QueryString["keyword"];
        int categoryID = !String.IsNullOrWhiteSpace(context.Request.QueryString["categoryID"]) ? Convert.ToInt32(context.Request.QueryString["categoryID"]) : 0;
        System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
      
        context.Response.Write(serializer.Serialize(SearchProduct(keyword, categoryID)));
    }


ProcessRequest methodumuzun son hali yukarıdaki gibidir. Artık AutoCompleteSearch.ashx dosyamızla işimizi tamamlamış olduk.
Sayfa yönlendirmeleri için projeye MasterPage mizi kullanan Default.aspxCategory.aspxProduct.aspxSearchResult.aspxisimlerinde 4 tane WebForm ekliyoruz. Fazla karışıklık olmasın diye sayfaları Pages adında bir folder açıp, bu folder a ekleyebiliriz. Aynı şekilde projemizdeki diğer dosyalarıda uygun şekilde folderlar içine eklememiz daha iyi olacaktır.















Şimdi autocomplete javascript fonksiyonumuzu daha da geliştirmeye başlamadan önce kullanıcının arama şekline göre sayfa yönlendirmesini yapacağımız yeni bir javascript fonksiyonu yazalım. Fonksiyonumuzun ismi de navigateSearch olsun ve bizden parametre olarak kullanıcı kategori seçtiyse seçilmiş kategorinin id sini, ürün seçtiyse seçilmiş ürünün id sini ve kullanıcının arama textbox ına girmiş olduğu arama kelimesini parametre olarak alsın. Bu parametreleri ve en başta MasterPage imizde tanımlamış olmuşduğumuz window.SearchType değişkenin o anki değerini kullanarak kullanıcıyı doğru sayfaya yönlendirsin.
function navigateSearch(categoryID, productID, searchKeyword) {
    if (window.SearchType == 1) {
        /*Kullanıcı autocompletten herhangi bir kategori veya ürün seçmeden enter a basmıştır.*/
        /*
        Öncelikle textbox ın değerinin boş olup olmadığını kontrol edelim. Boş değilse kullanıcı aradığını gelen sonuçlar içinde bulamamış ve seçtiği kategoride detaylı arama yapmak için enter a basmıştır.
        Bu durumda categoryID ve textbox a girmiş olduğu kelime ile arama sayfasına(SearchResult.aspx) yönlendiriyoruz.*/
        if (searchKeyword == '') { return false; }
        else {
            window.location.href = '../Pages/SearchResult.aspx?c=' + categoryID + '&k=' + searchKeyword;
        }
    }
    else {
        /*Kullanıcı autocompletten bir kategori veya ürün seçmiştir.*/
        if (productID == -1) {
            /*productID nin değeri -1 ise kullanıcı kategori seçmiş demektir. Bu durumda seçmiş olduğu kategorinin id si ile Category.aspx sayfamıza yönlendiriyoruz.*/
            window.location.href = '../Pages/Category.aspx?c=' + categoryID;
        }
        else if (productID > 0 && categoryID > 0) {
            /*productID nin değeri 0 dan büyükse kullanıcı ürün seçmiş demektir. Bu durumda seçmiş olduğu ürünü id si ve ürünün categoryID si ile Ürün sayfasına yönlendiriyoruz. Ürün seçilmişse categoryID nin değeri 0 dan büyük gelecektir ama biraz paranoyaklık yapıp onuda kontrol etmekte fayda var...*/
            window.location.href = '../Pages/Product.aspx?c=' + categoryID + '&p=' + productID;
        }
    }
}


navigateSearch fonksiyonumuzun son hali yukarıdaki gibidir. Sayfa yönlendirme işinide büyük ölçüde tamamladığımıza göre artık autocomplete fonksiyonumuzu geliştirmeye devam edebiliriz.
İlk olarak, arama sonuçlarına göre autocomplete mizde ürünleri ve ürün kategorilerini göstereceğimiz için, kullanıcı gösterilen sonuçlardan birini seçmiş ise window.SearchType değişkenimizin değerini olarak set ediyoruz ve sayfa yönlendirmesini yapması için navigateSearch fonksiyonumuzu çağırıyoruz. Bunu autocomplete mizin select option unda yapıyoruz.
select: function (event, ui) {
            window.SearchType = 0; //Search Type = Autocomplete Search
            /*Kullanıcı productID nin değerine göre Category.aspx sayfasına veya Product.aspx sayfasına yönlendirilecek.*/
            navigateSearch(ui.item.category, ui.item.productID, searchKeyword);
            return false;
}


Category.aspx sayfasınamı, yoksa Product.aspx sayfasınamı yönlendirceğimizi ise navigateSearch fonksiyonumuza parametre olarak verdiğimiz productID değişkeninin değeri belirleyecektir. Bu yüzden autocomplete mizde gösterdiğimiz kategoriler için özel bir productID değeri belirlemeliyiz. Şimdi hem bunun için hemde kategorilerin gösterimini render etmek için kullanacağımız bir AutoCompleteCategoryItem nesnesi oluşturalım. Bu nesne üzerinde productID property miz olacak ve değerini -1 olarak set ederek bunun aslında bir ürün değilde kategori olduğunu belirtmiş olacağız. Bunun için projenizin durumuna göre farklı çözüm yollarıda kullanabilirsiniz.

function AutoCompleteCategoryItem(item) {
    var categoryItem =
    {
        label: item.categoryName,
        value: item.categoryName,
        category: item.category,
        categoryName: item.categoryName,
        productID: -1
    }
    return categoryItem;
}



AutoComplete mizdeki kategori itemlerınıda render ederken oluşturduğumuz categoryItem nesnesini kullanacağız.
Peki kullanıcı arama textbox ına birşeyler yazdı ve autocomplete den herhangi bir item seçmeden enter a basarsa ne olacak? Bu durumda kullanıcının texbox a girmiş olduğu değer ve seçmiş olduğu kategorinin id si ile arama sayfamıza (SearchResult.aspx) yönlendireceğiz. Bu işlemi ise autocomplete mizin searchoption ununda yapabiliriz. search option unda sadece window.SearchType değişkenimizin değerini 1 olarak set ediyoruz. Sayfa yönlendirmesini ise arama textbox ımızın keyup yada keydown event inde keyCode u kontrol ederek yapacağız. Şimdilik sadece autocomplete mizin search option ununu yazıyoruz.
search: function (event, ui) {
            window.SearchType = 1; //Search Type = Text Search
            /*Kullanıcı enter a basarsa SearchResult.aspx sayfasını yönlendirelecek.*/
}


Sıra AutoComplete mizin  itemlarını istediğimiz gibi render etmeye geldi.

 $.widget("custom.catcomplete", $.ui.autocomplete, {
    
 });


bu işlem için AutoComplete mizin widget fonksiyonunu kullanacağınız. Önce Ürünleri göstereceğimiz itemları ürün resimlerinide gösterecek şekilde yeniden render ediyoruz.

/*Ürünlerin sadece adlarını değil resimlerinide göstereceğiz. Bu yüzden AutoCompletimizin itemlerını kendimize göre render ediyoruz.*/        
_renderItem: function (ul, item) {
            if (item.productID != '0') {
                return $('<li></li>')
                .data('item.autocomplete', item)
                .append("<a style='line-height: 30px;'><span style='width: 33px; height: 30px; float: left;'><img width='30' height='25' alt='' style='padding-right: 2px;' src='" + item.imageUrl + "'/></span>" + item.label + "</a>")
                .appendTo(ul);
            }
}


Şimdi de kategorilerimizi render edelim.

/*Arama sonuçlarında ürünlerimizi category lerine göre gruplayarak göstereceğiz. Bu yüzden AutoCompletimizin menüsünüde kendimize göre render ediyoruz.*/
_renderMenu: function (ul, items) {
            var self = this,
                currentCategory = '';
            $.each(items, function (index, item) {
            if (item.category != currentCategory) {
                    var categoryItem = AutoCompleteCategoryItem(item);
                    var categoryElement = $('<li></li>')
                                            .data('item.autocomplete', categoryItem)
                                            .append("<a style='text-decoration: underline; font-weight: bold;'>" + categoryItem.categoryName + "</a>");
                    ul.append(categoryElement);
                    currentCategory = item.category;
                }
                self._renderItem(ul, item);
            });
}


autoComplete fonksiyonumuzun son hali aşağıdaki gibidir.

function autoComplete(objID) {
    var handlerUrl = '../Handlers/AutoCompleteSearch.ashx';//Arama için kullanacağımız Generic Handler ımızın pathi
    var searchKeyword = ''; //Arama yapılan kelime
    $.widget("custom.catcomplete", $.ui.autocomplete, {
    /*Ürünlerin sadece adlarını değil resimlerinide göstereceğiz. Bu yüzden AutoCompletimizin itemlerını kendimize göre render ediyoruz.*/
        _renderItem: function (ul, item) {
            if (item.productID != '0') {
                return $('<li></li>')
                .data('item.autocomplete', item)
                .append("<a style='line-height: 30px;'><span style='width: 33px; height: 30px; float: left;'><img width='30' height='25' alt='' style='padding-right: 2px;' src='" + item.imageUrl + "'/></span>" + item.label + "</a>")
                .appendTo(ul);
            }
        },
        _renderMenu: function (ul, items) {
        /*Arama sonuçlarında ürünlerimizi category lerine göre gruplayarak göstereceğiz. Bu yüzden AutoCompletimizin menüsünüde kendimize göre render ediyoruz.*/
            var self = this,
                currentCategory = '';
            $.each(items, function (index, item) {
            if (item.category != currentCategory) {
                    var categoryItem = AutoCompleteCategoryItem(item);
                    var categoryElement = $('<li></li>')
                                            .data('item.autocomplete', categoryItem)
                                            .append("<a style='text-decoration: underline; font-weight: bold;'>" + categoryItem.categoryName + "</a>");
                    ul.append(categoryElement);
                    currentCategory = item.category;
                }
                self._renderItem(ul, item);
            });
        }
    });

    $("#" + objID).catcomplete({
        source: function (request, response) {
            $.ajax({
                url: handlerUrl, //arama işleminin yapılacağı .ashx dosyamızın pathi
                contentType: 'application/json; charset=utf8;',
                data: {
                    keyword: request.term, //arama textbox ımıza girilen değer.
                    categoryID: $('#cmbCategory').val() //dropdownlist imizden seçilen kategori
                },
                success: function (data) {
                    searchKeyword = request.term; //daha sonra kullanmak için arama yapılan kelimeyi bir değişken üzerinde tutuyoruz.
                    response($.map(data, function (item) {
                    /*gelen arama sonuçlarımızdaki datayı kullanmak istediğimiz şekilde mapliyoruz.*/
                        return {
                            label: item.ProductName,
                            value: item.ProductName,
                            productID: item.ProductID,
                            imageUrl: item.ProductImageUrl,
                            category: item.CategoryID,
                            categoryName: item.CategoryName
                        }
                    }));
                },
                error: function (xmlHttpRequest) {
                }
            });
        },
        select: function (event, ui) {
            window.SearchType = 0; //Search Type = Autocomplete Search
            /*Kullanıcı productID nin değerine göre Category.aspx sayfasına veya Product.aspx sayfasına yönlendirilecek.*/
            navigateSearch(ui.item.category, ui.item.productID, searchKeyword);
            return false;
        },
        search: function (event, ui) {
            window.SearchType = 1; //Search Type = Text Search
            /*Kullanıcı enter a basarsa SearchResult.aspx sayfasını yönlendirelecek.*/
        },
        open: function () {
            $(this).removeClass('ui-corner-all').addClass('ui-corner-top');
        },
        close: function () {
            $(this).removeClass('ui-corner-top').addClass('ui-corner-all');
        }
    });
}


Son olarak arama textbox ımızın keydown un da keyCode u kontrol ederek eğer enter a basılmışsa arama sayfa yönlendirme işlemimizi yapacak olan navigateSearch fonksiyonumuzu tetikletiyoruz. Bunun için öncelikle form un submit ini kapatmamız gerekiyor.

<form id="form1" runat="server" onsubmit="return false;">



$('#txtSearch').keydown(function (event) {
                if (event.keyCode == '13') {
                    /*form un submit ini kapatıyoruz ve arama textboxının key enter ında aramamızı yönlendirecek fonksiyonumuzu çalıştırıyoruz.*/
                    navigateSearch($('#cmbCategory').val(), 0, $('#txtSearch').val());
                }
});


Biraz uzun sürsede sonunda bitti, uygulamanın kaynak kodlarını buradan indirebilirsiniz.
Sonuçlar için ekran görüntüleri.







































3 yorum:

  1. Paylaşılan kodlar ile sayfaları oluşturdum ancak hata ile karşılaşıyorum. Dosyayı indirme linki çalışmıyor, linki güncelleme şansınız var mı?

    YanıtlaSil
  2. Elinize sağlık. Hocam paylaşılan kodlara erişilemiyor. Güncelleyebilir misin?

    YanıtlaSil
  3. Bu yorum yazar tarafından silindi.

    YanıtlaSil