Knockout.js - ленивая загрузка шаблонов

Итак, я исхожу из шаблонного рабочего процесса, который включает в себя создание объекта данных (сродни модели представления в нокауте), передающей это в механизм шаблонов (jstemplate в нашем случае), рендеринг шаблона с использованием этого объекта данных и добавление его к дом.

Как достичь аналогичного рабочего потока с нокаутом? Является ли поток управления "if" тем, что я ищу? Или привязать шаблоны в тегах script без атрибутов привязки данных и добавить их динамически позже и обработать шаблон, например, ko.applyBindings(viewModel, node)?

Мне любопытно, как другие ленивые шаблоны загрузки используют нокаут.

Кроме того, дополнительный кредит, если вы можете сказать мне, почему js скрипка ниже не работает, как я ожидал бы. Я пытаюсь изучить привязку потока управления if, и это не работает.

http://jsfiddle.net/JJgJ7/1/

Ответы

Ответ 1

Есть несколько направлений, которые вы можете использовать для чего-то вроде этого:

вы можете применять разные модели представлений к различным элементам, как вы упомянули, например:

var viewModelOne = { ...  };
var viewModelTwo = { ...  };
ko.applyBindings(viewModelOne, containerElementOne);
ko.applyBindings(viewModelOne, containerElementOne);

Вы даже можете динамически применить привязку со своими данными к элементу типа:

var viewModelOne = { ... };
ko.applyBindingsToNode(containerElement, { template: { name: 'itemTemplate', foreach: items }, viewModelOne);

Похоже на этот образец: http://jsfiddle.net/rniemeyer/gYk6f/

Вы также можете сделать что-то вроде:

var mainViewModel = {
   sideBarModel = ko.observable(),
   contentModel = ko.observable()
};

Затем привяжите его так:

<div data-bind="with: contentModel"></div>
<div data-bind="with: sideBarModel"></div>

Они могут даже быть вложенными как:

<div data-bind="with: contentModel">
   ...
   <div data-bind="with: $root.sideBarModel"></div>
</div>

Поскольку модели наблюдаемы, они могут изначально быть пустыми и заполняться по требованию.

Вы можете использовать именованные шаблоны в таких случаях, как:

<div data-bind="template: { name: "contentTmpl", data: contentModel }"></div>
<div data-bind="template: { name: "sideBarTmpl", data: sideBarModel }"></div>

За вопрос о дополнительном кредите:

Теги

p не могут содержать другие элементы уровня блока (например, ваш div). Браузер перемещает его из тега p. Замените div на span, и он будет вести себя так, как вы ожидаете (или замените p на div).

Ответ 2

Я знаю, что ответ по-прежнему старый, я думаю, вам было бы интересно посмотреть на это. Это мой образец. Можно сказать, что я злоупотребляю концепцией нокаутов, но здесь он... он работает!

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

Скажем, у вас есть это.

<script type="text/html" id="template-emtpy">

</script>

Cool теперь позволяет взглянуть на то, как работает шаблон для нокаута, шаблон нокаута - это просто привязка на самом деле, поэтому он проверяется во время выполнения и всякая причудливая вещь, которую вы можете сделать до начала работы. И это означает, что у вас могут быть такие вещи.

<div data-bind="template: { name: activeTemplate, data: contentModel }"></div>

где activeTemplate может быть наблюдаемым объектом! О, так что наблюдаемые действительно работают там... когда наблюдаемый объект изменяется, тогда шаблон уведомляется и введет редердер с правильным шаблоном.

Теперь, когда вы понимаете, что мы можем на самом деле установить шаблон и изменить его в будущем, вы поймете, что до тех пор, пока наш шаблон не будет загружен, мы отправим нокаутом пустой шаблон. Не будет никакой ошибки привязки, потому что ничего не нужно связывать ничего!

Теперь давайте посмотрим на это!

<div data-bind="template: { name: getTemplate('reports'), data: contentModel }"></div>

Где getTemplates определяется как:

window.getTemplate = function (name) {
    var baseUrl = "/templates/";

    var loaded = ko.observable(false);

    var template = document.getElementById('template-' + name);

    if (template) {
        loaded(true);
    } else {
        jQuery.get(baseUrl + name + '.html', function (data) {
            var scriptTag = $('<script type="text/html" id="template-' + name + '"></script>');
            scriptTag.html(data);
            $('head').append(scriptTag);
            loaded(true);
        });
    }

    return ko.computed(function () {
        if (loaded()) {
            return 'template-' + name;
        } else {
            return "template-empty";
        }
    })();
};

Подводя итог, мы создаем наблюдаемый загруженный по умолчанию false. Если мы найдем шаблон, мы изменим значение на true. Если нет, мы попытаемся загрузить его с помощью jQuery (загрузите его, как вам нравится... вы могли бы определенно разместить текстовую область и загрузить шаблон оттуда. Все возможно...).

Возвращаем вычисленное значение, зависящее от наблюдаемого loaded. Когда загружается значение true, оно вернет идентификатор загруженного шаблона. По некоторым причинам, knockoutjs требует, чтобы текст находился внутри тега script html. Поэтому я обновляю тег script с помощью html.

Так что это. Кроме того, я могу ошибаться, и я не уверен, как обрабатывать дескрипторы нокаута, но можно было бы включить и выключить загрузку, чтобы перезагрузить шаблоны... И это означает, что вы можете иметь динамически загружаемую и редактируемую шаблонную awesomness!!!

Также обратите внимание, что я выполняю вычисляемое значение непосредственно перед его возвратом. И обратите внимание, что функция является глобальной... Чтобы исправить это! Создайте свою собственную привязку, чтобы сделать что-то вроде этого:

<div data-bind="lazy_template: { name: "reports", data: contentModel }"></div>

И тогда тебе хорошо идти. Все, что вам нужно сделать, это поместить логику загрузки в пользовательскую привязку.

Я создам проект на github со всем работающим, которого я хочу, это поможет. Я позже обновлю URL.

Не может быть стабильным, потому что я взломал его через полчаса, но он работает для меня. Вероятно, мне придется написать несколько тестов, но в любом случае. Повеселись! https://github.com/llacroix/knockout-lazy-template