Главная > JavaScript, Программирование > JavaScript шаблонизатор

JavaScript шаблонизатор

16 Январь 2010

Конечно шаблонизатор это очень громко сказано, но все же это попытка разнести данные и представление по разным углам. Но пока я не нашел этому реального применения, я не хотел постить это в блог и это было в моей голове и на форуме, а теперь я собираюсь использовать это в проекте и созрел запостить тут, может кто-то что-то умное скажет.

Сам вопрос довольно прост, надо сделать сопряженные выпадающие списки, то есть выбрал что-то в одном, поменялись варианты ответов в другом, естественно ajax'ом. Как правильно собрать содержимое select'a в кучу если проходит JSON?!

Итак представим наш код


$.ajax({
    url : "my/back/end.json",
    type : "json",
    success : function (result) {/**/}
});

Вот, собственно, и надо реализовать функцию success. Учитывая что формат ответа:


[
{value:1,name:"CTAPbIu_MABP"},
{value:2,name:"Vasya Pupkin"},
{value:3,name:"%UserName%"}
]

Подавляющее большинство делает что-то вроде


function(result)
    var array = [];
    $(result).each(function(i, val) {
        /*
         * Предполагаю что хватает ума не писать ересь типа
         * $('select#id').append('<option value="' + val.value + '">' + val.name + '</option>');
         */
        array.push('<option value="' + val.value + '">' + val.name + '</option>');
    });
    $('select#id').html(array.join(""));
}

Но если бы меня устраивало я бы не писал эту статью. Из этого надо выделить данные, они у меня в переменной result, и шаблон из <option ...>. Выделил, теперь переписываю.


var template = '<option value="[value]">[name]</option>';
...
function (result) {
    var array = [];
    $(result).each(function(i, val){
        array.push(template.replace(/(\[([^\[\]]+)\])/g, function($0, $1, $2){
           return val[$2] || "";
        }));
    });
    $('select#id').html(array.join(""));
}

Что тут происходит? есть шаблон, который скорее всего будет браться откуда-то из вне. В шаблоне есть плейсхолдеры [key], имя плейсхолдера это свойство в получаемом объекте. регулярным выражением я заменяю плейсхолдеры на полученные данные, если в данных присутствует плейсхолдер, он так и останется плейсхолдером, потому что строка повторно не обрабатывается, если значения свойства не определено подставляется пустая строка.

Осталось придумать как натянуть все это целую форму...

Updated 29.06.10 Это все приобрело финальную форму и успешно используеться уже во втором проекте:


function T (data, template) {
	var array = [];
	$(data).each(function(key, val){
		array.push(template.replace(/(\[([^\[\]]+)\])/g, function($0, $1, $2){
		   return $2 in val ? val[$2] : "";
		}));
	});
	return array.join("");
}
  1. B@rmaley.e>
    16 Январь 2010 в 21:33 | #1
    
    $('select#id')
    
    Зачем тут select? Для замедления выборки?
  2. 16 Январь 2010 в 22:07 | #2
    не, это чтоб было понятно, что я не в div вставляю, хотя да наверное это излишне ;)
  3. B@rmaley.e>
    16 Январь 2010 в 23:11 | #3
    Ну тогда можно было бы в переменную select записать. Или комментарием.
  4. 16 Январь 2010 в 23:20 | #4
    да ладно, статья не о скорости
  5. 17 Январь 2010 в 12:57 | #5
    Если я правильно въехал, схема такая: 1) юзер запрос и инициализация Аякса. 2) Аякс бекенд получает данные и шаблон отображения из внешнего файла. 3) Посылка данных на фронтенд: сугубо данных и шаблона отображения. 3) Яваскрипт-фронтенд Аякса сшивает данные и шаблон и плюет в браузер? Верно? или я что-то не так понял :-). Если все так, то зачем сшивать данные в яваскрипте, если можно все склеить (данные+шаблон отображения) еще в бекэнде и выплюнуть фронтенд-яваскрипту готовую строку для отображения?
  6. 17 Январь 2010 в 14:11 | #6
    второй пункт - неправильный шаблон зашит во фронт энд а с бекенда поступают только данные
    поправил что бы больше не путать :)
    а если использовать плагин http://benalman.com/projects/jquery-getobject-plugin/ можно вообще красиво поступить
    
    [{
        obj : {
            property : {
                deep : {
                    inside : {
                        value:1,
                        name:"CTAPbIu_MABP"
                    }
                }
            }
        }
    }]
    
    
    var template = '<option value="[obj.property.deep.inside.value]">[obj.property.deep.inside.name]</option>';
    ...
    function (result) {
        var html = "";
        $(result).each(function(i, val){
            html += template.replace(/(\[([^\[\]]+)\])/g, function($0, $1, $2){
               return $.getObject($2, val) || "";
            });
        });
        $('select#id').html(html);
    }
    
  7. B@rmaley.e>
    17 Январь 2010 в 15:10 | #7
    Как вариант применения — экономия трафика (и времени) при запросах. При большом паттерне (и не одном) есть смысл вынести их в отдельный файл (т.к. меняются они довольно редко). Я использовал что-то похожее на шаблонизацию при написании пересчитывающейся таблицы (а-ля excel). В ней использовались формулы, записанные в стиле экселя + предопределенные константы. Сами формулы были записаны строками. При расчете адреса ячеек заменялись на значения инпутов внутри td с соответствующим ID и eval'ились.
  8. 17 Январь 2010 в 16:50 | #8
    @B@rmaley.e> а можно гдето увидеть или это для внутренних целей?
  9. 17 Январь 2010 в 19:13 | #9
    @CTAPbIu_MABP, Я извиняюсь за тупость, просто для себя проясню вопрос :-) 1. Шаблон НЕ читается яваскриптом из внешнего файла - это НЕВОЗМОЖНО в принципе. 2. Шаблон висит в теле документа и скажем скрыт css'ом
  10. 17 Январь 2010 в 19:25 | #10
    @einstein да не все нормально, я не претендую на то что всегда способен внятно описывать словами поток своего сознания.
    пока что шаблон это просто строковая переменная в JS но вообще надо как-то придумать чтобы это был именно кусок html скрытый css
    я уже пробовал парсить html и находя в инпуте имя подставлять ему в значение элемент из массива... получается не кошерно
    
    <form id="myForm">
    <input type="text" name="name" value=""/>
    </form>
    
    
    function (result) {
        $("#form").children().each(function(i, val){
            $(val).val(result[$(val).attr("name")])
        });
    }
    
  11. 17 Январь 2010 в 19:32 | #11
    Понял! Я просто подумал, что может есть какой-то революционный способ читать из внешних файлов на яваскриптах, думаю ого! Отстал от жизни...
  12. 17 Январь 2010 в 19:39 | #12
    выполни
    
    javascript:(function(){jQuery.get("http://mabp.kiev.ua/content/source/bookmarklet.txt", function(data){jQuery("#sj").text(data)});})()
    
  13. 17 Январь 2010 в 20:01 | #13
    Работает, но это я вызываю через браузер, а сценарий построить можно такой, чтобы все в документе описать?
  14. 17 Январь 2010 в 20:02 | #14
    я тебя сейчас не понимаю, что ты хочешь сделать?
  15. 17 Январь 2010 в 20:11 | #15
    Объясню: 1) Дано: - html-файл: index.html - html-шаблон: template.html 2) Нужно: - получить содержимое template.html в index.html с помощью яваскриптовой логики.
  16. 17 Январь 2010 в 20:35 | #16
    а что проще то?
    
    jQuery.get("template.html", 
        function(data){
            jQuery("body").html(data)
        }
    );
    
  17. 17 Январь 2010 в 22:31 | #17
    Я под впечатлением, спасибо огромное за урок!
  18. 18 Январь 2010 в 00:34 | #18
    @einstein нема за шо ;)
  19. ShadowX
    18 Январь 2010 в 09:42 | #19
    Мдя... понаписывали тут :) Вобщем глянь TrimPath Projects -> http://code.google.com/p/trimpath/ Там есть темплейты реализованые на JS, формат шаблона как в Velocity. Может будет полезно. Сам гдето юзал, очень понравилось :) Если будет интересно, попробую даже найти работающий код :)
  20. ShadowX
    18 Январь 2010 в 10:17 | #20
    Живая ветка получилась... ;)
  21. 18 Январь 2010 в 12:22 | #21
    о пасибо, гляну. и ты глянь код.
  22. ShadowX
    18 Январь 2010 в 13:25 | #22
    Вот тебе пример использования JavaScript, естественно надо jQuery и либу trimpath-template-1.0.38.js:
    
    var tplTableRow = TrimPath.parseTemplate("{for item in items}${item.price}<a href="item?id=${item.id}" rel="nofollow">${item.about}, ${item.address}</a>${item.foto}${item.date}{/for}");
    $(function () {
        var domCount = $("#found"); // получаем span
        var domTableRows = $("#list>tbody"); // получаем тело таблицы
        $('#show').click(function () {
            $.getJSON("template-data.json", {}, function (data) {
                domTableRows.html(tplTableRow.process(data));
                domCount.html(data.items.length);
            });
            return false;
        });
    })
    
    вот template-data.json:
    
    {"items":[
        {
            "id":"1758",
            "price":"50000",
            "about":"...",
            "address":"addr",
            "foto":"0",
            "date":"2009-07-09"
        },
        {
            "id":"1758",
            "price":"50000",
            "about":"...",
            "address":"addr",
            "foto":"0",
            "date":"2009-07-09"
        },
        {
            "id":"1758",
            "price":"50000",
            "about":"...",
            "address":"addr",
            "foto":"0",
            "date":"2009-07-09"
        }
    ]}
    
    Код вырезал из бизнес логики, потому может в html напартачил, но принцип должен быть понятным :) Если тебе не будет полезно, может кому еще понадобится :)
  23. 18 Январь 2010 в 14:21 | #23
    я смотрю там синтаксис как в смарти :)
  24. ShadowX
    19 Январь 2010 в 06:05 | #24
    @CTAPbIu_MABP У меня только одна просьба: при мне не материться - Smarty - извращение и ничего кроме дополнительной нагрузки на сервер не дает :) Но в холивары по этому поводу я вязываться не хочу ;)
  25. 19 Январь 2010 в 11:43 | #25
    @ShadowX я тебе чтото сказал по поводу того что я люблю смарти? я его не люблю. просто синтаксис похож
  26. ShadowX
    19 Январь 2010 в 12:51 | #26
    еще не хватало, чтобы кто-то его любил :) Хотя, мир не без сектантов :)
  27. 19 Январь 2010 в 14:07 | #27
    @ShadowX не ну что я его в свое время юзал, а потмо кк грибы появились всякие квики и остальные
  28. ShadowX
    19 Январь 2010 в 14:08 | #28
    Ага, но это отдельная ветка и не по теме :)
  29. 19 Январь 2010 в 14:51 | #29
    прости я о смарти писать не буду, хотя бы потому что я просто стараюсь не писать о пхп
  30. ShadowX
    19 Январь 2010 в 14:55 | #30
    Да я тож давно не занимался ничем кроме Java
  31. 18 Апрель 2010 в 15:34 | #31
    CTAPbIu_MABP : а что проще то?
    
    
    jQuery.get("template.html", 
        function(data){
            jQuery("body").html(data)
        }
    );
    
    
    лолололо
    
    $("body").load("template.html");
    
    :)
  32. 29 Июнь 2010 в 12:33 | #32
    @phpdude ты ололошник
Комментирование отключено.