spacer ASCIIcasts

Tags

205: Unobtrusive JavaScript 

(view original Railscast)

Other translations: spacer spacer spacer spacer spacer

Written by Ümit Kayacık

Rails 3 özelliklerini incelediğimiz serinin bu bölümünde unobstrusive Javascript'in kullanımını inceleyeceğiz. Unobtrusive Javascript ile web uygulamasında javascript kod ile içeriği birbirinden CSS de olduğu gibi ayrılır. Unobtrusive Javascript'i Rails'de kullanmaya başlamadan önce basit bir HTML döküman içinde kullanalım.

Aşağıdaki ekran görüntüsü üzerinde bir link olan bir web sayfasını gösteriyor. Link tıklandığında Javascript alarm popup açılır ve "Hello world!" mesajı verir.

spacer

Bu sayfanın HTML kodu şuna benzer:

<!DOCTYPE html>
<html>
  <head>
      <title>UJS Example</title>
  </head>
  <body>
      <h1><a class="#">

Sayfada bir linkimiz var ve onclick özelliğine de bir Javascript kod yazılmış. Script HTML içinde birleşik olduğundan unobtrusive değildir ve iyi bir şey değildir, çünkü içerik ve kod birbirine karışıyor. 1990'ların sayfalarında CSS olmadığı için <font> tag'i ile yazı görünümü değiştirilirdi, sayfada yüzlerce bunlardan olurdu. Tarayıcılar CSS kullanmaya başlayınca stil bilgileri stylesheet dosyalarında toplanmaya başladı ve hem değişiklik yapılması kolaylaştı hem daha anlaşılır oldu.

Aynısı Javascript'e de uygulanabilir. Küçük küçük Javascript kod parçaları HTML tagların özellikleri içinde yazılırsa değişiklik yapmak zorlaşır. Javascript'i ayrı bir dosyaya koyunca tekrarlayan kodlar azalır, düzenlemeler kolaylaşır ve karmaşık uygulamaları üretmek ve debug kolaylaşır.

Örneğimizi nasıl unobtrusive yapacağız? Ana adım, onclick özelliğindeki Javascript'i ayrı bir dosyaya taşımak ve bunun için bir Javascript framework kullanacağız. Burada JQuery ile elemanların olaylarını algılayacağız. Önce sayfanın değişmişini bir görelim sonra açıklayalım.

<!DOCTYPE html>
<html>
  <head>
    <title>UJS Example</title>
    <script src="/img/spacer.gif"> 

İlk Dikkat çeken nokta Javascript'i daha önce söylediğimiz gibi ayrı bir dosyaya çıkarmadık. Bunu sadece burda gösterim için yaptık.

Body içindeki elemanın onclick özelliğini kaldırıp ona bir id verdik. Bu sayede hedefe JQuery üzerinden bir bağlantı yapabiliriz. Daha sonra head bölümünde JQuery kütüphanesini yüklüyoruz ve bunun altında dış dosyaya koyacağımız script görünüyor. Script JQuery'nin $ fonksiyonunu bir fonksiyon argümanı ile çağırıyor. Argümandaki bu fonksiyon sayfa DOM yüklemesinde çağrılır. Bu fonksiyon JQuery ile elemanı id'sinden bulur ve click olayına bir fonksiyon bağlar. Bağlanan fonksiyon ise bir alert ile mesaj verir ve geriye false dönerek link bağlantısına gidilmesini engeller.

Eğer sayfayı şimdi tazelersek aynen bir öncekinin yaptığını yapacaktır. Tıklanınca bir alarm verecektir.

Burda çok iş yapmamıza rağmen karşılığında pek bir şey elde etmedik. Burada Unobtrusive Javascript avantajlarını pek göremedik tek satır Javascript yerine 6 satır oldu. Bu örnek sadece Unobtrusive Javascript'in mantığını anlatmak için yapıldı. Unobtrusive Javascript'in avantajı sayfadaki Javascript sayısı arttıkça ortaya çıkmaya başlar. Tüm Javascript kodlarını ayrı bir dosyada tutmak sayesinde tekrarlamaların önüne geçilmeye başlanır.

Bu yaklaşımın bir sorunu var. JavaScript genellikle statik bir dosyaya yazılıyor. Bu durumda satır içine yazmadığımıza göre nasıl server tarafı dinamik JavaScript ekleyebileceğiz?

HTML 5 ile birlikte artık ısmarlama verileri ilgili eleman tag içine özellik olarak koyabiliyoruz. Bunlar aynı diğer özellikler gibi yazılıyor, tek farkları data- ile başlamaları. Mesela tıklanınca verilecek mesajı özellikte saklamak için şöyle yazın:

<a class="#" id="alert" data-message="Hello from UJS">Click Here</a>

JavaScript'de alert satırını mesajı bu yeni özellikten alacak şekilde değiştirelim:

$(function () {
  $('#alert').click(function () {
    alert(this.getAttribute('data-message'));
    return false;
   })
});

Eğer sayfayı tazelersek linki tıklayınca özeliikten gelen mesajı alabiliriz.

spacer

Rails 3 Data Özelliklerini Nasıl Kullanır

Rails 3 bu ısmarlama data özellikler ile veriyi JavaScript'e gönderir. Şimdi bunun bir Rails 3 uygulamasında nasıl olacağını inceleyelim. Uygulamamız içinde arama yapılabilecek ürünlerin listesi bulunan basit bir e-alışveriş uygulaması. Ayrıca ürünü düzenlemek ve silmek için de linkler var , ama silmek için olan çalışmıyor gibi.

spacer

Bu Rails 3 uygulamalarında sık karşılaşılan bir sorundur. Eğer eski bir versiyon uygulamayı upgrade ediyorsanız, JavaScript'lerin çalışmaması çok karşılaşılan bir durumdur.

Görsel dosyasındaki kod "Destroy" linkini standart link_to metodunu kullanarak üretir. :confirm opsiyonu ile bir JavaScript confirm alarmı üretilir ve :method opsiyonu da :delete olarak ayarlanmıştır. Böylece link tıklanınca GET yerine DELETE metoduna çağrı yapılacaktır.

/app/views/products/show.html.erb

<%= link_to "Destroy", @product, :confirm => "Are you sure?", :method => :delete %>

Burada enteresan olan bu kodun ürettiği HTML kod:

<a class="/products/8" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a>

Rails 2'de destroy link oluşturmak için link_to kullanınca bir sürü JavaScript ile confirm diyaloğu oluşturuluyor ve bir form ile DELETE ya da PUT çağrısı yapılıyordu. Rails 3 koduna bakarsanız daha temiz ve daha önce gördüğümüz HTML 5 data özelliklerini kullanıyor. Onay mesajını içeren bir data-confirm ve metodu saklayan bir data-method özelliği.

Linkin çalışmama sebebi head bölümünde JavaScript fonksiyon tanımlanmadığı için , standart bir GET çağrısı yapılacak ve silme işlemi DELETE çağrılmadığı için gerçekleşmeyecektir.

Bunu düzeltmek için uygulamanın layout dosyasına aşağıdaki iki satırı eklemeliyiz:

/app/views/layouts/application.html.erb

<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>

Yukardaki ilk satır tanıdık gelecektir. Bir Rails uygulaması için standart JavaScript dosyaları yüklüyor. İkinci satır DELETE işlemlerini gerçekleştirmek için gerekli yetkilendirme bilgilerini taşıyan iki metatag üretir. Değişim sonrası sayfayı tazelersek üretilen iki satırı göreceğiz.

<script src="/img/spacer.gif"> 

Şimdi sayfada tüm JavaScript dosyalara erişim ve cross-site saldırılara karşı tüm önlemler mevcuttur. Böylece PUT ve DELETE çağrılarının bir hacker tarafından değil doğru kişiden geldiğinden emin olabiliriz.

Bu iki satırla beraber bizim destroy linkimiz beklendiği gibi çalışacaktır.

spacer

Bir Arama Formuna AJAX Eklemek

Sonra index sayfasındaki arama formunu değiştirerek GET çağrısı yerine AJAX kullanmasını sağlıyacağız. Index görselindeki form için kod aşağıda gösteriliyor:

/app/views/products/index.html.erb

<% title "Products" %>

<% form_tag products_path, :method => :get do %>
  <p>    
  <%= text_field_tag :search, params[:search] %>
  <%= submit_tag "Search", :name => nil %>
  </p>
<% end %>

<div id="products">
  <%= render @products %>
</div>

<p><%= link_to "New Product", new_product_path %></p>

Burada kullanılan form episode 37. de gösterilen teknikle arama yapmak içindir. Rails'in önceki versiyonlarında formun AJAX ile çalışması için form_tag ile form_remote_tag değiştirilirdi. Bu metod şimdi sakınmaya çalıştığımız satır içi JavaScript'ten bir sürü üretecektir.

Rails 3 ile beraber birçok remote helper metod artık kullanılamaz oldu. Eğer kullanmak istersek Prototype Legacy Helper plugin install etmeliyiz.

Bunu form_remote_tag ile yapmak yerine yine form_tag, kullanıyoruz ama yeni bir parametre ile :remote.

/app/views/products/index.html.erb

<% form_tag products_path, :method => :get, :remote => true do %>
  <p>
    <%= text_field_tag :search, params[:search] %>
    <%= submit_tag "Search", :name => nil %>
  </p>
<% end %>

Bu :remote parametresi ayrıca link_to, button_to ve form_for gibi diğer helper metodlarla da kullanılabilir. Eğer sayfayı tazeleyip kaynağı incelersek yeni form kodumuzun nasıl çalıştığını görürüz.

<form action="/products" data-remote="true" method="get">  <p>
    <input id="search" name="search" type="text" />
    <input type="submit" value="Search" />
  </p>
</form>

Form elemanı aynı ama bu sefer yeni bir data-remote özelliği var. Satır içi JavaScript yok, yeni özellik  rails.js içindeki JavaScript'e formun AJAX yoluyla gönderildiğini anlatmaya yeter.

Sırada AJAX çağrısını işleyecek kodu yazmak var. Ürünlerin listesi bir  div içersinde bulunuyor. Bu  div  içeriğini update ederek sadece aranan ürünleri gösterebiliriz. Form  ProductController’in index eylemine gönderiliyor ve tüm ihtiyacımız olan JavaScript isteklerini işleyecek bir  index.js.erb dosyası eklemek.

Bu kalıp dosyaya tarayıcıya dönüldüğünde çalışmasını beklediğimiz herhangi bir JavaScript kodu yazabiliriz. Yeni kalıp dosyamızdaki kod div içeriğini sonuca göre update edecek.

/app/views/products/index.js.erb

$("products").update("<%= escape_javascript(render(@products))%>");

Sayfayı tazelediğimizde ve formun gönderme düğmesine tıkladığımızda arama AJAX çağrısı ile yapılacak ve URL değişmeyecektir.

spacer

İşte böyle, Rails 3 ile unobtrusive JavaScript sadece :remote parametresi kullanarak yapılıyor. AJAX çağrısına bir server bir JavaScript ile dönüş yapıyor ve o da div içeriğini değiştiriyor.

Frameworkları Değiştirmek

Bu bölümü uygulamamızın kullandığı JavaScript Framework'u nasıl değiştirceğimizi göstererek kapatacağız. Uygulamamız şu anda Prototype kullanıyor, bu Rails'in parçası olarak geliyor , fakat JQuery kullanmak istiyorsak ne olacak?

İlkönce uygulama layout'da yer alan şu satırı değiştirmeliyiz.

/app/views/layouts/application.html.erb

<%= javascript_include_tag :defaults %>

şöyle değiştirin:

/app/views/layouts/application.html.erb

<%= javascript_include_tag "ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", "jquery.rails.js" %>

Listedeki ilk dosya Google üzerinden JQuery'nin son versiyonu. Bu tek başına yeterli değil rails.js dosyasının JQuery eşleniğini de yüklememiz gerekiyor, yoksa unobtrusive uygulamalarımız çalışmaz. Bu dosyanın orjinalini  jquery-ujs project on Github adresinde bulabilirsiniz. Bu projede indirip projemizde kullanabileceğimiz bir rails.js dosyası vardır. Bu dosyayı indirip uygulamamızın  /public/javascripts klasörüne koyalım ve adını jquery.rails.js yapalım ve bu dosya uygulamamızın Rails tarafından kullanılan unobtrusive JavaScript işlerini gerçekleştirir.

Şimdi daha önce uygulamamıza bizim eklediğimiz Prototype'a göre olan JavaScript'imizi JQuery'ye uygun olacak şekilde değitirmek zorundayız. Daha önce ürettiğimiz index.js.erb dosyasında küçük bir değişiklik yapacağız. Div seçicisi olarak products yerine #products kullanarak ve Prototype'ın update metodu yerine JQuery eşleniği olan html kullanarak.

/app/views/products/index.js.erb

$("#products").html("<%= escape_javascript(render(@products))%>");

Uygulamamız artık kaputun altında Prototype yerine JQuery kullanıyor.

Estetiğin Kaybolması

Eğer bir kullanıcı JavaScript izin verilmeyen bir tarayıcı kullanarak uygulamamızı açarsa biraz estetik kaybı olacaktır. Buton normal bir GET çağrısı yapacaktır. Ürün silme linki de çalışmayacaktır. Bu genel bir problemdir, HTML linkleri sadece GET çağrıları yapabilir, bu yüzden Rails DELETE için biraz JavaScript kullanır. Bunun önüne geçmek için bir yöntem button_to kullanmaktır ama çirkin görünecektir, bu yüzden link olarak kalmalı. Tercih edilebilecek bir teknik olarak episode 77   de JavaScript izin verilmeyen tarayıcılarda silme işlemi için başka sayfa açan örnek var.

Previous episode Next episode
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.