jQueryしか使ってはいけないときの、適当なテンプレートエンジン

# jQueryしか使っちゃダメ！？

　そういう案件あるみたいです。
　でも、私はDOMいじりが苦手です。
　というか、入力値→表示値→入力値と行き来するのがすごくつらい。
# なので、やっつけました。
## 動き
- 初期化時に、指定したID以下にある、templateクラスがついたものを奪い取る。
- updateイベントのハンドラを追加する。
- updateイベントでは、データをデータ件数レンダリングしてHTMLをがさっと書き換える。

![before.PNG](https://qiita-image-store.s3.amazonaws.com/0/133692/c4008f52-eb44-41bf-358e-1966a574ba6b.png)

をテンプレートにして、

![jquery_control.gif](https://qiita-image-store.s3.amazonaws.com/0/133692/3d1a13d6-4d98-1911-0dec-7bf49df019f7.gif)

こういう動きをさせる。
## 実装

```js:template.js
(function(global) {
    if (!global.$kl) global.$kl = {};
    if (!global.$kl.t) global.$kl.t = {};
    var templates = {};
    var escapeMap = {
        '&': '&amp;',
        '\x27': '&#39;',
        '"': '&quot;',
        '<': '&lt;',
        '>': '&gt;',
    };

    function escapeCallback(char) {
        if (!escapeMap.hasOwnProperty(char)) {
            throw new Error;
        }
        return escapeMap[char];
    }

    global.$kl.t.escapeHtml = function(str) {
        return String(str).replace(/[&"'<>]/g, escapeCallback);
    }
    global.$kl.t.getTemplate = function(holderId) {
        var template = $("#" + holderId + " > .template").prop('outerHTML');
        $("#" + holderId + " > .template").remove();
        return template;
    }
        //テンプレートを奪い取ってしまうやつ
    global.$kl.t.setupTemplate = function(holderId) {
        templates[holderId] = global.$kl.t.getTemplate(holderId);
        //Updateされたら、中身を再度レンダリングして更新する
        $("#" + holderId).on('update', function(e, params) {
            //独自イベント：レンダリング
            $("#" + holderId + " > .template").remove();
            var all = "";
            var data = params.list;
            if (params.list.length == 0) {
                $("#" + holderId).css('display', 'none');
                return;
            }
            $("#" + holderId).css('display', '');
            for (var k in data) {
                var row = templates[holderId];
                row = row.replace(/\{\{(.*?)\}\}/g, function(all, key) {
                    return !data[k][key] ? "" : data[k][key];
                });
                row = row.replace(/\{(.*?)\}/g, function(all, key) {
                    return !data[k][key] ? "" : global.$kl.t.escapeHtml(data[k][key]);
                });
                all += row;
            }
            $("#" + holderId).html(all);
        });
        $("#" + holderId).trigger('update', {
            list: []
        });
    }

})((this || 0).self || global);
```

## 使い方
```html:hoge.html

<input type="text" id="search" onkeyup="doSearch()">

<div id="lookup_list" style="position:absolute;background-color:white;z-index:10;border:1px solid black;height:auto">
    <div class="template" onclick="select('{code}')">{code}：{name}</div>
</div>

<scirpt>
    $(document).ready(function() {
        $kl.t.setupTemplate("lookup_list");
    }
    function doSearch() {
        var searchKey = $("#search").val();
        $.ajax({
            'url': './search.php',
            'dataType': 'json',
            'data': {
                searchkey: searchKey
            }
        }).then(function(result) {
            $("#lookup_list").trigger('update', {list:result});
        });
    }
</script>
```

※search.phpはこんな結果を返します。

```json
[
    {"code":"aaaa","name":"ああああ"},
    {"code":"aaai","name":"あああう"},
    {"code":"aaau","name":"あああえ"}
]
```