Как добавить компоненты условно внутри другого компонента

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

Шаблон для родительского компонента

<div id="container">
</div>

Модель просмотра для родительского компонента

define(["jquery", "knockout", "ko-postbox", "text!./parent.html"], function($, ko, kopost, template) {

    function displayChildContent(value) {
        switch (value.toLowerCase()) {
            case "child":
                //
                // How to load child component?
                //
                break;
            default:
                break;
        }
    }

    function ParentViewModel() {
        ko.postbox.subscribe("child-click", function(newValue) {
            displayChildContent(newValue);
        }, this);
    }

    return { viewModel: ParentViewModel, template: template };
});

Шаблон для дочернего компонента

<div>
    <h1>Child</h1>
</div>

Модель просмотра для дочернего компонента

define(["text!./child.html"], function(template) {

    function ChildViewModel() {
    }

    return { viewModel: ChildViewModel, template: template };
});

Щелчок срабатывает, но я не знаю, как добавить дочерний шаблон в родительский шаблон. Кроме того, я планирую передать некоторые данные от родителя к дочернему элементу, используя привязку params к пользовательскому элементу. После того, как я добавлю дочерний шаблон к родительскому, сможет ли он это сделать?


person g_b    schedule 08.08.2015    source источник


Ответы (1)


В вашем родительском компоненте добавьте строку, похожую на:

<!-- ko if: childTmpl --><!-- ko component: {name: 'child'} --><!-- /ko --><!-- /ko -->

где childTmpl — логическая наблюдаемая, подписанная на child-click. Теперь это может создать небольшую проблему, если вы не хотите тесно связывать компонент с именем «дочерний» внутри родителя. В этом случае вы все равно можете заменить его свойством (n observable) в родительской модели представления или даже динамически чередовать. Это станет:

<!-- ko if: childTmpl --><!-- ko component: {name: childComp} --><!-- /ko --><!-- /ko -->

где childComp — это свойство ParentViewModel, которое вы можете заполнить через params/fixed value/observable. Вот образцы моделей, с которыми я тестировал:

function ParentViewModel(params) {
  this.childComp = params && params.child || 'child';
  this.childTmpl = ko.observable(true).subscribeTo("child-click");
}

function ChildViewModel(params) {
  this.buttonClicked = ko.observable(true).publishOn("child-click");
}
ChildViewModel.prototype.toggle = function() { 
  this.buttonClicked(!this.buttonClicked()); 
};

В тестовом примере нажатие кнопки в дочернем компоненте (который изначально показан) запускает buttonClicked в false, который затем также обновляет childTmpl в false, удаляя дочерний компонент. См. полную скрипку здесь:

http://jsfiddle.net/ohdodfzr/2/

Что касается вашего второго вопроса:

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

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

<!-- ko component: {name: 'child', params: {parent: $data}} -->
person Tyblitz    schedule 08.08.2015
comment
Спасибо. У меня все еще не работает из-за другой проблемы, но я думаю, что ваше решение правильное. Теперь я столкнулся с новой проблемой. Может быть, вы можете посмотреть (stackoverflow.com/questions/31899738/)? Я все равно отмечу это как ответ, так как считаю, что это правильный способ сделать это. - person g_b; 09.08.2015
comment
@g_b Я вижу пару проблем с вашим кодом во втором вопросе. Первая ошибка [Object Object] связана с тем, что вы передаете экземпляр вместо конструктора. Если ваш компонент имеет только 1 экземпляр, вы можете вернуть viewModel: {instance: model}, иначе вам нужно установить подписку на почтовый ящик внутри конструктора (как я сделал здесь). Не уверен, что подписка на почтовый ящик срабатывает напрямую, но вы все равно должны установить ее после объявления модели. Также сделал вещи с requirejs и почтовым ящиком, и мне пришлось установить if (!ko.postbox) ko.postbox = kopost;, чтобы он работал, но не знаю, имеет ли это значение здесь. - person Tyblitz; 09.08.2015