使用从 ajax 响应生成的 handlebars.js 模板

Consuming handlebars.js template generated from ajax response

handlebars.js 模板在服务器端生成并作为响应的一部分返回。

"<div>{{name}}<small style='color:#999;'><br><code>{{vafm}}</code></small><br><code>{{email}}</code></div>"

.

var t = "";

        $('#UniqueId').select2({
            ajax: {
                url: '/search/endpoint',
                dataType: 'json',
                processResults: function (data) {
                    t = data.template;
                    return {
                        results: data.results
                    };
                },
            },
            templateResult: Handlebars.compile(t),
            escapeMarkup: function (m) {
                return m;
            }
        });

不幸的是 select2 上的渲染部分不包含 data.results 返回的值

我已将问题定位到这一行

templateResult: Handlebars.compile(t),

自从尝试了

<script>
    const template = Handlebars.compile(@Html.Raw(Model.Template));
</script>

templateResult: template,

按预期工作。

在最后一个例子中,我从模型中传递了模板,

但我不需要从 ajax 响应中传递它并获得相同的输出。

存在多个问题:

  • templateResult 需要回调函数,但您传递的是已编译的 Handlebars 模板对象。 the select2 docs 中对此进行了描述。因此,假设您已经在正确的位置执行了以下操作:
var t = Handlebars.compile(...)

然后像这样的东西会起作用:

templateResult: function(data) {
    if (!data.id) return data.text;
    return $(t({
        name: 'example name',
        vafm: 'example vafm',
        email: 'example email'
    }));
  • 模板html必须有一个封闭元素,所以把东西放在<div></div>中,例如

  • 您的模板缺少 <small> 开始标记


所以让我们假设您的服务器发送一些 JSON 如下所示。每个结果的模板都会一起发送,并且每个结果都可以不同。特定于模板的数据也是如此:

[
    {
        "id": 1,
        "text": "Henry",
        "data": {
            "vafm": "1234",
            "email": "henry@example.com"
        },
        "template": "<div>{{text}}<br><small>vafm: {{data.vafm}}</small></div><small>email: {{data.email}}</small>"
    }, {
        "id": 30, 
        "text": "Tesla Roadster",
        "data": {
            "price": "0.000",
            "color": "dark red"
        },  
        "template": "<div>{{text}}<br><small>price: {{data.price}}</small></div><small>color: {{data.color}}</small>"
    }
]

在您的 JavaScript 中加上类似的东西,它应该可以工作:

$('#UniqueId').select2({
    ajax: {
        url: '/search/endpoint',
        dataType: 'json',
        processResults: function(data) {
            /** Note: select2 expects "results" to be an array of objects, each containing
             *  at least "id" (becomes the value) and "text" (displayed text). I made the
             *  format from the server match that (plus added some more info), so that I don't
             *  need any conversions except for compiling the template. I do that with
             *  Array.prototype.map() in this case, but of course a for-loop would work too.
             */
            return {
                results: data.map(function(e) {
                    e["template"] = Handlebars.compile(e["template"]);
                    return e;
                })
            };
        }
    },
    templateResult: function(el) {
        if (!el.id) return el.text;
        /*  Note: "el" will be just like it came from the server, except for the
         *  modifications we applied in processResults. We can just pass "el" to
         *  the compiled template entirely and there, only pick what we need.
         */
        return $(el["template"](el));
    }
});