Bu makalemizde, Can.JS'nin EJS ve View sınıfları ile JavaScript Template konusunu işleyeceğiz. Bir önceki makalemizdeki son örneğimizde, Observe sınıfında tuttuğumuz bir değeri View ile ekrana bastırmıştık. Şimdi sıra, bu işin aslını öğrenmeye geldi.

İlk olarak "Bunlara neden ihtiyacımız olsun ki??" sorusuna cevap verelim. Hatırlarsan, Can.JS serisinin ilk makalesinde SPA (Single Page Application) yapmanın hayallerini kurmuştuk. Bu hayalimizde, kullanıcının aksiyonlarına göre ekrandaki HTML içeriğe yeni içerikler ekliyor ve kaldırıyorduk. Ancak eklenecek ve kaldırılacak HTML içeriklerin sayısı yüzlere, hatta binlere ulaştığı zaman, bu işi JavaScript içerisinden yönetmek çok da gerçekçi gözükmemişti. Örneğin bu statik bir HTML sitesi olsa, değişiklik yapmak istediğimiz HTML belgesini açar, gerekli değişikliği yapardık. Ancak tüm içerik JavaScript içerisinden dinamik olarak eklendiğine göre, ilgili HTML kodunu tutan değişkeni ara ki bulasın. Bu ilk mesele.


İkinci meselenin (daha doğrusu çözümünün) adı Seperation of Concern. Bu prensip der ki, "Kardeşim, bir adam hem proje yöneticisi olup, hem takım yönetip, hem de kod yazamaz" (Kariyerinin üç yılını bu şekilde geçirmiş ve sonunda bunların hiçbirini adam akıllı yapamadığını fark etmiş biri olarak konuşuyorum). Aynı durum yazdığımız kodlar için de geçerlidir. HTML, CSS ve JavaScript üç ayrı dildir. Bunların üçü de farklı amaçlara hizmet ederler ve üçünün de mümkün mertebe birbirinden ayrılmış olması gerekir. JavaScript içerisinden JQuery ile hardcoded HTML ve CSS eklemek başlangıçta kolay gelir ancak eklenen elemanların sayısı arttıkça yönetim zorlaşır, Refactoring çok zor, Unit Testing neredeyse imkansız hale gelir. Oysa bunlar büyük projelerin olmazsa olmaz parçalarıdır. Bu yüzden iş mantığını içinde barındıran JavaScript kodumuz ile, kullanıcı ile etkileşime giren ön yüz bileşenlerini birbirinden ayırmak gerekir.

JavaScript Templating kavramı burada yardımımıza yetişir. Bu kütüphaneler sayesinde, HTML kodlarımızı (ve onlarla ilgili CSS kodlarımızı) kendi dosyalarında saklarız. Ardından JavaScript içerisinden bu dosyaları yükleyerek ekranda gösteririz. Üstelik bu kütüphanelerin kendilerine has notasyonları sayesinde, JavaScript tarafından gönderdiğimiz nesneler, HTML kodlarımız içerisinde istediğimiz noktaya yerleşebilirler. Böylece statik HTML yerine, dinamik içeriklere sahip olabiliriz. Henüz "Controller" konusuna girmediğimiz için, bu noktada MVC konusuna girmek istemiyorum. Ancak bil ki, bu makalede MVC'nin V'sine giriş yapıyoruz.

Not  : Türk programcılarda nedense MVC'yi ASP.Net'e mal etme gibi bir yatkınlık var.  Oysa MVC ilk konuşulmaya başlandığı zaman (1970'ler) henüz ne MS-DOS (1981) ne de HTML (1980) ortalarda yoktu. Bill amca da henüz 20'lerinde bir delikanlıydı.

JavaScript Templating kütüphaneleri Can.JS'ye has bir çalışma değil. İşin aslı, Can.JS kendi içerisinde yeni bir Templating kütüphanesi de barındırmıyor. Bunun yerine popüler kütüphanelerden EJS ve Mustache'ı varsayılan olarak kullanıyor. Bu iki kütüphanenin yetenekleri hemen hemen aynı olmasına karşın, vaktiyle ASP ile kod yazmış kişiler, muhtemelen EJS'de kendilerini daha rahat hissedeceklerdir.

Pekala, çok fazla konuştuk. Haydi biraz aksiyon görelim. El clasico, HTML belgemizi hazırlıyoruz.

<!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>
</head>
<body>
</body>
</html>


Ardından "program.js" dosyamızı hazırlıyoruz.

"use strict";

var obj;

$(document).ready(function () {

    var data = {
        Name: "Ali"
    };

    var html = can.view("test.ejs", data);

    $("body").append(html);

});

Her zamankinden farklı olarak, bu dosyaların yanına aşağıdaki içerik ile "test.ejs" adında yeni bir dosya daha oluşturuyoruz.

<%= this.Name %>


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.


İnceleyelim bakalım, neler yapmışız. Öncelikle "test.ejs" dosyasından başlayalım. Bu dosya, yukarıda iki paragraf boyunca bahsettiğim JavaScript Template dosyası. Bu dosya içerisine HTML olarak ne yazarsak, statik olarak sayfaya basılır. Ancak "<%=  xxxx  %>" şeklindeki bir yazımda, "xxxx" yerine yazdığımız ifade, değişken gibi işlem görür ve kendisi yerine içerisinde sakladığı değer sayfaya yazılır. Bunu cebimize koyduk.

Bir de "program.js" dosyasına bakalım. İlk olarak bir nesne tanımlıyoruz.

    var data = {
        Name: "Ali"
    };

Nesnemizin içerisinde "Name" adında tek bir değişken yer alıyor.

    var html = can.view("test.ejs", data);

Burada "html" adında bir değişken tanımlıyoruz ve değer olarak, Can.JS'nin View sınıfını veriyoruz. Bu sınıf iki parametre kabul ediyor. İlk parametre, yüklenecek Template dosyasının göreceli adresi (Dosyalar yan yana durduğu için direk dosya ismini veriyoruz), ikinci parametre ise, bu Template'e geçilecek olan nesnemiz.

Bu satır işletildiği anda, Template dosyamızın içeriği okunuyor. İkinci parametre olarak geçtiğimiz nesnemiz, Template içerisinde "this" olarak kabul ediliyor (Bu durumda nesnemiz içerisindeki Name değişkeni de "this.Name" oluyor). İlk olarak "<%=  xxxx  %>" şeklindeki ifadeler varsa, bunların taşıdıkları değerler statik hale çevriliyor, sonrasında da dosya içerisinde bulunan diğer statik ifadeler (Ki bu örneğimizde hiç yok) ile birleştirilerek ortaya çıkan HTML sonuç "html" değişkenine atanıyor.

    $("body").append(html);

Son olarak, elde ettiğimiz değeri HTML belgemize ekliyoruz. Sonuçta, gönderdiğimiz nesne ile etkileşime girebilen ama HTML kodlarını JavaScript kodumuzdan uzak tutan bir yapıya kavuşmuş oluyoruz.

Bu örnek, JavaScript Templating'in çalışma mantığını anlamak için yeterli ancak yeteneklerini anlayabilmemiz için fazla basit. "program.js" dosyamızın içeriğini aşağıdaki gibi değiştirelim.

"use strict";

var obj;

$(document).ready(function () {

    var data = {
        UserList: [{
                Name: "Ali",
                Age: 40
            }, {
                Name: "Veli",
                Age: 30
            }]
    };

    var html = can.view("test.ejs", data);

    $("body").append(html);

});

"test.ejs" dosyasının içeriğini de aşağıdaki gibi değiştirelim.

    <% for(var i = 0; i < this.UserList.length; i++) { %>
  • <%= this.UserList[i].Name %>, <%= this.UserList[i].Age %>
  • <% } %>

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.


"program.js" dosyasındaki tanımlı nesnemizi biraz zenginleştirdik. Artık nesnemiz içerisinde "UserList" adında bir dizi var ve dizinin her bir elemanı da, "Name" ve "Age" değişkenlerini içeren birer nesne içeriyor. Gözle görülür başka bir değişikliğimiz yok.

Bir de "test.ejs" dosyasına bakalım. Hmm, burada yeni bir şeyler var. Öncelikle <% %> işaretleri içerisinde olmayan, "<ul>" ve "<li>" ifadelerini görüyoruz. Bunlar statik ifadeler ve aynen kabul ediliyor.

<% for(var i = 0; i < this.UserList.length; i++) { %>

Bir önceki örneğimizde "<%=  xxxx  %>" ifadesini görmüştük ve demiştik ki, "xxxx" değişken gibi işlem görür ve kendisi yerine içerisinde sakladığı değer HTML'e yazılır. Ama burada "=" işareti olmadan, "<%  xxxx  %>" şeklinde bir kullanım görüyoruz. Bu ifade şeklinde de, "xxxx" yerine yazılan kısım, JavaScript ifadesi olarak işlem görür. Örneğin burada "for" döngüsünü kullanmışız. Bu yüzden döngünün "{ }" işaretleri arasında yer alan kısmı, döngü miktarınca tekrar ediliyor. Yine burada nesnemiz içerisindeki diziye "this.UserList" şeklinde ulaştığımıza dikkat edelim. Mantık yine aynı, nesnemiz "this" olarak geçiyor.

Not  : Buraya yazabileceğin JavaScript ifadeleri ile atabileceğin taklaları bir düşün.


<li><%= this.UserList[i].Name %>, <%= this.UserList[i].Age %></li>

Burada hibrit bir kullanım görüyoruz. Statik HTML ifadeleri ile dinamik ifadeler birlikte kullanılıyor. Bu satır döngü içerisinde olduğu için, döngü adedince işletiliyor ve dizinin elemanları okunuyor.

Sonuç olarak aşağıdaki gibi bir HTML söz dizimi elde ediliyor ve ekrana yazılıyor.

<ul>
<li>Ali, 40</li>
<li>Veli, 30</li>
</ul>
JavaScript Templating'in tadına varmaya başladık inşallah. Artık projemizde binlerce HTML ekranı olsa da, eğer ki Template dosyalarını düzgün klasörleyebilirsek, değiştirmemiz gereken kısmı kolayca bulur ve başka bir yeri bozmadan üzerinde çalışabiliriz.

Ancak yine de bir sıkıntımız var. Template dosyalarının içeriği, ihtiyaca göre fazla kompleks olabilir. Bu durumda, üzerinde çalışmamız gereken kod bloğu, yine çalışma sonrası psikolojik rehabilitasyon gerektirecek boyutlara ulaşabilir. Böyle durumlara düşmemek için, Nested Template tekniği ile tanışıyoruz. İlk olarak, aşağıdaki içerikle ve "test2.ejs" adında yeni bir dosya oluşturalım.

<%= this.Name %>, <%= this.Age %>



Ardından "test.ejs" dosyamısının içeriğini aşağıdaki şekilde güncelleyelim.

    <% for(var i = 0; i < this.UserList.length; i++) { %>
  • <%= can.view.render("test2.ejs", this.UserList[i]) %>
  • <% } %>


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.


Kabul ediyorum, buradaki örnekte iç içe Template kullanmak işimizi pek kolaylaştırmadı ama önemli olan işin mantığını öğrenmek. Aslında burada yapmaya çalıştığımız iş çok kolay. Bir Template içerisinde "can.view.render" fonksiyonu vasıtasıyla, başka bir Template'i çağırıyoruz ve o anda döngüde elimize gelen dizi elemanını, ikinci Template'e nesne olarak geçiyoruz. Kompleks Template'lerde bu şekilde işi daha basit hale getirebiliriz ve daha da önemlisi, kod tekrarının önüne geçeriz (DRY prensibi).

Template konusunu az çok tamamladık gibi. Makaleyi sonlandırmadan önce, EJS'de kullanılan "<%" yazım şekillerinin tamamını gösteren bir örnek vermek istiyorum. "program.js" dosyamızın içeriğini aşağıdaki şekilde değiştirelim.

"use strict";

var obj;

$(document).ready(function () {

    var data = {
        Name: "Ali"
    };

    var html = can.view("test.ejs", data);

    $("body").append(html);

});


"test.ejs" dosyasının içeriğini de aşağıdaki şekilde değiştirelim ("test2.ejs" dosyasına ihtiyacımız kalmadı).

<%= this.Name %>

<%== this.Name %>

<%%== this.Name %>

<%# Yorum satırı %>


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.


Dikkat edersen, örneğimizdeki nesnemizde bulunan değişkende artık HTML anlamı olan bir ifade bulunuyor. Bunu ilk olarak "<%=  xxxx  %>" ifadesiyle yazdırıyoruz ve görüyoruz ki, HTML yorumlama yapılmadan düz şekilde ekrana yazdırılmış.

Ardından çift eşittirli yeni bir ifade şekli görüyoruz ("<%==  xxxx  %>"). Bu şekilde yazdığımızda, HTML yorumlanarak ekrana yazdırılıyor ve bold halde "Ali" ifadesini görüyoruz.

Üçüncü olarak "<%%==  xxxx  %>" şeklinde bir ifade görüyoruz. Aslında burada önemli olan "<%%" kısmı. Bu durumda ifade, Template Engine'den yorumlanmadan çıkıyor. Peki buna niye ihtiyaç duyalım ki? Kod üreten bir uygulama (Code Generation) buna güzel bir örnek olabilir.

Son olarak "<%#  xxxx  %>" şeklinde bir ifade görüyoruz ki, bunun hiçbir çıktı üretmediğini, Template dosyamızın içerisine yorum satırı eklemek için kullanıldığını anlıyoruz.

Not  : "<% %>" şeklinde JavaScript kodunu çalıştıran 5. yöntemi zaten biliyorsun.

Çok şükür sonuna geldik. Ayarı yine kaçırdım galiba. Haydi bu makalede öğrendiklerimizi özetleyelim.
  • MVC, ne ASP.Net, ne de Web ile ortaya çıkmış bir kavram değildir.
  • Bu makale ile MVC'nin V'sine giriş yapmış olduk (Hatta geçmiş olduğumuz nesneler ile kısmen M'sine de girdik).
  • Seperation of Concern ve diğer prensipler sebebiyle JavaScript Templating'e ihtiyacımız var.
  • Can.JS, dahili olarak EJS ve Mustache Template Engine'leri destekliyor.
  • EJS'nin kendine has notasyonunu kullanarak, statik HTML içerikler ile Template'e geçtiğimiz nesnemizdeki değerleri birlikte kullanabiliyor ve ortaya dinamik içerikler çıkartabiliyoruz.
  • Template dosyaları içerisinde ihtiyaca yönelik olarak direk JavaScript kodlarını çalıştırmamız da mümkün.
  • İhtiyaca göre Template içerisinde Template (Nested Template) kullanabiliyoruz.


Yorum Gönder

 
Top