DOM API USAGE SERIES

Template Rendering -1 (Mustache.JS)

JS ve JQuery ile DOM içerisine yeni sub HTML yapıları oluşturmak oldukça zor bir işlem bunun yerine bazı hazır kütüphaneler sizin bu işlemleri hem daha basit hem de daha hızlı yapmanızı sağlıyor. Bu yazıda Template Rendering konusunda bahsedeceğim.

--

1. Giriş

Bu yazıyı daha önceden yazmış olduğum DOM API Kullanım Yöntemleri yazı serisinin bir parçası olarak yazıyorum. Bir çok kavramı tek bir yazıda ele almanın yaratacağı karmaşıklıktan kaçmak için bu şekilde bir yönteme başvurdum.

Önceki yazımda JS ve JQuery DOM string oluşturabilmek için el ile string işlemleri yaptığımız anlattım. Daha önceden ES6 öncesinde string işlemek için Template Literals yapısı mevcut değildi. Bundan dolayı string concat işlemleri ile bu ve daha karmaşık html oluşturma işlemi oldukça zor bir işlemdir.

let DOMAsStr='';
for(let i=0;i<counter;i++){
DOMAsStr+=`<div>Selam</div>`
}

2. Template Rendering

Elimizde bir Model olsun bunun ile View oluşturmak isteyelim bunun için önce elimizde Model verimiz olsun bu model verimizden aşağıdaki sonucu oluşturmak isteyelim.

Model

userArr=[{name:'Onur', age:'39'}, {name:'Ugur', age:'36'}]

Sonuç (View)

<div id='userList'>
<div>
<span class='user-name'>Onur</span>
<span class='user-age'>39</span>
</div>
<div>
<span class='user-name'>Ugur</span>
<span class='user-age'>36</span>
</div>
</div>

İşte bizim Model’den → View dönüştürecek bir mekanizmaya ihtiyacımız var. Bu dönüşümü yapan mekanizmaya Template Engine ve yaptığımız bu dönüştürme işlemine Template Rendering diyoruz.

//fx=> Template Rendering
fx(Model, Template)
= View

Peki bu durumda Template nasıl bir şey olmalı ?

Template
{{#userArr}}

<div>
<span class='user-name'>{{name}}</span>
<span class='user-age'>{{age}}</span>
</div>
{{/userArr}}

Farklı farklı Template Kütüphaneleri mevcut. Bunların bazıları basit, bazıları kompleks, ihtiyaç ve kullanım alanlarına göre farklılıklar içeriyor. Mustache.JS, Handlebar.JS, Underscore.JS, EJS bunların en çok kullanılanları. Öncelikli olarak bu yazımda Mustache.JS ve özelliklerinden bahsedeceğim.

3. Mustache.JS ile Template Rendering

En basit template rendering yöntemidir. Modeli + Template birleştirerek view oluşturulur.

3.1 Array Render Etme

<html><head>
<script src="...jquery.js"></script>
<script src="...mustache.js"></script>
//Template Script
<script id="user-script" type="template/text">
{{#userArr}}
<div>
<span class='user-name'>{{name}}</span>
<span class='user-age'>{{age}}</span>
</div>
{{/userArr}}
</script>
<script>
$(function () {
const appModel={};
appModel.userArr=[
{name:'Onur', age:'39'},
{name:'Ugur', age:'36'}];

const theTemplate = $("#user-script").html();
var theHtml = Mustache.to_html(theTemplate, appModel);
$("#userContainer").html(theHtml);
});
</script>
</head>
<body>
<div>
<div id='userContainer'>
</div>
</div>
</body>
</html>

3.2 Boş Array ve False Değerli Model

false/[] için template rendering çalışmaz. Ama bu kısımda inverted sections (^) kullanarak bu kısım içerisinde bir takım html oluşturabilirsiniz.

{{^userArr}}No users:({{/userArr}}

3.3 Nested Array Render

Bizim kullandığımız yapılar iç içe yapılar oluşturabiliriz. Örneğin kullanıcının altında çocukların listesinide eklemek istersek.

Model

[ { name: 'Onur', age: '39', 
children: [{ name: 'Ozgur' }, { name: 'Deniz' }]},
{ name: 'Ugur', age: '36',
children: [{ name: 'Ela' }, { name: 'Kaan' }, { name: 'Lena' }] }];

Template

{{#userArr}}
<div class='user'>
<span class='user-name'>{{name}}</span>
<span class='user-age'>{{age}}</span>
{{#children}}
<div class='children'>
<span class='children-name'>{{name}}</span>
</div>
{{/children}}
</div>
{{/userArr}}

3.4 Nested Object Rendering

Bizim kullandığımız array içerisindeki nesnelerinde içerisinde başka nesne referansları ve onların içerisinde de nesneler bulunsun.

Modelimizi biraz daha geliştirip kullanıcılar altında childInfo

[ { name: 'Onur', age: '39', childInfo:{ 
count:2,
children: [{ name: 'Ozgur' }, { name: 'Deniz' }]},
{ name: 'Ugur', age: '36', chidInfo:{
count:3
children: [{ name: 'Ela' }, { name: 'Kaan' }, { name: 'Lena' }] }];

Template nested objeleri destekleyecek şekilde geliştiriyoruz. Bunun için childInfo.children gibi referanslar kullanabilirsiniz.

{{#userArr}}
<div class='user'>
<span class='user-name'>{{name}}</span>
<span class='user-age'>{{age}}</span>
<span class='user-child-count'>{{childInfo.count}}</span>
{{#childInfo.children}}
<div class='children'>
<span class='children-name'>{{name}}</span>
</div>
{{/childInfo.children}}
</div>
{{/userArr}}

Nested yapılarda delegation olayı bazen template çok karışmasına neden olur. Örneğin;

#childInfo.children
#childInfo.children.objX
#childInfo.children.objX.objY

İşte bu karmaşayı önlemek için mustache.js bize bir kullanım kolaylığı sunuyor içerde o nesneyi template eklediğiniz zaman nokta işareti ile delegation işlemi yapmadan bu nesnenin özelliklerini kullanabilirsiniz.

{{#userArr}}
<div class='user'>
<span class='user-name'>{{name}}</span>
<span class='user-age'>{{age}}</span>
{{#childInfo}}
<span class='user-child-count'>{{count}}</span>
{{#children}}
<div class='children'>
<span class='children-name'>{{name}}</span>
</div>
{{/children}}
{{/childInfo}}
</div>
{{/userArr}}

3.5 Fonksiyonların Kullanımı

Yukarıdaki örnekte bir problemde çocuk sayılarını statik olarak yazdık.

count:2,
children: [{ name: 'Ozgur' }, { name: 'Deniz' }]

aslında burda bir fonksiyonumuz olsa ve array length hesaplasa. İşte aşağıdaki gibi objeler içerisinde toplam para, vergi hesabı, vb hesaplamaların yapıldığı fonksiyonlarıda Mustache.JS destekliyor. Tek yapmamız gereken count karşısına aşağıdaki fonksiyonu yazmamız.

count:function(){return this.children.length}

3.6 Duruma(If Koşulu) Göre Rendering Yap

Şimdi bize dönen nesnede bir kullanıcının hiç çocuğu olmasın ama bunun childInfo nesnesi aşağıdaki şekilde dönüş yapsın. Biz bu kullanıcıya ait bu view oluşmasını istemiyoruz.

count:0,
children: [],

Bunun için Mustache.JS koşullarını kullanabiliriz.childCondition değerinde bir üst condition yapısı oluşturduk ve model verimizde de buna karşılık gelen fonksiyonu yazmamız yeterli olacak.

{{#userArr}}
<div class='user'>
<span class='user-name'>{{name}}</span>
<span class='user-age'>{{age}}</span>
{{#childCondition}}
{{#childInfo}}
<span class='user-child-count'>{{count}}</span>
{{#children}}
<div class='children'>
<span class='children-name'>{{name}}</span>
</div>
{{/children}}
{{/childInfo}}
{{/childCondition}}
</div>
{{/userArr}}

childContion için fonksiyon. Bundan sonra çocuk bilgisi kısmında children array boş gelenler için bu kısmın template çizmeyecek.

childCondition:function(){return this.childInfo.children.length>0}

3.7 Template Parçalara Bölerek Kullanmak

Bazen tek bir template yönetmesi oldukça zorlaşabilir bu yüzden template parçalara bölerek kullanabilirsiniz. Biz örneğimizde sadece çocuğun ismini yazmışız ama daha fazla özelliği olsaydı template iyice karmaşıklaşacaktı. Bunun için bu child bilgilerini render eden parçayı ayrı bir template olarak rendering eklemek istersek bu kısmı ayrı bir parça olarak oluşturup

const childTemplate = {child: "<span class='children-name'>{{name}}</span>"};

daha sonrasında da template {{>child}} kısmi parça olarak ekleyebiliriz.

{{#userArr}}
<div class='user'>
<span class='user-name'>{{name}}</span>
<span class='user-age'>{{age}}</span>
{{#childCondition}}
{{#childInfo}}
<span class='user-child-count'>{{count}}</span>
{{#children}}
<div class='children'>
{{>child}}
</div>
{{/children}}
{{/childInfo}}
{{/childCondition}}
</div>
{{/userArr}}

Yukarıdaki örnekleri kaynak kodunu aşağıdaki linkte toplamaya çalıştım.

DOM API Usage ile ilgili örnek Kodlar

4. Yorum

Mustache.JS güzelliği sizi view için kod işlemlerinden soyutluyor olması olabildiğince basit bir şekilde verinizin template geçirilerek view oluşması sağlanır ve ortadaki bir çok kod tekrarı ve kirliliğinden kurtularak bu işlemin soyutlanması sağlanmış olur.

Okumaya Devam Et 😃

Bu yazının devamı veya yazı grubundaki diğer yazılara erişmek için bu linke tıklayabilirsiniz.

--

--