Bu makalemizde, Can.JS'nin Control sınıfı ile MVC'nin C'sine giriş yapacağız. Bir önceki makalemizde View ve EJS sınıfları ile kullanıcı ön yüzüne ait bileşenleri programımıza nasıl ekleyeceğimizi görmüştük. Şimdi sıra, eklediğimiz bu bileşenler ile etkileşime girecek kodları yazmaya geldi.

Bundan üç yıl öncesinde henüz Can.JS ortalıklarda yokken, JavaScriptMVC adında birkaç kütüphanenin birleşmesinden oluşmuş devasa bir Framework vardı. Bu Framework'ün MVC tarzında SPA (Single Page Application) geliştirmekten sorumlu alt kütüphanesinin adı JQueryMX'di. JQueryMX'in de aynı Can.JS gibi View ve EJS sınıfları vardı. O zamanlar, sayfaya eklenen her bir View için bir adet de Controller sınıfından türetilmiş bir sınıf kullanırdık ki, bu sınıfın içerisinde, View'da bulunan bileşenlerin Event Hander'ları ve ihtiyaç duydukları diğer alt fonksiyonları bulunurdu. O zamanki mantık, sayfaya View ekle, ardından bir Controller ekleyip bunu View'a bağla şeklindeydi.


Zaman içerisinde JQueryMX kütüphanesi, Can.JS ve JQuery++ şeklinde iki ayrı parçaya ayrıldı. MVC ve SPA ile ilgili kısımlar Can.JS tarafında kaldı ve daha da geliştirildi. JQuery++ ise meşhur JQuery kütüphanesine alt seviyede ek özellikler katan bir eklenti haline geldi.

Bu makalede göreceğimiz Control sınıfı, aslında eski JQueryMX kütüphanesindeki Controller sınıfının gelişmiş bir versiyonu olarak karşımıza çıkıyor. Temel fark ise şurada; Eskiden sayfaya bir View ekleyip, sonrasında buna bir Controller bağlarken, artık sayfaya sadece bir Control ekliyoruz ve sayfaya View ekleme işini de Control içerisinde gerçekleştiriyoruz. Bu açıdan bakınca, Control sınıfı sanki bir Widget olarak görev yapıyormuş gibi gözüküyor ve standart MVC Controller'dan daha kolay kullanım/kontrol edilebilirlik özellikleri sergiliyor.

Not  : Control sınıfı, ilk başlarda gördüğümüz Construct sınıfından türediği için, bu sınıfın tüm özelliklerini içerisinde barındırır ancak kullanım amaçları çok farklıdır. Bu bilgiyi sadece Control sınıfının yeteneklerini daha iyi anlaman için veriyorum.

Bu kadar teorik bilgi yeter. Haydi şu aleti bir de iş başında görelim. Her bir örnekte yeni bir özellik ekleyerek, adım adım gideceğim. İlk olarak aşağıdaki kodlarla HTML belgemizi hazırlayalım.

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1254" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="can.jquery-1.1.7.min.js"></script>
<script src="program.js"></script>
<script src="testControl.js"></script>
</head>
<body>
</body>
</html>

Ardından aşağıdaki kodlarla "test.ejs" adındaki JavaScript Template'imizi hazırlayalım.

<div id="TestArea">
<button id="WriteText">Yaz</button>
<button id="ClearText">Temizle</button>
<button id="CloseView">Kapat</button>
<span id="TextField"></span>
</div>

Programımızın giriş kapısı olan "program.js" dosyamızı hazırlayalım.

"use strict";

var obj;

$(document).ready(function () {

    var control = new TestControl("body");

});

Son olarak, "program.js" dosyamızın içerisinden çağırdığımız ve bu makalenin ana konusunu olan "testControl.js" dosyamızı hazırlayalım.

"use strict";

can.Control("TestControl", {

    init: function (el, options) {

        this.element.html(can.view("test.ejs", {}));

    }

});

Bu örneğin hazır yazılmışını çalıştırmak için buraya tıklayabilirsin. Karşına aşağıdaki gibi bir sayfanın gelmesi gerekiyor.


Hemen hatırlatayım. Butonlara basınca hiçbir şey olmayacaktır çünkü bunlar için gerekli Event Handler kodlarını henüz yazmadık. Peki ne yaptık? Bir önceki makalemizde gördüğümüz gibi EJS Template dosyamızı hazırladık, ki bu sefer içerisinde herhangi bir JavaScript kodu da içermiyordu. Normalde biz bu Template dosyasını, "program.js" dosyası içerisinde bir View sınıfı yardımıyla ekrana eklerdik. Burada ise bu işi "TestControl" sınıfına bıraktık. Daha önce de söylediğim gibi, "Control" sınıfı "Construct" sınıfından türediği için, aslında şu anki hali sadece bir "Construct" sınıfı gibi çalışıyor ve "init" fonksiyonunda View ile Template'i ekrana ekliyor.

Yalnız burada dikkat edilecek tek bir husus var. "program.js" dosyasının içerisinde "control" nesnesini tanımlarken "TestControl" sınıfına "body" değerini geçtik. Bu değer, "TestControl" sınıfına "this.element" nesnesi içerisinde geçti. Bu yapı, Control sınıflarının sayfadaki hangi eleman içerisinde etkileşime gireceğini ve sayfanın geri kalanıyla ilgilenmemesi gerektiğini belirten bir yöntem. Biz de View'ımızı, "init" fonksiyonu içerisinde "this.element" nesnesinin (ki burada body'e tekabül ediyor) içerisine yerleştirdik.

Buraya kadar Control sınıfının pek bir hayrını görmedik. Hatta bu kadarını Construct sınıfı ile de yapardık, haklısın. Şimdi "testControl.js" dosyasının içeriğini aşağıdaki kodlarla değiştirelim.

"use strict";

can.Control("TestControl", {

    init: function (el, options) {

        this.element.html(can.view("test.ejs", {}));

    },

    "#WriteText click": function (el, options) {

        $("#TestArea #TextField").text("Ali");

    },

    "#ClearText click": function (el, options) {

        $("#TestArea #TextField").empty();

    }

});

Bu örneğin hazır yazılmışını çalıştırmak için buraya tıklayabilirsin. Karşına aşağıdaki gibi bir sayfanın gelmesi gerekiyor.


Burada ilk iki butonumuza birer tane Event Handler ekledik. Nasıl yaptığımıza bakalım. Control sınıflarında fonksiyon tanımlarken, fonksiyon ismini tırnak işaretleri içerisinde yazarsak, bunun özel bir anlamı olur. Bu durumda, tırnak işaretleri arasındaki ilk kelime CSS Selector mantığında dinlenecek elemanı gösterir. Burada başına "#" işareti koyduğumuz için "id" değerine göre Event Handler bağlıyoruz. Yine tırnak işareti içerisinde boşluktan sonra gelen kelime ise, dinlenecek olayı belirtir. Biz burada "click" olayını dinledik ancak diğer olayları da aynı şekilde dinleyebilirdik.

Event Handler fonksiyonlarımızın içerisi klasik JQuery ifadeleri, açıklamaya gerek yoktur sanırım. Ancak burada bir noktaya dikkat çekmek istiyorum. İçeriği değiştirilecek elemanı direk "#TextField" ismi ile de seçebilirdim ancak bunun yerine, EJS Template'in en dışına yerleştirdiğim Div'in ismi ile birlikte seçtim. Bunun sebebi, yazdığımız program büyüdükçe, ekrandaki elemanlara aynı isimleri verebilme ihtimalimizden kaynaklanıyor. Bu durumda, hiç fark etmediğimiz başka bir elemana müdahale etme ihtimalimiz ortaya çıkar. Bundan kaçınmak için, "içerisinde bulunduğumuz Div'in içerisinde bulunan şu isimli eleman" şeklinde seçim yapmak, bizi olası hatalardan koruyacaktır.

Sıra geldi, Control sınıfının en basit ama en önemli yeteneğine; Sayfaya eklediğimiz bir Control'ün sayfadan kaldırılması.

Bu serinin ilk başında kurduğumuz hayali hatırlıyorsan, ekrana dinamik olarak HTML elemanları ve bunların Event Handler'larını eklemeyi, işimiz bittiğinde de bunları kaldırmayı düşünmüştük. Sayfaya eklenen elemanlar ve onlardan gelecek olayları dinleyen Event Handler'lar iki ayrı bileşendir. Örneğin sayfaya bir buton ve bu butonun Click olayını dinleyen bir Handler eklesek, butonu sayfadan kaldırsak dahi olmayan butonun Click olayını dinleyen Handler halen sayfada kalır. Eğer ki bu durumu gözden kaçırırsak, kullanıcı on dakika boyunca yazdığımız programı kullanıp View'lar arasında dolaşırsa, sayfamızda binlerce zombi Event Hander kalır ve sebebini anlayamadığımız şekilde programı yavaşlatmaya, ekranda donmalara sebep olmaya ve hatta tarayıcının kilitlenmesine yol açar. Bu konu hakkındaki daha detaylı bilgiye bu makaleden ulaşabilirsin.

Can.JS'nin Control sınıfı, bu işi bize çok kolaylaştırıyor. Yapmamız gereken tek şey, Control sınıfının müdahil olduğu HTML elemanını ortadan kaldırmak. Böylece Control sınıfı içerisinde tanımlanmış tüm Event Hander'lar otomatik olarak ortadan kaldırılıyor. Hemen uygulamalı olarak görmek için "testControl.js" dosyasının içeriğini aşağıdaki kodlarla değiştirelim.

"use strict";

can.Control("TestControl", {

    init: function (el, options) {

        this.element.html(can.view("test.ejs", {}));

    },

    "#WriteText click": function (el, options) {

        $("#TestArea #TextField").text("Ali");

    },

    "#ClearText click": function (el, options) {

        $("#TestArea #TextField").empty();

    },

    "#CloseView click": function (el, options) {

        this.element.empty();

    }

});

Bu örneğin hazır yazılmışını çalıştırmak için buraya tıklayabilirsin. Karşına aşağıdaki gibi bir sayfanın gelmesi gerekiyor.


Gördüğün gibi "this.element.empty();" komutu ile View'ımızı ve buna bağlı Event Handler'ları sayfamızdan kaldırmış olduk.

Control sınıfı Construct sınıfından türediği için, Construct sınıfının sahip olduğu (Inheritance ve function overriding gibi) tüm özellikleri içerisinde barındırır. Bunlara ayrıca değinmiyorum. Bunların haricinde bir de Templated Events konusu var ki, şimdilik buna ihtiyacımızın olacağını sanmıyorum. Eğer olursa, projeler sırasında bu konuya da değinirim. Ama illa öğrenmek isteyen olursa buradan konu hakkında bilgi edinebilir.

Control sınıfı hakkında söyleyebileceğim son sözleri özetlersek, MVC Pattern'in C'sinin yeniden elden geçirilmiş haline benzetilebilir. Control sınıfı içerisinden sunucu tarafına bağlanarak gerekli veriler alınıp bir Observe (veya ileride göreceğimiz Model) sınıfı içerisine yerleştirilerek, sayfada gösterilmek üzere View sınıfına verilebilir. Ardından ekrandaki görüntü ile etkileşime giren kullanıcıdan alınan veriler yine bir Observe (veya Model) sınıfı vasıtasıyla Control sınıfı üzerinden sunucu tarafına gönderilebilir ve MVC yaşam döngüsü tamamlanmış olur. Baştan sonra tam bir örnek yapmadan MVC kavramının havada kaldığının farkındayım ama bunu yapmak için gerekli olan tüm sınıfları bitirmeyi bekliyorum. Biraz daha sabretmek lazım.

Böylece Control sınıfı hakkındaki makalemizi de tamamlamış olduk. Son olarak öğrendiklerimizi özetleyelim.
  • Control sınıfı, bilinen standart MVC Controller'ın yeniden elden geçirilmiş bir versiyonudur.
  • Ekrandaki View'larla etkileşime girmenin haricinde, ekrana View ekleme sorumluluğunu da üzerine alarak, daha çok bir Widget karakteristiğini yansıtır.
  • Control sınıfı, daha önce gördüğümüz Construct sınıfından türemiştir ve onun tüm özelliklerini üzerinde barındırır.
  • Etkileşimde bulunduğu View üzerindeki elemanların Event'lerini yakalamak için CSS Selector mantığında bir yapı sunar.
  • Etkileşimde bulunduğu View'ın sahneden kaldırılması ile birlikte, Control sınıfı içerisindeki tüm Event Handler'lar da otomatik olarak sahneden kaldırılır ve Zombi Event Handler sendromuna sebep olmaz.


Yorum Gönder

 
Top