"bir yazılımcının not defteri.."

18 Eylül 2011 Pazar

Microsoft ajax - Basit Kullanım Örnekleri

Hiç unutmam bundan 3 yıl kadar önce bir bayan programcı meslekdaşım msn den bana “ gökhan ajax diye birşey çıktı!! ” dediğinde ben de ona: “ ne yeni çıkması yahu, ben yıllardır kullanıyorum ” demiştim. Bunun üzerine şaşırmış ve : “ ciddi misin?? way beee... ” demişti; ben de büyük bir gururla cevap verdim tabiki : “ elbette!! bulaşık deterjanımdan hiç şaşmam.... ”   :)) Bu vesile ile hem bulaşıkları küvetin içinde elde yıkadığımı, hem de web teknolojisi olan ajax tan habersiz oldumu ilan edip iki pot birden kırmıştım :)

Şaka bi yana, (ki aslında şaka da değil buna çok benzer bir konuşma gerçekten olmuştur :)) ,, garip bulduğum bu teknoloji dünyasına ansızın giren “ajax” kelimesi aslında bildiğiniz JavaScript tir. Ancak büyük yazılım ekiplerinin karmaşayı azaltmak için oluşturdukları daha basitleştirilmiş üst düzey kütüphanelerinde XML ile iletişim ve asenkron veri iletimine ağırlık verildiği için kısaltılmış cümle olarak adına AJAX (asenkron javasacript and XML) denmiştir. Bildiğiniz gibi bunlardan biri de Microsoft Ajax Libary dir. İlk çıktığı zamanlarda sadece .NET programcıları ve Visual Studio için düşünülen bu kütüphane şu anda tamamen open source ve tüm web ortamı için kullanılabilr durumdadır. Hatta Mutfakta bile! :)

Eh kullandık... lakin geçenlerde başıma gelen küçük bir vukuat ile güvendiğim dağlara biraz kar yağdı. Yaptığım projenin ajax işlemleri Visual Studio da çalıştı sunucuda çalışmadı. 2 gün uğraştım sonra da IE (internet explorer) da çalıştı, Chrome da çalışmadı. Forumlara girdiğimde efendim git bilmem hangi javascript dosysını bul içindeki şu kodu şununla değiştir diyordu. Ve bunu diyen bir MS programcısı idi. Kendisine sormak istedim doğrusu: eğer ben bunu resmen hack leyerek çalıştıracaksam düzgün çalıştığını nasıl idda ediyorsunuz? ya da gecelerin ve kodda hata yaptığımı sanıp saç baş yolarak harcadığım saatlerin hesabını kime soracağım ??  :)

Nihai sonuç olarak şimdiki düşüncem odur ki : Microsoft Ajax Libary içindeki extended (üst seviyeli) kontrolleri (ModalPopup, CollapsiblePanel, DynamicPopulate, vs...) kullanırken bazı noktarda çok kullanışlı olabilmelerine rağmen bazı noktalarda da çözdüklerinden daha çok sorun çıkardıklarını görmüş durumdayım. Ya da gereğinden çok daha fazla kod eklediklerinden uygulamayı yavaşlatabilmekteler. Örneğin bir GridView a TemplateColumn dan bir Extended Ajax Tool u eklerseniz doğal olarak aynı kontrolü her satır için ayrı ayrı yaratacaktır. Bu da bir yığın javascript kodunun uygulamanıza gereksiz yere eklenmesi demektir. Aslında sorun pratik çözümünde çoğu zaman buna gerek hiç yoktur. Ancak Control Tool Kit in üst seviyeli yapısından dolayı basitliğinin külfeti kod kirliliği olabilmektedir.

Peki bu üst düzey controlleri kullanmadan MS Ajax ı kullanamaz mıyız? Elbette kullanabiliriz. Şöyleki, MS Ajax Extended Controlleri diğer bir adı ile Microsoft Ajax Control Tool Kit, aslında MS in temel bir Ajax kütüphanesinin üzerine inşa edilmiş daha üst düzey bir yapıdır. Altında çalışan temel yapı da gayet hoş bir ajax katmanıdır. Üstelik bu katmanı kullanmayı öğrenmek olayın hakimiyeti çok daha fazla sizin elinize bırakacaktır. Daha az sorun ve kesinlikle daha hızlı çalışacaktır. Yanlış anlaşılmasın Control Tool Kit gereksiz demiyorum. Ben de halen kullanmaya devam ediyorum. Ama sırf hazırını kullanacam diye de yeri geldiğinde daha iyisini kendimiz yapmaktan kaçınmayalım. Üstelik Yine MS AJAX ı kullanacağız. Dilerseniz çok kullanılan temel işlemlerden başlayalım. Hepsini buraya yazmama imkan yok, kaldıki hepsini ben de bilmiyorum. Ama sık kullanılanlara basitçe gözatalım :


setVisible
web de en çok kullanılan atraksyonlardan biri olan başımızın belası görün / gizle işlemidir. Bunu yapmanın pek çok yolu var. En yaygın kullanımı CSS özelliklerini değiştirip görünür yada gizli yapmaktır. Bu komut ile olay gayet basit bir şekilde kodu bulandırmadan yapılır. Fonksyonun formal parametreleri :

Sys.UI.DomElement.setVisible( element , bool );

kullanım şekli ise :
Sys.UI.DomElement.setVisible($get("Button1"), false); //gizle
Sys.UI.DomElement.setVisible($get("Button1"), true); //göster

$get in içinde çift tırnak arasındaki elemen adı eğer server taraflı bir kontrol ise şu şekilde de belirtebilirdik ki bu daha sağlıklı olurdu :

Sys.UI.DomElement.setVisible($get("<%=Button1.ClientID %>"), false);




getVisible
setVisible komutunun tamamlayıcı özellik taşıyan bu komut, parametre olarak verilen elementin ekranda görünür durumda olup olmadığını bize geri bildirir. Dönüş değeri true ya da false dir. Özellikle runtime esnasında dinamik olarak bir elemantin görünürlük durumunu bilmek isteyediğimiz durumlarda kullanışlı olabilir :

var b = Sys.UI.DomElement.getVisible($get("Panel1"));
alert(b); //true ya da false

if (b) {      //görünür durumda ise
Sys.UI.DomElement.setVisible($get("Panel1"), false);   //gizle
}

gibi....




setLocation
2. büyük baş belamız olan yine manuel javascript ve CSS ler ile yapageldiğimiz olaylardan biri de ekrandaki bir elementin yerini runtime da dinamik olarak belirlemek / değiştirmektir. Neyseki bu komut ile artık oldukça kolay :

Sys.UI.DomElement.setLocation( element , int X ,int Y);

şablonundaki komutumuzun ilk parametresi bir web elementi, diğer iki parametre ise ekranın top ve left parametreleri. Yani üstten ve soldan pixel cinsinden uzaklık. Oldukça basit olan bu komutun örnek kullanımı ise şöyle :

Sys.UI.DomElement.setLocation($get("Button1"), 300, 200);

veya elementimiz server kontrolü ise, bu daha iyidir :

Sys.UI.DomElement.setLocation($get("<%=Button1.ClientID %>"), 300, 200);

tabiki pratikte bir Button u ekranda sağa sola fırlatmamız pek gerekmeyecektir :) Örnek açısından burada button kullandım. Biz daha çok div paneller, resimler gibi görsel unsurları taşıyacağız.




getBounds
setLocation komutunu tamamlayıcı nitelikte olan bu komutumuz bir elementin ekran koordinatlarını ve genişlik / yükseklik (width - height) değerlerini elde etmemizi sağlar. Tek parametre alır bu da söz konusu bilgilerini almak istediğimiz elementtir. Ve kendisini çağıran yere de bu özellikleri içerek JavaScript nesnesini yollar. Kullanımı şöyledir :

var obj = Sys.UI.DomEle ment.getBounds($get("Panel1")); veya,
var obj = Sys.UI.DomElement.getBounds($get("<%=Panel1.ClientID %>"));

obj.x      //Panel1 in pixel cinsinden soldan uzaklığı
obj.y     //Panel1 in pixel cinsinden üstten uzaklığı 

obj.width    //Panel1 in pixel cinsinden genişliği 
obj.height    //Panel1 in pixel cinsinden yüksekliği





addHandler
Html elementlerine olaylar atamak ve bu olayları da javascript fonksyonlara bağlamak için kullanılan basit pratik bir komuttur.

$addHandler(element, “olayadı”, fonksyon_adı);

buradaki ilk element malum fatmagül ün suçu ne misali olayın kendisine yapılacak olan elementtir, orta kısımda tırnak arasındaki parametre olay adıdır; click, dblclick, blur, change, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, mouseup, vs.. gibi olaylardan biri olabilir. Son formal parametremiz ise ismi doğrudan (tırnak arasına ALINMADAN yazılan) Javascript fonksyonunun adıdır.

Bazı event durumlarında bu javascript fonksyonuna durum bilgisini parametre olarak aktarır. Örneğin mousedown, keypress gibi olaylarda tıklanan mouse ya da basılan klavye tuşunun bilgisini fonksyona aktarmak için gizliden bir değer yollar; tüm yapmamız gereken fonksyonda bir formal parametre tanımlayıp bu değeri kapmaktır. Hemen bir örnek ile durumu izah edelim :

function pageLoad() {
    $addHandler($get("<%=this.Panel1.ClientID %>"), "mousedown", moss_indi);
    //veya:   $addHandler($get("Panel1"), "mousedown", moss_indi);
}



function moss_indi(e) {
alert("mouse indi");

alert(e.x);
alert(e.y);

//değişik kullanım şekilleri, 
alert(e.offsetY);
alert(e.offsetX);

alert(e.clientX);
alert(e.clientY);

alert(e.deltaX);
alert(e.deltaY);

 if (e.button == Sys.UI.MouseButton.leftButton)  {
    $get("<%=this.Label1.ClientID %>").innerHTML = "mouse indii";
    $get("<%=this.Panel1.ClientID %>").style.position = "relative";
    $get("<%=this.Panel1.ClientID %>").style.top = e.clientY + 'px';
    $get("<%=this.Panel1.ClientID %>").style.left = e.clientX + 'px';;
 }
}


Şimdi burada neler olup bitti biraz konuşalım:
önce $addHandler ile bir web elementine mousedown olayı tanmladık. Yani bu elementin üzerinde mouse in bir tuşu tıklanırsa bu olay tetiklenecekti. Bu tetiklenecek fonksyonun da adı “moss_indi” olacak. Dikkat ederseniz moss_indi fonksyon tanımını formal parametre kısmına e parametresi ekledik,, bu fonksyona gönderilen durum bilgisini kapmak içindir. Böylece bu parametrenin kaptığı bilgiyi sorgulayarak neler olup bittiğini daha detaylı öğreneceğiz... ki if ile sorguladığımız da tam olarak budur : “ if (e.button == Sys.UI.MouseButton.leftButton)” satırı ile tam olarak neye basıldığının bilgisini alıyoruz. Eğer istese idik .rightButton ya da .middleButton da diyebilirdik. Aynı şeyi klawye tuşları için de yapabiliriz. Şöyleki :

function pageLoad(sender, args) {
    $addHandler(document, “keydown”, OnKeyPress);
}


function OnKeyPress(args) {
   if (args.key.Code === Sys.UI.Key.esc) {
        //birşeyler yap....
 }
}


Benzer şekilde burada da klavye tuşlarını kontrol ettik, bu şekilde neredeyse bütün tuşları kontrol edebilirsiniz.

Bir başka vakada diyelim ki benimki gibi çok güzel bir blog hazırladınız ve insanların yazdıklarınızı kopyalamasını istemiyorsunuz. Ne yapabiliriz? Tabiki select olayına kod yarak basitçe bunu engelleyebiliriz, şöyleki :

function pageLoad() {
    $addHandler(document, “selectstart”, olmassss);
}


function olmassss() {
   return false;
}

gibi basit bir ifade ile select işlemini engelleyebiliriz. Yada yukarıdaki mouse event lerinde olduğu gibi sağ mouse tuşunu da bloke edebilirsiniz. Ama aslına bakarsanız konu web oluca hiçbir şekikde hırsızlığı engelleyemezsiniz. En azından işlerini biraz güçlerştirebilirsiniz :)



removeHandler
adından da anlaşılacağı üzere addHandler in tam tersidir. Yani bir elementten bir olay tetikleyicisini kaldırmamızı sağlar. Yazılış şekli de aşağı yukarı aynıdır, yani :

$removeHandler($get(“Button1”) , “cliclk” , “oynat”);

bu komut sonrasında Button1 e tıklandığında artık “oynat” isimli JavaScript fonksyonu tetiklenmeyecektir. Olayı kaldırma işleminin başta gereksiz olduğunu düşünsem de, sonra farkettim ki bu tür komutlar sayfanın dinamik kullanımı esnasında gerekli olabilir.





celarHandlers
bir web elementine yüklenmiş tüm olayları iptal etmek içindir. Yazım şekli oldukça basittir :

$clearHandlers(element);

yani

$clearHandlers($get(“Panel1”));

ya da

$clearHandlers($get("<%=this.Panel1.ClientID %>"));

clearHandlers komutunu uyguladığınızda artık o elementin olay tetikleyicilerini   " yok "  kabul edebilirsiniz :)




Biraz da ‘Still Yakalamaca’ Oynayalım :)
$get komutu ile birlikte kolayca bir elementin still özelliklerine de sahip olabiliriz. Şöyle ki :

$get(“element1”).style.top = “200px”;
$get(“element1”).style.position = “fixed”;

ya daa...

$get(“element1”).className = “class1”;


başka bir örnek de rek değitirme ile ilgili olsun :

var color = ‘red’;
var div = $get('div');
div.style.color = color;

son bir örnek de görünmez kılmak ile yapalım :

var lab = $get(“Label1”);
lab.style.display = ‘none’;

gibi...


Ajax libary içide css class lar ile ilgili olan 3 faydalı komut şöyle :

addCssClass
Adından da anlaşılacağı üzere bir elemente bir Css sınıfı eklemek için kullanılır. Normal koşullara gayet kolay yapabildiğimiz bu işi runtime esnasında dinamik olarak yapması açısından oldukça kullanışlıdır. Kullanımı :

Sys.UI.DomElement.addCssClass(element, “css_class_adı”);

yani :

Sys.UI.DomElement.addCssClass( $get("Panel1") , "c1" );

ya da :

Sys.UI.DomElement.addCssClass( $get("<%=this.Panel1.ClientID %>") , "c1" );

gibi...

bu komut varolan Css özelliklerin üzerine ekleme yapar. Eğer elementin daha önceden Css nitelikleri varsa onlar aynen devam ederi. Şayet çakışma söz konusu ise yani eski niteliğin hükmü devam eder.



removeCssClass
addCssClass ın tam tersi olarak removeCssClass elementten belirtilen Css class özelliklerini çıkarır. Kalan Css özellikleri devam eder. Kullanım şekli gene aynı :

Sys.UI.DomElement.removeCssClass(element, “css_class_adı”);

yani :

Sys.UI.DomElement.removeCssClass( $get("Panel1") , "c1" );

ya da :

Sys.UI.DomElement.removeCssClass( $get("<%=this.Panel1.ClientID %>") , "c1" );

gibi...



toggleCssClass
toogle bir elementin Css clasını belirtilen class ile değiştirir.

Sys.UI.DomElement.toggleCssClass($get("Panel1"), "c1");

komutu ile Panel1 in eski Css sınıfı kalkacak ve c1 isimli stil atanacaktır. Yine runtime esnasında dinamik işlemlerde bu komut işimize oldukça yarayacaktır.



containsCssClass
bu elementin Css sınıfı bu mudur? sorusunun yanıtırını boolean (true / false) olarak döndürür. Kullanımı :

Sys.UI.DomElement.containsCssClass(element , "still_class");

Şayet belirtilen elementin Css sınıfı "still_class" da belirtilen sınıf ise true döner. aksi duruma malumunuz false döner.

var c = Sys.UI.DomElement.containsCssClass($get("Panel1"),, "c1");
alert(c);

dediğimizde eğer Panel1 c1 sınıfına sahip ise ekrana true yazan uyarı gelecektir.




MS AJAX ı kullanarak browser kontrolü yapalım :
evet biliyorum ms ajax browser a göre davranıyor ve bize ayrı ayrı kod yazma derdinden kurtarıyor. Ama yine de hala bazen kullanıcının hangi browserda olduğunu bilmek istediğimiz durumlar olabiliyor. Küçük bir uygulama ile hemen buna da bir gözatalım :

if (Sys.Browser.agent == Sys.Browser.Safari)
  //birşeyler yap...

Söz konusu değişlen,
Sys.Browser.Opera
Sys.Browser.InternetExplorer
Sys.Browser.Safari
Sys.Browser.Firefox

değerlerinden biri olabilir. Chrome ise bildiğim kadarı ile Safari ile aynı motoru kullanıyor. bunun da tespitini şöyle yapabiliriz :

alert(Sys.Browser.name);

versiyonunu dahi elde etmek isteyeceğiniz ileri işlemler olur mu bilmiyorum ama onu da :

alert(Sys.Browser.version);

komutu ile elde edebilirsiniz.



PostBack anında donuklaşan buttonlar :
ASP.NET programcılarının sık karşılaştıkları bir sorun da buttona iki kez basılması sendromudur. Yani diyelimki buttona tıklandığında form DB ye insert olacak; ve sunucunuz da o esnada iyi gününde değil, postback süresi biraz uzun. Kullanıcı ilk click inin hemen ardından beklemeden ikinci kez buttona basabiliyor. Bu da istenmeyen çift kayıt durumlarının ya da artık orada yapılan her ne ise iki kez işlemesine sebep oluyor.  .NET ilk çıktığında bize bir kullanıcı postback başlattığında süreç bitene kadar başka birşeye basamayacağını söylenmişti; ama nafile...  Hem bu durumlardan kurtulmak, hem de bugünden itibaren oluşturacağımız süper interaktif görünümlü web form ları (!) için buttonlarımız işini bitirene kadar onu pasif durumda getirmeli; ve içindeki metni de örneğin : yükleniyor.. yapılıyor.. kaydoluyor..  gibi değiştirirsek çok daha şık bir form elde ederiz. Evet biliyorum çoğunuz bu durumlarla zaten karşılaştınız ve herkes kendince yöntemlerle önlemler aldı. Hatta bunlar aşağıdakine göre çok daha kısa ve pratik çözümlerdi. Ama burada Ms Ajax ile basit kullanımları örneklediğimden şöyle çözüyorum :

    <script language=javascript>

        function pageLoad() {            
            var manager = Sys.WebForms.PageRequestManager.getInstance();            
            manager.add_beginRequest(OnBeginRequest);
            manager.add_endRequest(OnEndRequest);
        }


        var GlobalSubmitButtonID = "Button1";
        var SubmitButtonID;


        function OnBeginRequest(sender, args) {
            SubmitButtonID = args.get_postBackElement().id.toLowerCase();

            if (SubmitButtonID === GlobalSubmitButtonID.toLowerCase()) {
                //eğer postback edilen bizim button ise 
                //postback esnasında disabled duruma getiriyoruz
                $get(GlobalSubmitButtonID).disabled = true;
                $get(GlobalSubmitButtonID).value = "Kaydediliyor...";
            }
        }


        function OnEndRequest(sender, args) {         
            //iş bittiğinde tekrar eski haline getirmekte fayda var :)
            $get(GlobalSubmitButtonID).disabled = false;
            $get(GlobalSubmitButtonID).value = "Kaydet";

        } 

    </script>


Aaşağı yukarı böyle; Burada dananın kuyruğunun koptuğu yer args.get_postBackElement() komutu. Çünkü bu şekilde PostBack e neden olan elementin ID sini elde ediyoruız. Bu şık komutu daha bir çok başka durumda kullanabiliriz. Buradaki örnekte ise; özellikle ekranda çok sayıda button olan, görünürde hiç postback etmeyen, hatta postback esnasında bile işine devam eden ileri seviyeli bir web formu düşünün? O zaman basit JavaScipt çözümleri yerine olaya çok daha hakim olmamızı sağlayan bu tür daha ileri durum kontrollerine ihtiyacımız olacaktır.

Elbette Microsoft Ajax ın küçük bir kısmı tüm bunlar; ama sıkça kullandığımız temel araçlar olduğunu düşünüyorum. Daha derinlemesine örneklerde ve başka yazılarda buluşmak üzere şimdilik hoşçakalın.


Hiç yorum yok: