19 Ağustos 2012 Pazar

Knockout JS ve NodeJS ile Kullanımı

Knockout js bize zengin ve etkileşimli kullanıcı arayüzleri oluşturma imkanı veren bir javascript kütüphanesi.Dinamik olarak değişen arayüz bileşenleriniz mevcutsa kullanım ve geliştirme kolaylığı ile öne çıkan bir kütüphane.

Binding mekanizması ve observable (gözlenebilirlik) yapısı sayesinde otomatik güncelleme yapabilmemize imkan sağlayan bir yapı.

Basitleştirilmiş bir şekilde geliştirme mimarisini ele almamız gerekirse MVVM(Model-View-ViewModel) dizayn modelini kullanarak geliştirme yapıyoruz. Html ile geliştirdiğimiz view, javascript tarafında ele aldığımız View Model yapısı dinamikliği sağlayan katmanlarımız.

ViewModel yapısı modelimizi ve bu modelin ne gibi özelliklere sahip olduğu bilgisini içeren javascript kodu.
Örnek vermek gerekirse;
ViewModel(Javascript)
// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel({
    this.adi"Ertuğrul";
    this.soyadi"Taş";
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

View (html)
<p>Adi: <strong data-bind="text: adi"></strong></p>
<p>Soyadi: <strong data-bind="text: soyadi"></strong></p>

olarak tanımladığımız sayfamızı çalıştırdığımızda model de tanımlanan adı ve soyadı alanlarını
view katmanında data-bind"text" ifadesi ile view katmanına bağlıyoruz.

Peki bu yapı bize ne kazandıracak tanımladığımız model içinde yer alan özellikleri

observable hale getirerek model de yapılan değişikliğin tüm referanslarda etkili olmasını sağlayabiliriz.

Yukarıda verdiğimiz örneği geliştirelim, adı ve soyadı alanlarını input olarak alalım değişen değerlerin 

sayfa içerisindeki diğer referanslara yansımasını gözlemleyelim. Bunun için ViewModel içerisinde adi ve soyadi 
özelliklerini observable yapalım.

// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel({
    this.adi"Ertuğrul";
    this.soyadi"Taş";
    this.adiko.observable("Ertuğrul");
    this.soyadiko.observable("Taş");
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

Html sayfamıza da ilgili input bileşenlerini ekleyelim

<p>Adi: <input data-bind="value: adi" /></p>
<p>Soyadi: <input data-bind="value: soyadi" /></p>
<p>Adi: <strong data-bind="text: adi"></strong></p>
<p>Soyadi: <strong data-bind="text: soyadi"></strong></p>

Yukarıda yer alan kodu çalıştırdığımızda input alanlarında yapacağımız değişiklikler onblur event'ı ile tetiklenecek focus input alanından çıktıktan sonra sayfa içerisinde yer alan tüm referanslara ilgili değişiklik yansıyacaktır. Yukarıda yer alan kod parçalarının çalışan versiyonlarını git adresinden indirebilirsiniz.

Temel olarak kullanımın üstünden geçtiğimize göre artık knockout kütüphanesini kullanarak nodejs ile daha kompleks örnekler hazırlayalım.

Daha önceki yazılarımızda anlattığımız şekilde WebMatrix ile boş bir nodejs projesi oluşturalım.
Yine daha önce değindiğimiz gibi proje içerisine Express Framework'ünün son sürümünü kuralım.

KnockoutJS download adresinden knockout.js 2.1.0 sürümünü indirelim.

Oluşturduğumuz nodejs projesi içerisine static isminde bir klasör oluşturalım. Bu klasör içerisine script adında bir klasör daha oluşturalım.knockout-2.1.0.js dosyasını script klasörü içerisine kopyalayalım.
Daha sonra script klasörü altında viewmodels adıyla bir klasör açalım.Bu klasör knockout yapısında kullanacağımız viewmodel javascript dosyalarını koyacağımız klasör.

static klasörü altına view ismiyle bir klasör daha oluşturalım. Bu klasör altında görüntüleyeceğimiz html dosyaları yer alacak.

Klasör Yapısı


Dosyalarımızı oluşturmaya başlamadan önce nodejs ile html sayfalarını render edebilmemiz için ejs paketine ihtiyacımız olacak.

Command Prompt üzerinden proje dizinimize geldikten sonra
npm install ejs komutunu çalıştırarak ejs modülünün kurulmasını sağlayalım. Daha sonra server js içerisinde html dosyalarının render edilebilmesi için

app.engine('html', require('ejs').renderFile);
satırını ekleyelim.

Bunun yanı sıra static klasörü altında yer alan static içeriğimizin 
(javascript dosyaları,resimler,static html dosyaları vs.) kullanılabilir olabilmesi için server.js içerisine 

app.use(express.static(__dirname + '/static'));

satırını eklememiz gerekiyor.

server.js'nin son hali aşağıdaki gibi olmalıdır.


var express = require('express'),
    app = express();
 
app.use(express.static(__dirname + '/static')); 
app.engine('html', require('ejs').renderFile);

app.listen(3000);


Şimdi html, viewmodel dosyalarımızı oluşturmaya başlayabiliriz. Daha önceden static -> script dizini altında oluşturduğumuz 
"viewmodels"dizinine sağa tıklayarak yeni bir javascript dosyası oluşturalım. 
Table ve collection'lar ile ilgili bir örnek yapacığımız için "tableViewModel.js" ismini verelim.


dosya içerisine modelimizin ve modelimizin sergileyeceği davranışları içeren kod blogumuzu yazalım.

// Rezervasyon Sınıfı
function KoltukRezervasyon(isim, parametreYemek) {
    var self = this;
    self.isim = isim;
    self.yemek = ko.observable(parametreYemek);
}
 
// ViewModel
function RezervasyonViewModel() {
    var self = this;
 
    //yemek Listesi
    self.yemekListesi = [
        { yemekAdi: "Standard (sandwich)", fiyat: 0 },
        { yemekAdi: "Premium (Adana Kebap)", fiyat: 34.95 },
        { yemekAdi: "Ultimate (Karışık Kebap)", fiyat: 290 }
    ];    
 
    // Rezervasyon listesi
    self.koltuklar = ko.observableArray([
        new KoltukRezervasyon("Salim", self.yemekListesi[0]),
        new KoltukRezervasyon("Ertuğrul", self.yemekListesi[0])
    ]);
      self.koltukEkle = function() {
        self.koltuklar.push(new KoltukRezervasyon("Ertuğrul", self.yemekListesi[0]));
    }
}
 
ko.applyBindings(new RezervasyonViewModel());

İlk oluşturduğumuz "KoltukRezervasyon" sınıfı içerisinde koltuk sahibinin adını ve tercih ettiği yemek nesnesini tutuyoruz.

Daha sonra ViewModel içerisinde katalog olarak kullanacağımız yemek listesini ve
 rezervasyon Listesinin başlangıç halini tanımlıyoruz. View tarafında rezervasyon eklemek için koyacağımız butona 
basıldığında yeni bir rezervasyon eklemesi için "koltukEkle" metodumuzu tanımlıyoruz.

"ko.applyBindings" metodu tanımladığımız ViewModel'in kullandığımız sayfada geçerli olmasını ve gerekli bağlama işlemlerinin 
yapılmasını sağlayan metod.



"view" klasörü altında yeni bir html dosyası oluşturarak "tableView.html" ismini verelim.

Modelimizde tanımladığımız rezervasyon,yemek ve fiyat bilgilerini görüntüleyeceğimiz tablo yapısını oluşturalım.

tableView.html

<!DOCTYPE html>
 
<html lang="tr">
    <head>
        <script type="text/javascript" src="../script/knockout-2.1.0.js"></script>
      
    </head>
    <body>
    <h2>Rezervasyonlar</h2>
 
<table>
    <thead><tr>
        <th>Yolcu Adı</th><th>Yemek</th><th>Fiyat</th><th></th>
    </tr></thead>
    <!-- Todo: Generate table body -->
   <tbody data-bind="foreach: koltuklar">
    <tr>
        <td data-bind="text: isim"></td>
        <td data-bind="text: yemek().yemekAdi"></td>
        <td data-bind="text: yemek().fiyat"></td>
    </tr>    
</tbody></table>
        <button data-bind="click: koltukEkle">Rezervasyon Ekle</button>
          <script type="text/javascript" src="../script/viewmodels/tableViewModel.js"></script>
    </body>
</html>

sayfamızın head kısmında daha önceden "script" klasörü altına kaydettiğimiz "knockout-2.10.js" dosyasını import ediyoruz.
Daha sonra rezervasyonları listelemek üzere tablomuzu oluşturuyoruz. tbody içerisinde "data-bind" ile 
ViewModel içerisinde tanımladığımız "koltuklar" listesini tablomuza bağlıyoruz.

Daha sonra her bir koltuk içerisinde yer alan KoltukRezervasyon sınıfının özelliklerini 
hücrelere bağlama işlemini gerçekleştiriyoruz. "isim" özelliğini direkt kullanırken 
observable olarak tanımladığımız "yemek" özelliğini metod olarak çağırarak kullanıyoruz. 
Bu işlem observable olarak tanımladığımız tüm nesneler için geçerli.

En altta ise yeni bir rezervasyon eklemek için kullanacağımız butonumuz mevcut. 
Yine data-bind özelliğine atanmış view model içerisinde tanımladığımız "koltukEkle" metodunu görüyoruz.

Tüm bu satırların en altında tanımladığımız "tableViewModel.js" dosyasının sayfaya
 eklendiğini görüyoruz. Bu satırın en altta olmasının sebebi knockout kütüphanesinin 
oluşturulmuş html nesneleri üzerinden çalışıyor olması. 
Eğer bu satırı en üste alacak olursak sayfa açılışında ilgili html elemanları 
oluşturulmadan çalışacağı için null gidecek olarak gelecek elemanlardan
 dolayı sorun yaşarız.JQuery kütüphanesinin onReady metodu kullanılarak tüm dom 
oluşturulduktan sonra çalışacak şekilde geliştirilmesi mümkün olsa da
şimdilik buna gerek görmedik.


çalıştıracağımız sayfamız hazır olduğuna göre server.js içerisine bu sayfayı 
çalıştıracak request'i tanımlayalım.

app.get('/tableView', function(req, res) {
    res.render("../static/view/tableView.html");
});

Yukarıda yer alan kod blogunu server.js içerisine eklediğimizde tableView
 url(localhost:3000/tableView)'i ile yapılan request sonucunda oluşturmuş olduğumuz 
"tableView.html" sayfası görüntülenecektir.

Örneğimizi biraz daha geliştirip tablomuzu güncellenebilir hale getirelim. 
view html'imizi aşağıdaki gibi güncellememiz yeterli olacaktır.

<!DOCTYPE html>
 
<html lang="tr">
    <head>
        <script type="text/javascript" src="../script/knockout-2.1.0.js"></script>
      
    </head>
    <body>
    <h2>Rezervasyonlar</h2>
 
<table>
    <thead><tr>
        <th>Yolcu Adı</th><th>Yemek</th><th>Fiyat</th><th></th>
    </tr></thead>
    <!-- Todo: Generate table body -->
   <tbody data-bind="foreach: koltuklar">
    <tr>
       <td><input data-bind="value: isim" /></td>
        <td><select data-bind="options: $root.yemekListesi, value: yemek, optionsText: 'yemekAdi'"></select></td>
        <td data-bind="text: yemek().fiyat"></td>
    </tr>    
</tbody></table>
        <button data-bind="click: koltukEkle">Rezervasyon Ekle</button>
          <script type="text/javascript" src="../script/viewmodels/tableViewModel.js"></script>
    </body>
</html>



Gördüğünüz gibi artık tabloda yer alan elemanlarımız değiştirilebilir durumdalar.
Çalıştırdığınızda yemek değiştiğinde fiyat alanınında otomatik olarak güncellendiğini
 göreceksiniz.Bunun sebebi "yemek" nesnesinin "observable" olarak tanımlanmasıdır.

"knockout.js" ile dinamik sayfalar geliştirmek son derece basit ve akıcı.
Daha detaylı knockout örnekleri için Knockout Tutorials sayfasını ziyaret edebilirsiniz.

Örnek kodların tamamını git adresimizde bulabilirsiniz. Knockout Simple projesi html ve
 javascript ile yaptığımız örnekleri içerirken, Knockout Example projesi tüm bu yazdığımız
 kodların yer aldığı nodejs projesidir. Uygun sürümlerin kullanıldığından emin olmanız için proje içerisinde
 kullanılan modül ve sürüm bilgileri aşağıda yer almaktadır.

git: Knockout Sample
git: Knockout Example

Sürüm Bilgileri:





Hiç yorum yok:

Yorum Gönder