Рекурсия Mustache.js

Я пытаюсь построить html-дерево с помощью Mustache.js, но это не позволяет выполнить "Максимальный размер стека вызовов", возможно, из-за бесконечной рекурсии.

Что не так?

var Mustache = require('mustache');

var root = {
    title: 'Gar1',
    children: [{title: 'gar2'}, {title: 'gar3', children: [{title: 'gar4'}]}]
};

var panelTemplate = '{{title}}<ul>{{#children}}<li>{{>panel}}</li>{{/children}}</ul>';

var partials = {panel: panelTemplate};
var output = Mustache.render(panelTemplate, root, partials);


console.log(output);

Ответ 1

Проблема присуща реализации в Mustache.js(отказ от ответственности: не уверен, что проблема в самой спецификации), поскольку алгоритм ищет свойство в своем родителе, когда он не может найти его в текущем контексте.

Чтобы объяснить это кратко: код запускается на вашем шаблоне, выводит Gar1<ul> и находит тег {{#children}}. Так как ваш контекст имеет дочерний тег, он выдает <li> и вызывает частичное, которое теперь будет выполняться во внутреннем контексте {title: 'gar2'}. Когда Mustache снова достигнет вашего тега {{#children}}, теперь выясняется, что текущий контекст не имеет свойства children, поэтому он идет на один уровень вверх, где он действительно находит ваше дочернее свойство и начинает рекурсировать (это настоящее слово?) Снова на себе, как сумасшедший.

Два возможных решения:

1 - измените свои данные, чтобы все записи имели свойство children, а когда node не должно быть детей, установите его на false или null (а не на пустой массив) следующим образом:

var root = {
    title: 'Gar1',
    children: [{title: 'gar2', children: false}, {title: 'gar3', children: [{title: 'gar4', children: false}]}]
};

2 - используйте Handlebars вместо Mustache и оберните <ul> тегом {{#if children}}.

Надеюсь, это поможет, я знаю, что ответ немного запоздал, так как это было задано.

Ответ 2

Вот один объект, который нуждается в рекурсии.

Объект

var obj = [
    {
        obj: true,
        key: 'a',
        value: [
            {
                obj: false,
                key: 'a',
                value: 1
            },
            {
                obj: false,
                key: 'b',
                value: 2
            },
            {
                obj: true,
                key: 'c',
                value: [
                    {
                        obj: false,
                        key: 'a',
                        value: 3
                    }
                ]
            }
        ]
    },
    {
        obj: false,
        key: 'b',
        value: 4
    }
];

Шаблон (recursion.html).

<!-- root -->
<ul>
    {{#value}}
    <li>
        <!-- object -->
        {{#obj}}
        <span><b>{{key}}</b></span>
        {{>object}}
        {{/obj}}
        <!-- value -->
        {{^obj}}
        <span><b>{{key}}</b> <span>{{value}}</span></span>
        {{/obj}}
    </li>
    {{/value}}
</ul>

Первым объектом, в который вы проходите, является корень, у которого нет key только value. Если value имеет свойство obj, установленное в true, то оно представляет собой объект, распечатает его ключ и снова вызовет шаблон рекурсивно для его значения. Если не объект, то нет необходимости в рекурсии, просто распечатайте.

Отредактировать клиентскую сторону.

// html is recursion.html contents
var template = Hogan.compile(html),
    content = template.render({value: obj}, {object: html});
// show the rendered template
$('body').empty().append(content);

Отредактировать серверную сторону с помощью Express.js

res.render('recursion', {
    value: obj,
    partials: {
        object: 'recursion'
    }
});

Вывод этого примера

http://jsfiddle.net/simo/GYjMY/

Btw Я использую Hogan.js для рендеринга шаблона. Я не знаю, поддерживает ли Mustache.js рекурсию или нет.