Решение для создания шаблонов Javascript, которое позволяет после рендеринга использовать внедренные объекты?

Итак, я создаю приложение на основе Backbone.js, используя шаблоны для рендеринга некоторых объектов.

Это работает, однако теперь мне нужно динамически ссылаться на объекты во время выполнения, и я не уверен, что это возможно с решениями для шаблонов, которые я видел (подчеркивание, руль,...), которые «выравнивают» javascript.

Для иллюстрации у меня есть список объектов, скажем, Задачи. У меня есть модель, которую можно упростить как таковую:

{{#each tasks.models as |task|}}
<div>
{{task.name}}
</div>
{{/each}}

Теперь мне нужно будет использовать объект «задача» динамически после завершения рендеринга. Например, сделайте что-то вроде этого:

<div>
{{task.name}} - <button onClick="task.setComplete()" />
</div>

Конечно, этот способ не работает; и не делайте что-то вроде {{task}}.setComplete(), так как {{task}} преобразуется в строку при рендеринге.

Есть ли способ сделать это?

Я думал, что мне нужны замыкания, чтобы сохранить объекты, единственный способ получить их - не сглаживать html, так как в противном случае все преобразуется в строку.

Есть идеи? Может быть, существуют библиотеки шаблонов, которые позволили бы напрямую генерировать объекты DOM, которые я мог бы добавить в свой документ?

Заранее спасибо,


person Eino Gourdin    schedule 08.09.2015    source источник
comment
Вы используете Backbone, так зачем вам использовать атрибут onClick, а не обрабатывать событие клика через events представления? Попытка смешать функциональный код с вашими шаблонами отображения обычно приводит к запутанной путанице.   -  person mu is too short    schedule 08.09.2015
comment
Спасибо за отзыв! Если нет возможности сделать ссылку в шаблоне, это то, что я сделаю. Однако мне нужно будет сопоставить идентификаторы объектов из шаблона с идентификаторами в моем магистральном коде на нескольких уровнях, поэтому кажется, что полученный код будет более сложным, чем прямая ссылка в шаблоне.   -  person Eino Gourdin    schedule 09.09.2015
comment
Вы можете добавить id в атрибуты данных следующим образом: stackoverflow.com/a/7825773/479863   -  person mu is too short    schedule 09.09.2015


Ответы (2)


Этот вопрос отмечен тегом backbone.js поэтому вам следует использовать обычную систему обработки событий представления Backbone вместо обработчиков onclick. Вы упомянули tasks.models, так что предположительно tasks является коллекцией.

Одним из подходов было бы использование атрибутов данных для хранения модели ids. Ваш шаблон будет выглядеть так:

{{#each tasks}}
    <div>
        {{name}} - <button data-id="{{id}}" type="button">Completed</button>
    </div>
{{/each}}

и тогда ваше представление будет настроено следующим образом:

Backbone.View.extend({
    events: {
        'click button': 'completed'
    },
    render: function() {
        var t = Handlebars.compile($('#whatever-the-template-is').html());
        this.$el.append(t({
            tasks: this.collection.toJSON()
        }));
        return this;
    },
    completed: function(ev) {
        var id = $(ev.currentTarget).data('id');
        var m  = this.collection.get(id);
        // Do whatever needs to be done to the model `m`...
    }   
});

Демо: https://jsfiddle.net/ambiguous/z7go5ubj/

Весь код остается в представлении (где уже есть все данные), а шаблон обрабатывает только представление. Никаких глобальных переменных, хорошее разделение задач и идиоматическая структура Backbone.

Если части вашего представления для каждой модели более сложны, вы можете иметь одно представление для коллекции и подпредставления для каждой модели. В этом случае ваши шаблоны для каждой модели будут выглядеть так:

<div>
    {{name}} - <button type="button">Completed</button>
</div>

Больше никаких атрибутов данных не требуется. У вас будет новое представление для каждой модели примерно так:

var VM = Backbone.View.extend({
    events: {
        'click button': 'completed'
    },
    render: function() {
        var t = Handlebars.compile($('#whatever-the-template-is').html());
        this.$el.append(t(this.model.toJSON()));
        return this;
    },
    completed: function() {
        console.log('completed: ', this.model.toJSON());
    }   
});

и цикл переместится в представление коллекции:

var VC = Backbone.View.extend({
    render: function() {
        this.collection.each(function(m) {
            var v = new VM({ model: m });
            this.$el.append(v.render().el);
        }, this);
        return this;
    }
});

Демо: https://jsfiddle.net/ambiguous/5h5gwhep/

Конечно, в реальной жизни ваш VC будет отслеживать свои VM, чтобы VC#remove мог вызывать remove для всех своих дочерних VM.

person mu is too short    schedule 10.09.2015

Мой ответ - всего лишь намек, я старался держаться ближе к вопросу. Обратитесь к этому ответу для лучшего решения: https://stackoverflow.com/a/32493586/1636522.

Вы можете использовать индекс или любую другую информацию, чтобы найти элемент. Вот пример использования Handlebars, предполагая, что каждая задача может быть идентифицирована по идентификатору:

var tasks = [];
var source = $('#source').html();
var template = Handlebars.compile(source);
tasks[0] = { id: 42, label: 'coffee', description: 'Have a cup of coffee.' };
tasks[1] = { id: 13, label: 'help', description: 'Connect to StackOverflow.' };
tasks[2] = { id: 40, label: 'smile', description: 'Make μ smile.' };
$('#placeholder').html(template({ tasks: tasks }));

function onClick (id) {
  var task, i = 0, l = tasks.length;
  while (i < l && tasks[i].id !== id) i++;
  if (i === l) {
    // not found
  }
  else {
    task = tasks[i];
    alert(task.label + ': ' + task.description);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.2/handlebars.min.js"></script>
<script id="source" type="text/x-handlebars-template">
  {{#each tasks}}
  <button 
    type="button" 
    class="task" 
    style="margin-right:.5em"
    onclick="onClick({{id}})"
  >{{label}}</a>
  {{/each}}
</script>
<div id="placeholder"></div>

person leaf    schedule 08.09.2015