(из серии «малая механизация 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
— число, индекс текущего элемента списка;$first
—true
если это первый элемент;$last
—true
если это последний элемент;$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);
Успехов.
Автор: csmile