Repeatable, еще один способ рендерить списки

от автора

(из серии «малая механизация web страниц»)

Что такое Repeatable?

Repeatable это способ вывода (популяции) всякого рода списков, таблиц и пр. по массивам данных. Данный механизм
использует шаблон описанный в самом коде разметки (в отличие от, скажем, {{mustache}} templates).

Поддерживаются выражения и условное включение. И всё это в 90 строках кода.

Repeatable функиональность есть в каждом «взрослом» web framework’е. Но если вы не хотите по тем или иным причинам завязываться с монстрами то вот вам механизм который, что называется, есть не просит.

Пример

Скажем есть такие данные:

var data = [        { name: "Olga", age: 20, email: "aaa@example.com" },        { name: "Peter", age: 30, email: "bbb@example.com" },        { name: "Ivan", age: 15, email: "ccc@example.com" },     ]; 

И нам нужно из вывести как-то так:

<ul id="people">     <li><a href="mailto:{{this.email}}">{{this.name}}</a> <b if="this.age > 18">18+</b> </li>      <li>No data available</li> </ul> 

Первый <li> собственно и есть шаблон записи. Для каждой записи во входном наборе этот элемент будет повторен с подстановками и гуляшшыми девами. Второй <li> будет выведен если Repetable «накормить» пустым массивом.

Если у нас это все описано то собсвенно популяция нашего списка это одна строка:

var list = $("ul#people").repeatable(); // declaring the repeatable     list.value = data; // that's data population, sic! 

Вот живой пример.

Микроформат шаблонов

Текст внутри разметки или значение аттрибута может содержать выражение в «mustache» скобках: {{ ...expr ...}}.
При заполнении списка такие выражения будут вычислены и замещены их строковым значениями.

Специпльные переменные доступные в выражениях
  • this — объект — текущий элемент списка.
  • $index — число, индекс текущего элемента списка;
  • $firsttrue если это первый элемент;
  • $lasttrue если это последний элемент;
  • $length — число, кол-во записей во входном массиве.
Условное включение

Любой элемент внутри repeatable шаблона может быть объявлен как условный. Для этого нужно описать у него атрибут if="...expr...". При генерации списка выражение будет вычислено и если оно «truthy» то элемент будет выведен, если нет — удален.

Домашняя страница repeatable plugin — здесь
Исходник repeatable привожу здесь полностью для тех кто пропустил ссылку в начале:

/** * @author Andrew Fedoniouk <andrew@terrainformatica.com> * @name jQuery repeatable() * @license WTFPL (http://sam.zoy.org/wtfpl/) * @purpose template-less population of repeatables (lists) */  (function ($) {    function repeatable(el) {              var $el = $(el);     var template = $el.find(">*").remove();     var nrTemplate = template.length > 1 ? $(template[1]) : null; // "no records" template         template = $(template[0]);          var compiled = {}; // compiled expressions     var vector = null; // data     var index = 0;     // current index being processed      //function evalExpr(str) { return eval("(" + str + ")"); }     function compiledExpr(str) {        var expr = compiled[str];        if( !expr )         compiled[str] = expr = new Function("$index","$first","$last","$total", "return (" + str + ")");        return expr;     }      function replace(text, data) {       function subst(a, b) {          var expr = compiledExpr(b);         var s = expr.call(data, index, index==0,index==vector.length - 1, vector.length); return s === undefined ? "" : s;        }       return text.replace(/{{(.*)}}/g, subst);     }      function instantiate(el, data) {       var attributes = el.attributes;       for (var i = 0; i < attributes.length; ++i) {         var attribute = attributes[i];         if (attribute.name == "if") {           var str = attribute.value;           var expr = compiledExpr(str);           var tokeep = expr.call(data, index, index == 0, index == vector.length - 1, vector.length);           if (!tokeep) { el.parentElement.removeChild(el); return; }         }         else if (attribute.value.indexOf("{{") >= 0)           attribute.value = replace(attribute.value, data);       }       for (var nn, n = el.firstChild; n; n = nn) {         var nn = n.nextSibling;         if (n.nodeType == 1)  // element           instantiate(n, data);         else if (n.nodeType == 3) // text         {           var t = n.textContent;           if (t.indexOf("{{") >= 0)             n.textContent = replace(t, data);         }       }     }      function getValue() { return vector; }      function setValue(newValue) {       vector = newValue;       var t = template[0];       if( !vector || vector.length == 0 ) {         $el.empty();         if(nrTemplate)           $el.append(nrTemplate); // no records       }       else {         var fragment = document.createDocumentFragment();         for (index = 0; index < vector.length; ++index) {           var nel = t.cloneNode(true);           instantiate(nel, vector[index]);           fragment.appendChild(nel);         }         $el.empty();         $el.append(fragment);       }     }      el.getValue = getValue; el.setValue = setValue;         // redefine its 'value' property, setting value to some array will cause popupaltion of the repeatable by that data.     try { Object.defineProperty(el, "value", { get: getValue, set: setValue, enumerable: true, configurable: true }); } catch(e) {}      return el;   }    $.fn.repeatable = function () {     var el = null;     this.each(function () { el = repeatable(this); });     return el; // returns last matched element!   };  })(jQuery);  

Успехов.

ссылка на оригинал статьи http://habrahabr.ru/post/211590/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *