Angularjs Proje Yönetimi

8 Eyl

Yazılım projelerinin geliştirilmesi sırasında karşılaşılan bazı genel problemler vardır. Bu problemler yazılımın Frontend veya Backend olmasına bağlı olmayan, sürecin gelişimi sırasında ortaya çıkan problemlerdir.

Projelerde istenen taleplere bağlı olarak yazılımda çok fazla kod olabilir. Kod sayısı arttıkça yazılımın çalışma performansı da düşmeye başlar. Bir süre sonra kodu yönetemez hale gelirsiniz. Artık kod sizi yönetmeye başlar ki bu durumda yeterki  çalışsın mantığıyla bir dizi mantıksız işler yapmaya başlayabilirsiniz. Bu gibi durumlarla başa çıkabilmek için uyguladığınız yöntemlerde kod sayısı artsa bile kodda karmaşıklığın oluşmaması gerekmektedir. Yani bir sene süren bir projede ilk gün nasıl kafa karışıklığı olmadan rahatça kod eklenebiliyorsa, son günde de aynı rahatlıkla kod eklemesi yapılabilmelidir. Modüler yapılar kullanarak bir şekilde kodun karmaşasını azaltabiliriz, bu sefer de modül sayıları artar ve iş süreleri uzamaya başlar.

Bu noktada işlerimizi önemli ölçüde kolaylaştıracak olan araçlar Framework’lerdir. Bizim yapmamız gereken bir takım işleri Framework’lere yüklemek zaman kazanmak açısından önemlidir. Her framework amaca uygun olmayabilir. Bu nedenle Framework seçiminde kolay kullanılabilirlik, sürekli güncellenme, performans ve geniş topluluklar tarafından kullanılıyor olmak önemlidir.

Angularjs bu açıdan bakıldığında yapılabilecek en doğru seçimlerden birisidir. Üretim ve destekleme tarafında Google vardır ve çok yaygın kullanılan bir Framework’dür. Kullanım açısından son derece kolaydır. Model ve View tarafındaki ayrımı yapabilmesi (MVC mimarisi) ve modüler geliştirmeye imkan sağlayan yapısı sayesinde kullanıcı dostu bir yapısı vardır.

Angularjs Yapı Taşları

Angularjs kendine özgü bir mimari üzerine geliştirilmiştir. Belli yapı taşları üzerine oturtulmuş bir düzen söz konusudur. Bunlar:

  • Module
  • Config
  • Route
  • Controller
  • View
  • Directive
  • Filter
  • Service
  • Factory

şeklinde sıralanabilir.

Angularjs Proje Yapılandırması

Angularjs ile yapılandırılacak projeler mimari açıdan önemlidir. Biz geliştiricilere düzgün kod yazabilmek için birçok imkanı sunan bir framewrok ile spagetti kod oluşturmamak lazım. Bu açıdan angularjs ile çalışırken dikkat edilmesi gereken bazı hususları aşağıda başlıklar halinde ele alınmıştır.

Modüler Yapı

Müşterinin her talebi için uygulamayı bölümlendirmek ve her bölüm için farklı bir modül oluşturulmalıdır. Geniş ölçekli bir uygulama geliştirirken her bileşeni tek bir modül altına toplamak yerine iş mantığına göre tasarlanmış birden fazla modül ile çalışmak daha uygun olacaktır. Örnek olarak Email Hizmeti veren bir uygulama için modüller şu şekilde olabilir:

angular.module("Epostalar", []);
angular.module("GelenKutusu", ["Epostalar"]);
angular.module("EpostaServisi", ["GelenKutusu"]);

Model Servisleri

Angularjs tarafından sunulan Dependency Injection yapısı sayesinde soyutlamalar kolayca yapılabilmektedir. Servis yapısı ile modüller arasında izolasyonlar yapılmalıdır. Bu sayede servisler veya modüller arasında kod aktarımı ile iletişim sağlanabilir.

Oluşturulan servisler tek bir görevi yerine getirmelidir. Örneğin HTTP protokolü üzerinden bir dış kaynak ile veri alış verişi yapacak olan bir servis sadece o kaynakla konuşmalıdır. Veriyi almışken servise hadi ekranda listeleme de yapın şeklinde ikinci bir görev verilmemelidir. Aksi taktirde hep karşısında durduğumuz karmaşıklık problemine doğru ilk adımı atmış oluruz.

Kod Yapısı

Mümkün olduğunca az kod satırlarıyla hazırlanmış, gerektiğinde servisler aracılığı ile haberleşebilen modüller oluşturulmalıdır. Servis, Controller ve Template gibi kod birimlerinin içerikleri sade anlaşılır ve kısa tutulmalıdır.

HTML tarafındaki bir DOM elemanları üzerinde Controller veya Service gibi yapılar içinden erişip doğrudan işlem yapmamalısınız.

Controller sınıflarından dış kaynaklara erişilmemelidir. Bu işlemi servisler aracılığı ile gerçekleştirip, ilgili servislere controller tarafından erişim sağlanmalıdır. Veri kümelerinin controller içerisinde depolanması da yanlış bir davranıştır.

Görünüm Yapısı

Görünüm tarafındaki HTML elementlerini depoladığımız yapılara template denir. Template içerisinde sadece HTML kodları ve Angularjs direktifleri olmalıdır. İş kuralları bu kısımda tanımlanmamalıdır. Kurallar template tarafından erişilen controller içerisinde tanımlanmalıdır. Aksi taktirde görünümle alakası olmayan kural belirleme sorumluluğu controller tarafından alınıp görünüm tarafına yüklenmiş olur.

Görünüm tarafında sürekli güncellenmesi gerekmeyen içerikler için TwoWayBinding yerine OneWayBinding tercih edilmelidir.

Proje Dizin Yapısı

Proje yapısı şekillendirilirken dikkat edilmesi gereken bir diğer yapı ise proje dizin yapısının oluşturulmasıdır. Kod birimlerinizi HTML, CSS, JS gibi özelliklerine ve Angularjs yapılarına göre ayırmak ve dizinlere aktarmak sık kullanılan bir yöntemdir.

Dizin
Yanlış Dizin Yapısı

Bütün controller dosyalarını Controllers dizini altında dizini altında toplamak, zamanla dizin içerisinde onlarca belki yüzlerce dosya birikmesine neden olacaktır. Bu durumda aradığımızı bulmak daha fazla zaman alacaktır. Örneğin bir EmailApplication projesi için GelenKutusu modülünün controller kodu Controllers dizininde aranacak ve görünüm için hazırlanan template kod dosyası ise Templates dizininde aranacaktır. Bu şekildeki proje tasnifi “türe göre tasnif” olarak adlandırılır. Türe göre tasnif edilen projeler zamanla projelerin karmaşık bir hal almasına neden olur.

Bunun yerine iş mantığına göre planlanmış bir dizin yapısı oluşturmak daha uygun bir yöntem olacaktır.

Uygun Dizin Yapısı
Uygun Dizin Yapısı

Email hizmeti ile ilgili iş kurallarını ve dosyalarını tabakalandırarak çalışmak daha uygun bir seçim olacaktır. Bu şeklide proje tasnifine ise “özelliğe göre tasnif” denir. Bu durumda Email listemizdeki kişilerle ilgili işlemlerin Contacts dizininde olduğunu özellik bakımından kolayca anlayabiliriz. Hem görünüm hem kullanım açısından sade ve anlaşılır bir yöntemdir.

Kodun organizasyon yapılandırması tamamen ekibinize veya size kalmış bir seçimdir. Bir dayatma söz konusu değildir. Temel nokta, kodun iyi bir şekilde ayrıştırılması ve ayrıştırılan bölümlerin yeni bir karmaşaya yol açmamasıdır.

Bu yazıda angularjs projeleri oluşturulurken dikkat edilmesi gereken önemli hususlardan bahsetmeye çalıştık. Umarım faydalı olmuştur. Bir sonraki yazıda görüşmek dileğiyle.

Angularjs ngResource ile RESTful veri iletişimi

4 Eyl

Bu yazıda angularjs ile proje geliştirirken REST servislere erişerek veri talep etmek için kullanılmak üzere hazırlanmış bir modül olan ngResource modülünü incelemeye çalışacağız.

ngResource modülü angular.js script dosyası içerisinde bulunmaz. Projemize ngResource modülünü dahil edebilmek için angular-resource.js javascript dosyasını projemize dahil etmeliyiz.

<script src="angular.js">
<script src="angular-resource.js">

Modülü bağımlı modül olarak projemize ekleyerek uygulamamıza yükleyebiliriz. Yükeleme işlemini şu şekilde yapabiliriz.

angular.module('app', ['ngResource']);

Yükleme işlemi gerçekleştikten sonra RESTful servislere erişmek için modül içerisinde bulunan $resource servisini kullanabiliriz. $resource servisi kendi içerisinde $http servisine bağımlıdır ve bu servis sayesinde sunucu ile iletişime geçebilir. $resource servisinin kullanım şekli kısaca aşağıdaki gibidir.

$resource(url, [paramDefaults], [actions], options);

Servisin REST uçları ile konuşabilmek için bazı metodları vardır. Bunlar:

{ 'get':    {method:'GET'},
  'save':   {method:'POST'},
  'query':  {method:'GET', isArray:true},
  'remove': {method:'DELETE'},
  'delete': {method:'DELETE'} };

Örnek olarak bir REST ucumuz aşağıdaki şekilde olsun. Bu uçla $resource servisi aracılığı ile işlemler yapmaya çalışalım.

  • http://location.bayramucuncu.com/api/location => GET  ile lokasyonlar listelenir.
  • http://location.bayramucuncu.com/api/location => POST ile yeni lokasyon ekler.
  • http://location.bayramucuncu.com/api/location/:id => GET tek lokasyon getirir.
  • http://location.bayramucuncu.com/api/location/:id => PUT lokasyon günceller.
  • http://location.bayramucuncu.com/api/location/:id => DELETE lokasyon siler.
angular.module('location.services')
 .factory('Endpoint', function($resource) {
    return $resource('http://location.bayramucuncu.com/api/entries/:id',
              {
                   id: "@id"
              },
              {
                   update: { method: "PUT" }
              }
    );
 });

Burada {update: { method: “PUT” }} şeklinde özel bir fonksiyon tanımlanmıştır. Çünkü  HTTP PUT metodu, $resource içerisinde standart bir kavram olarak ele alınmamıştır.

Diğer bir  parametre olan {id: “@id”} ise URL adresinin sonundaki “/:id” ifadesini değişken hale getirmek için tanımlanmıştır.

Artık controller içerisinde $resource servisinin metodlarını kullanabiliriz.

angular.module('location.controllers')
       .controller('LocationIndexCtrl', function($scope, Endpoint) {
           Endpoint.query(function(response){
              $scope.locations = response;
           });
       })
       .controller('LocationDetailCtrl', function($scope, Endpoint) {
           var parameter = { id: 1 };
           Endpoint.get(parameter, function(response){
              $scope.location = response;
           });
       })
       .controller('LocationCreateCtrl', function($scope, Endpoint) {
           var location = {
                name: "blue restaurant",
                lon: "123"
                lat: "456"
           };
           Endpoint.save(location, function(response){
              alert("new location created");
           });
       })
       .controller('LocationUpdateCtrl', function($scope, Endpoint) {
           var location = {
                name: "blue restaurant",
                lon: "123"
                lat: "456"
           };
           Endpoint.update({ id:1 }, location, function(response){
              alert("location updated");
           });
       })
       .controller('LocationDeleteCtrl', function($scope, Endpoint) {
           var parameter = { id: 1 };
           Endpoint.delete(parameter, function(response){
              alert("location deleted");
           });
})

Bu şekilde REST servisi işlemleri için her metoda karşılık bir controller oluşturmuş olduk. İsterseniz tek bir controller içerisine her HTTP metodu için bir fonksiyon da tanımlayabilirsiniz.

Angularjs ile asenkron işlemler gerçekleştirilirken kullanılan $promise nesnesine $resource servisi üzerinden erişmek de mümkündür.

angular.module('location.controllers')
       .controller('LocationIndexCtrl', function($scope, Endpoint) {
           Endpoint.query().$promise.then(
              function(response){
                 $scope.locations = response;
              },
              function(error){
                console.log("Hata oluştu!");
              }
           );
       })
})

Bu yazıda ngResource modülünün REST uçları ile nasıl konuşabileceğimizi incelemiş olduk. Bir sonraki yazıda görüşmek dileğiyle.

Javascript Array.prototype.slice.apply(arguments)

2 Tem

Geleneksel programlama dillerine göre bir çok yönden farklılık gösteren Javascript dilinde nesne oluşturma fonksiyonlar yardımıyla yapılır. Javascript dilinde, function tipleri normal programlama dillerindeki class benzeri işlev görür. Bir function tipinden yeni bir nesne oluşturmak için new anahtar sözcüğü kullanılır. function tipine dışarıdan gönderilen argümanlar arguments isimli bir iç değişkende tutulur. Aşağıdaki örnek, bir fonksiyona gönderilen argümanları listeleme işlemini göstermektedir.


function f(){
   return arguments;
}

console.log(new f());      // Ekrana [] yazar.
console.log(new f(1,2));   // Ekrana [1,2] yazar.
console.log(f(1,2));       // Ekrana [1,2] yazar.

Ekrana yazım şekilleri her ne kadar Array tipinde görünse bu diziler Array nesnesinin özelliklerini taşımazlar. Yani:


function f(){
   return arguments;
}

console.log(f(1,2) instanceof Array);    // Ekrana false yazar.

Çünkü oluşturulan nesneler Array tipinin push, pop, slice benzeri prototype özelliklerini taşımazlar. Bir fonksiyonun arguments üyesini Array tipine dönüştürmek için Array.prototype.slice.apply(arguments) şeklinde kullanmak gerekmektedir. Bu şekilde kullandığımızda, nesne içerisindeki argümanlar Array tipine dönüştürülmüş olur. Yani bu yöntem ile Array olmayan fakat ona benzeyen nesneleri Array tipine dönüştürür.


function f(){
   return arguments;
}

console.log(Array.prototype.slice.apply(f(1,2)) instanceof Array)
// Ekrana true yazar.

Bu özellikler Javascript dilinde ileri seviye işlemlerde önem arz etmektedir. Örneğin kütüphaneler oluştururken bizim sınıflarımızı kullanan kullanıcıların gönderdiği parametreleri bu şeklide alıp değerlendirmek durumunda kalabiliriz. Açık kaynak javascript kütüphanelerini inceleyerek dilin daha fazla özelliğini kavramak mümkündür.

Bir sonraki yazıda görüşmek dileğiyle.

 

Javascript Class ve Nesne Oluşturma

1 Tem

Javascript programlama dili, geleneksel programlama dillerindeki gibi gelişmiş özelliklere sahip olmasa da nesneye yönelik programlama açısından son derece esnek bir yapıya sahiptir. Bu yazıda nesneye yönelik programlamada önemli bir yer tutan class yapısını incelemeye çalışacağız.

Javascript dilinde class benzeri tanımlamalar fonksiyonlar yardımıyla yapılmaktadır. Class benzeri diyorum çünkü geleneksel programlama dillerindeki gibi class tanımlamak için özel bir yöntem yoktur. Her fonksiyon bir class olarak değerlendirilebilir ve her fonksiyonun new anahtar sözcüğü ile bir nesnesi oluşturulabilir.

1-Fonksiyon Tanımlamak

Normal bir Javascript fonksiyonu tanımlayarak aşağıdaki gibi bir class oluşturabiliriz.


function Map(name){
    this.name = name;
    this.version = "1.0.0";
    this.zoomLevel = 0;
    this.zoomin = zoomIn;
}

function zoomIn(){
    return this.zoomLevel + 1;
}

Yukarıda tanımlanan bir constructor fonksiyondur. Aynı zamanda class olarak değerlendirilir.  Bu class tipinde bir nesne aşağıdaki gibi oluşturulabilir.


var map = new Map("myMap");
map.version = 1.1.1;
map.zoomin();

2-Anti Pattern

Yukarıda tanımlama da zoomIn metodu Map calss dışında ayrı bir şekilde tanımlandığından  bir anti pattern oluşmaktadır. Kodun çalışması açısından hiç bir sorun yoktur. Ancak dışarıda tanımlanan her metod, global namespace içerisinde yer alacağından başka bir amaçla aynı isimde (zoomIn) bir metod tanımlandığında bu durum bir isim karışıklığına sebep olacaktır. Bu tür kirliliklerin önüne geçmek adına ihtiyaç duyulan metodlar constructor fonksiyonların içerisine tanımlanmalıdır.

function Map(name){
    this.name = name;
    this.version = "1.0.0";
    this.zoomLevel = 0;
    this.zoomin = function(){
           return this.zoomLevel + 1;
    }
}

Bu şekilde bir tanımlama kodda her hangi bir değişikliğe sebep olmayacaktır.

3-Metodların Prototype Şeklinde Tanımlanaması

2. maddede olduğu gibi metodları constructor fonksiyon içerisine tanımlayarak anti pattern oluşumundan kurtulmak mümkündür. Ancak bu durumun karşımıza çıkardığı bir dezavantaj vardır. Her nesne oluşturulduğunda zoomin() metodu yeniden oluşturulacaktır. Bu dezavantajı ortadan kaldırmak için zoomin() metodu prototype olarak tanımlanmalıdır.

function Map(name){
    this.name = name;
    this.version = "1.0.0";
    this.zoomLevel = 0;
}

Map.prototype.zoomin = function(){
    return this.zoomLevel + 1;
}

4-Doğrudan Nesne Tanımlamak

Şu ana kadar olan bölümlerde constructor fonksiyonlar yardımıyla sınıf simülasyonları olşuturduk ve new anahtar sözcüğü ile bu constructor fonksiyonlardan nesneler oluşturduk. Bu bölümde doğrudan nesneler tanımlamayı inceleyeceğiz.

Javascript dilinde doğrudan nesne tanımlamak object literal olarak geçer. Doğrudan oluşturulan  nesnelerden new anahtar sözcüğü ile tekrardan nesneler oluşturulamaz. Doğrudan bir nesne oluşturmak:

  var obj = {};

veya

  var obj = new Object();

şeklinde yapılabilmektedir.

Dizler için doğrudan nesne oluşturmak:

  var arr = [];

veya

  var arr = new Array();

şeklinde yapılır.

Herhangi bir sınıf tanımlamadan Map nesnesini doğrudan oluşturmak mümkündür.

var map = {
    this.name = name,
    this.version: "1.0.0",
    this.zoomLevel: 0,
    this.zoomin: function(){
        return this.zoomLevel + 1;
    }
}

Artık bu nesneyi doğrudan kullanmak mümkündür.

   map.version = 1.1.1;
   map.zoomin();

Bu tür tanımlamalar singleton olarak da geçer.

5-Fonksiyonlar Yardımıyla Singleton Nesne Tanımlamak

var map = new function(name){
    this.name = name;
    this.version = "1.0.0";
    this.zoomLevel = 0;
    this.zoomin = function(){
           return this.zoomLevel + 1;
    }
}

Burada tanımlanan constructor fonksiyonunun önünde new anahtar sözcüğü kullanıldığında doğrudan bir nesne oluşturulmuştur.

Böylece Javascript dilinde class ve doğrudan nesne kavramını ve bu türlerin nasıl tanımlandığını ve kullanıldığını incelemiş olduk. Bir sonraki makalede görüşmek üzere.

YUIcompressor kullanarak Webstorm üzerinde javascript minification

25 Oca

Bu yazımızda kullanıcı arayüzü geliştirme(frontend development) sürecinde uygulanan ve performans arttırma yöntemi olan dosya içeriklerinin azaltılması işlemi üzerinde duracağız. Bu işlem yabancı kaynaklarda minification olarak geçer. Javascript minification ya da css minification olarak karşılaşabiliriz.

Kodun okunabilirliğini arttırabilmek içi geliştiriciler olarak Javascript kodlarını düzgün biçimlendirerek ve anlamlı isimlendirmeler kullanarak yazarız. Değişken isimleri anlaşılır ve mümkün olduğunca uzun olur. Her satıra ayrı tanımlamalar yapılır. Kodda karmaşa oluşmaması için ne gerekiyorsa yapılır. Bu durumda dosyada boşluk karakterlerin sayısı ve değişken isimlendirmelerinden dolayı gereksiz karakter sayısı artar. Tabi gereksiz karakter kavramı kodu yorumlayan mekanizmaya göredir bize göre değil. Hal böyle iken dosya boyutu da doğal olarak büyür. Hele ki modüler yapıda bir uygulama geliştiriyorsak modüller arttıkça kodlar da artacaktır. Nihayetinde uygulamamızın yüklenmesi uzun sürecektir. Bu gibi durumlarda dosyadaki gereksiz boşluklar ve uzun isimlendirmelerin küçültülerek dosya boyutunun azaltılması gerekmektedir.

Örneğin aşağıdaki javascript kodu açık ve anlaşılır şekilde yazılmıştır.

var getProduct = function(productCode){

    var productList = GetProductFromService(productCode);

    return productList;

}

Bu kodun küçültülmüş hali şu şekilde olacaktır:

var getProduct=function(e){var t=GetProductFromService(e);return t}

Bu şekilde yüzlerce satırlık kodlar tek satır haline getirilir. Ağ üzerinden indirilen dosyaların boyutu küçüleceği için kullanıcı tarafına kolayca yüklenebilir.

Javascript dosyalarının küçültülmüş halleri gelenek olarak dosyaadi.min.js şeklinde adlandırılır. Yani dosya adında min ifadesini görünce dosyanın minimize edilmiş hali olduğunu anlayabiliriz.

Javascript dosya boyutlarının küçültülmesi işlemini manuel olarak yapmak çok zor bir işlemdir. Bu işlemin otomatik olarak yapılması gerekmektedir. Geliştirme yaptığımız IDE özelliklerinde minification özelliğinin olması bize avantaj sağlar. Ancak piyasada bu işlemi yapan araçlar da mevcuttur. Bu yazı da YUIcompressor aracı ile dosya küçültme işlemini gerçekleştirmeye çalışacağız. Geliştirme ortamı olarak ise Webstorm kullanılmıştır.

YUIcompressor yüklemek için nodejs komutunu kullanıyoruz. Yükleme komutu şu şekildedir:

npm install -g yuicompressor

Webstorm eklentilerinden File Watcher yüklü olması gerekmektedir. Bu eklenti javascript dosyalarımızın takibini yaparak otomatik olarak *.min dosyalarını oluşturacaktır.

File Watcher Plugin
File Watcher Plugin

Daha önce yüklediğimiz YUIcompressor aracını Webstorm tarafına tanıtmak işlemi aşağıdaki ekran çıktısında gösterilmiştir. Program kısmında

C:\Users\{user}\AppData\Roaming\npm\yuicompressor.cmd şeklinde dosya seçilmelidir.

File Watcher Plugin
YUI Compressor File Watcher

Bu işlemden sonra javascript dosyalarımız YUIcompressor tarafından takibe alınmıştır. Herhangi bir javascript dosyasında işlem yapıp kaydettiğimizde aşağıdaki gibi bir görüntü oluşacaktır.

min.js
min.js

Görüldüğü üzere otomatik olarak min dosyalarımın oluşturulmaktadır. Artık HTML dosyalarımızda kullanabiliriz.

AngularJS ile JSONP talebi göndermek

16 Tem

Angularjs ile Cross-Domain sorununu aşmak için JSONP yöntemini kullanabiliriz. En basit haliyle bir JSONP talebi şu şekilde gönderilebilir.

 $http.jsonp('http://www.filltext.com/?callback=JSON_CALLBACK&rows=5&fname={firstName}&lname={lastName}')
   .success(function (data) {
        console.log(data);
    }
 );

Diğer bir yöntem ise parametreleri ayırarak talebi göndermektir.

  $http({
        url: 'http://www.filltext.com',
        method: 'JSONP',
        params: {
                 callback: 'JSON_CALLBACK',
                 rows: 5,
                 fname: '{firstName}',
                 lname: '{lastName}'
        }
 }).
 success(function (data) {
      console.log(data);
 }).error(function (data) {
     console.log(data);
 })

Angularjs ile çalışırken callback fonksiyonlarının ismi JSON_CALLBACK şeklinde olmalıdır. Aksi taktirde hata ile karşılaşırız. Angularjs kendi içinde callback fonksiyonunun adını değiştirir. Sonuçta talep olarak bize aşağıdaki gibi bir cevap dönecektir.

    angular.callbacks._0({"key": "data"});

İşlem başarılı bir şekilde gerçekleşirse success fonksiyonu çalışacaktır. Hata oluşursa error fonksiyonu çalışacaktır.

Javascript ile sunucuya dosya yükleme sürecini kontrol etmek

21 Nis

Sunucuya doysa yükleme(File Upload) işlemi, küçük boyutlu dosyalar için kısa zamanda sonuçlanan bir işlemdir. Birkaç KB veya MB boyutundaki dosyaların sunucuya  yüklenmesi çok fazla zaman alamayacağından kullanıcı sabrını fazla zorlamaz. Ancak büyük boyutlu dosyaların yüklenmesi sırasında, yükleme işleminin kullanıcıya süreç olarak ifade edilmesi gerekmektedir. Aksi halde sunucudan uzun süre cevap alamayan kullanıcılar, internet tarayıcısının kilitlendiğini zannederek işlemi sonlandırabilir. Bu durumda yüklemi işlemi yarıda kesilir. Böyle durumların yaşanmaması için dosya yükleme sürecini bir şekilde kontrol altına alarak kullanıcıya işlemin hangi aşamada olduğunu grafiksel veya sözel bir şekilde bildirmemiz gerekmektedir. Tam da bu noktada imdadımıza javascript asenkron programlama yetişmektedir.

Javascript kullananların sıkça başvurduğu asenkron işlemler, dosya yükleme işleminde de etkili bir şekilde kullanıldığında geliştiriciye büyük kolaylık sağlamaktadır.

Dosya yükleme işlemini basit bir şekilde ifade edecek olursak bir form yardımıyla bilgisayarımızdan seçilen dosyaların (resim, müzik, video, veri, v.s) sunucuya aktarılmasıdır diyebiliriz. Bu kısa özetin ardından işlemin nasıl yapıldığına dair bir örnek uygulama göstermek faydalı olacaktır.

File Upload
File Upload

Örnek uygulama ile resimden anlaşıldığı üzere dosya yükleme süreci takip edilmektedir.

Kod tarafında Javascript ile yapılan işlem sadece XMLHttpRequest nesnesine ait olayların(events) yakalanmasıdır. XMLHttpRequest  nesnesi süreci asenkron olarak işletmektedir. Belli durumları olaylar yardımıyla bize bildirmektedir. Örneğin Yükleme sürecini progress event ile, işlemin bittiğini load event ile yakalayabilmekteyiz.

  this.ajax = new XMLHttpRequest();
  this.ajax.upload.addEventListener("progress", onProgressChanged, false);
  this.ajax.addEventListener("load", onFileUploadSuccess, false);
  this.ajax.addEventListener("error", onFileUploadFailed, false);

Bu şekilde event’leri sıralayabiliriz. Arayüz (HTML) tarafında belirlenen progress bar, button gibi elementlerin güncellenerek sürecin kullanıcıya yansıtılması bize kalmıştır. Bu noktada çeşitli yöntemlerle çalışmak mümkündür. Doğrudan javascript tarafından DOM elementlere ulaşıp içerik güncellemesi yapabildiğimiz gibi, JQuery gibi kütüphaneler kullanabiliriz. Ben bu uygulamada MVVM(Model View ViewModel) prensibini de etkin şekilde kullanabilmek açısından Knockoutjs kütüphanesini kullandım.

Sunucu tarafında uygulama Asp.net MVC4 ile oluşturulmuştur. Sunucu tarafında dosyaları diske yazma işini şimdilik kodlamadan bıraktım. Zaten yazının konusu değil.

Örnek uygulamayı GitHub hesabıma yükledim.  MVC4-knockoutjs-fileupload adresinden uygulamaya ulaşabilir, isterseniz katkıda bulunabilirsiniz.

ESRI Arcgis Javascript API with Knockout JS MVVM

4 Nis

Yazıya başlamadan önce, yazının başlığında belirtilen kavramları daha önce duymamış olanlar için kısaca açıklamaya çalışayım. Arcgis Javascript API, ESRI firmasının harita tabanlı javascript uygulamaları geliştirmek için sunduğu bir araçtır. Knockout JS ise javascript tarafında MVVM(Model-View-View Model ) tasarım deseninin uygulanabilmesini sağlayan bir kütüphanedir.

Knockout Js Model
Knockout Js Model

Kısaca söylemek gerekirse Javascript kodu ile HTML kodunun arasında aktarım yapabilen, iki taraf arasında köprü vazifesi gören bir kütüphanedir.

Bu yazının konusu, Arcgis Javascript API ve Knockout JS kütüphanesinin bir arada kullanıldığı bir harita uygulamasını göstermektir. GitHub hesabımda oluşturduğum esri-knockout-mvvm repository içerisinde uygulama kodlarını bulabilirsiniz.

Neden Arcgis JS API ile birlikte Knockout JS kullanma ihtiyacı duydum?

Arcgis Javascript API ile uyglamalar geliştirirken Javascript kodu içerisinde HTML elemanlarının kullanılması noktasına takıldım. Örneğin bir butona tıkladığımızda, butonun olay yakalayıcı metodunda bir HTML tablosunu oluşturur ve sayfanın bir yerine yerleştirir. Burada farklı konuların birbirinden ayrılması (Separation of Concerns) prensibini Javascript programlama dilinde ihlal etmiş oluyoruz. Oysa programlama prensipleri genel kavramlar olup uygulama alanına göre değişmez. Bu sebepten dolayı Knockout JS kullanarak HTML ve Javascript kodunu birbiriden ayırdım.

Uygulama Araç Kutusu:

  • Arcgis Javascript API
  • Knockout JS
  • Bootstrap
  • JQuery
  • Dojo

Uygulama Özeti:

Uygulama, harita üzerindeki bir noktaya tıklandığında, tıklanan yerin yakınlarındaki sosyal aktiviteleri, olayları göstermektedir. Bu bilgileri seatgeek.com API üzerinden çekmektedir.

Uygulamanın çalışan halini buradan inceleyebilrsiniz.

Uygulama Görseli
Uygulama Görseli

Javascript ve HTML Dom element etkileşimleri

8 Ara

Javacsript kodu ile HTML Dom elementler arasındaki etkileşimleri genelde elementin ID değeri üzerinden sağlarız. Javascript kodu ile document.getElementById(“elementId”) şeklinde ID aracılığıyla elementin seçilebilmesi mümkündür. Bu aşamadan sonra ise element üzerindeki bir değerin değiştirilmesi veya bir olayın(event) tetiklenmesi gibi işlemeri yapmak daha kolay hale gelmektedir.

HTML elementleri üzerinde tanımlı mevcut nitelikler(attributes), javascript tarafından elemente erişmemizi sağlarlar. Mevcut elementlerin kullanılabildiği gibi kendi tanımlayacağımız özel elementler üzerinden de bağlantı kurmamız mümkündür. Günümüzde kullanılan birçok Javascript kütüphanesi kendi tanımladığı nitelikler üzerinden işlemlerini yürütmektedir. Örneğin AngularJS ile çelışırken “ng-*” şeklinde veya JQuery ile çalışırken “data-*” şeklinde nitelikleri görürüz.

Şimdi bir senaryo geliştirerek biz de kendi tanımladığımız HTML nitelikler aracılığı ile bir uygulama geliştirmeye çalışalım. Bir buton elementi üzerine ekleyeceğimiz netelikleri(attribute) javascript tarafında kullanmaya çalışalım.

<button type="submit"
         data-get-async="true"
         data-url="/products.txt"
         data-attr-target="#getasyncresult">Getir
 </button>

Buton üzerinde data-get-async, data-url, data-attr-target şeklinde tanımladığımız nitelikleri anlamlandırmamız gerekmektedir.

data-get-async: işlemin asenkron gerçekleştirileceğini,
data-url: talebin gönderileceği adresi,
data-attr-target: talep sonrasında dönen cevabın hengi elementi etkileyeceğini belirtiyoruz.

Javascript dosyasını (deneme.js) ise şu şekilde düzenliyoruz:

<script type="text/javascript">

   $(function() {
       var buttonRequest = function () {
       var $button = $(this);
       var options = {
           url: $button.attr("data-url")
      };

      $.ajax(options).done(function(data) {
        console.log(data);
        var $target = $($button.attr("data-attr-target"));
        $target.html(data);
      });
  };

  $("button[data-get-async='true']").click(buttonRequest);
})
</script>

javascript tarafında gerçekleştirdiğimiz işlemi kısaca özetleyecek olursak, yaptığımız şey data-get-async niteliğini barındıran buton tıklandığında yapılacak işlemi belirlemektir.

$(“button[data-get-async=’true’]”).click(buttonRequest);

Bu örnekte “data-*” şeklinde nitelikler tanımlamamın sebebi yardımcı olarak JQuery kütüphanesini kullanıyor olmamdır.

JQuery ajax sorgusu için gerekli url gibi seçenekleri de yine buton üzerinde tanımlanan niteliklere tanımlıyoruz. Geriye kalan ise javascript işlemleridir.

Bu şekilde bir uygulama ile HTML tarafı ile Javascript kod tarafı birbirinden ayrılmış olmaktadır. Yani ön yüz(front end) geliştirme tarafında, Model ve View şeklinde bir ayrım yapılmış olmaktadır. Javascript MVC geliştirme araçlarının yaptığı işlem de bu şekildedir aslında. Direktifleri HTML nitelikeri(attributes) aracılığı ile alır ve komutları çalıştırırlar.

Bir sonraki yazıda görüşmek dileğiyle.

Yaygın Olarak Kullanılan Javascript MVC Çatıları

25 Eki

Yazılım dünyasında en popüler tasarım şablonlarından olan MVC(Model View Controller) tasarım şablonu, geleneksel programlama dillerinin yanında Javascript tarafında da yaygın olarak kullanılmaya başlamıştır. MVC bir uygulamada yapılması gereken işlerin üç sınıfta birbirinden ayrılmasıdır.

Model: Modellenen verinin tipi olarak düşünülebilir. Örneğin; ürün, kullanıcı, sipariş, v.s

View: Uygulamanın ön yüzü oalrak düşünülebilir. Örneğin; temalar, css, resimler.

Controller: Uygulamadaki eylemleri karşılar. Örneğin; Tıklamalar, istekler, cevaplar.

Javascript dili, kullanıcı(client) taraflı bir dil olduğundan ve internet tarayıcısı(browser) tarafından yorumlandığından bir ön yüz geliştirme aracıdır. MVC tasarım şablonunun ön yüzde yani View tarafında uygulanması biraz ilginç gelebilir. Fakat her ne kadar View tarafında olsak da ortada bir programlama aracı vardır ve bu programlama aracı ile yani javascript ile ön yüzde MVC şablonunu uygulamak mümkündür. Model ve Controller olarak javascript nesnelerini, View olarak ise HTML elemntlerini düşünebiliriz. Bu sayede MVC şablonunu ön yüz geliştirme ortamına uygulayabiliriz.

Neden MVC çatıları kullanılır?

Javascript MVC çatısı altında DOM etkileşimleri yanı sıra Sunucu ve Kullanıcı arası iletişimleri sağlamak mümkündür. Bu iletişim sırasında alınan ve gönderilen veriler üzerinde bazı mantıksal işlemleri uygulamak gerekebilir. MVC çatılarını kullanarak bu mantıksal işlemleri View tarafından ayırabiliriz.

Bir uygulama çatısı geliştirmek çok külfetli ve maliyetli olduğundan sıfırdan kütüphaneler yazmak yerine güven kazanmış açık kaynak kütüphaneleri kullanabiliriz.

Seçerken Dikkat

Bir MVC çatısını seçerken dikkat edilmesi gereken bazı hususlar vardır. Bunlar:

  • İhtiyacımızı gerçekten karşılayacak yapıda olması.
  • Destek alabilecek bir topluluğun olması.
  • Dökümantasyonunun iyi yapılmış olması.
  • Küçük uygulamalarla kullanım kolaylığının test edilmiş olması.

Javascript MVC Çatıları

MVC tasarım şablonunun javascript tarafında rahatça kullanılabilmesi için birçok çatı(framework) geliştirilmiştir.

Benim tecrübe ettiğim javascript MVC araçları Knockout, AngularJS, giriş seviyesinde de Backbone olmuştur. Fakat yaygın olarak kullanılarn Javascript MVC araçlarını şu şekilde listeleyebiliriz:

  • AngularJS
  • BackboneJS
  • KnockoutJS
  • EmberJS
  • AgilityJS
  • CanJS


Bir sonraki yazıda görüşmek dileğiyle.