Как связать вложенные компоненты нокаута с помощью разметки веб-компонента?

Я действительно хочу использовать вложенную разметку в стиле web-component, но у меня никогда не получается заставить ее работать. У меня это работает из-за примечания здесь (в ответе):

Проблема связана с тем, как параметры передаются в компонент при использовании синтаксиса «веб-компонент».

Я не очень понимаю, о чем они говорят, а ОП имеет дело с массивами. Я понимаю, что он создает вычисляемые наблюдаемые из вещей. Но params в моем конструкторе вложенного компонента всегда $raw и ничего.

<parent-component>
  <content>
    <!--works-->
    <div data-bind="component: { name: 'child-component', params: { id: $parent.id } }"></div>

    <!-- does not work -->
    <child-component params="id: '{{$parent.id}}'"></child-component>

  </content>
</parent-component>

jsFiddle

Почему я не могу вложить компоненты нокаута в стиле web-component и выполнить привязку?


person Nateous    schedule 26.04.2016    source источник
comment
Не могли бы вы расширить свой пример кода до минимально воспроизводимого примера?   -  person Jeroen    schedule 26.04.2016
comment
Я сделаю это, как только смогу!   -  person Nateous    schedule 27.04.2016


Ответы (2)


У меня есть пример веб-компонентов здесь https://github.com/brianlmerritt/knockout-babel-browserify-gulp

Типичный основной html с компонентами:

    <div class="row">
        <div class="panel panel-primary">
            <div class="panel-heading">
                <h2>Three Component View Model Binding Test</h2>
            </div>
            <div class="panel-body">
                <!-- THE GOAL OF THE PROJECT IS TO BIND EVERYTHING BEFORE AND AFTER THE FOLLOWING COMPONENT WITH centralViewModel -->
                <!-- ###ko stopBinding: true -->
                <div class="col-md-4">
                    <component-one></component-one>
                </div>
                <div class="col-md-4">
                    <component-two></component-two>
                </div>
                <div class="col-md-4">
                    <component-three></component-three>
                </div>
                <!-- ###/ko -->

                <p>Note: if component one did not load above, then check your browser console for errors</p>
            </div>

типичный компонент - обратите внимание, он написан на ES2015 (новый Javascript)

const ko = require('knockout')
        , CentralData = require('../../service-providers/central-data')
        , CentralState = require('../../service-providers/central-state')
        , template = require('./template.html');

    const viewModel = function (data) {

        //Make service providers accessible to data-bind and templates
        this.CentralData = CentralData;
        this.CentralState = CentralState;

        this.componentName = 'Component One';
        this.foo = ko.observable(`${this.componentName} Foo`);
        this.bar = ko.observableArray(this.componentName.split(' '));
        this.barValue = ko.observable("");
        this.bar.push('bar');
        this.addToBar = (stuffForBar) => {
            if(this.barValue().length >= 1) {
                this.bar.push(this.barValue());
                CentralData.pushMoreData({firstName: this.componentName,secondName:this.barValue()});
            }
        };
        this.CentralState.signIn(this.componentName);
        if (CentralData.dataWeRetrieved().length < 10) {
            var dataToPush = {firstName : this.componentName, secondName : 'Foo-Bar'};
            CentralData.pushMoreData(dataToPush);
        }
    };
    console.info('Component One Running');
    module.exports = {
        name: 'component-one',
        viewModel: viewModel,
        template: template
    };

шаблон.html:

    <div>
        <h1 data-bind="text: componentName"></h1>
        <p>Foo is currently: <span data-bind="text: foo"></span></p>
        <p>Bar is an array. It's values currently are:</p>
        <ul data-bind="foreach: bar">
            <li data-bind="text: $data"></li>
        </ul>
        <form data-bind="submit: addToBar">
            <input type="text"
                   name="bar"
                   placeholder="Be witty!"
                   data-bind="attr: {id : componentName}, value : barValue" />
            <button type="submit">Add A Bar</button>
        </form>
        <h2>Central State</h2>
        <p>The following components are currently signed in to Central State Service Provider</p>
        <ul data-bind="foreach: CentralState.signedInComponents()">
            <li data-bind="text: $data"></li>
        </ul>
        <h2>Central Data</h2>
        <p>The following information is available from Central Data Service Provider</p>
        <table class="table table-bordered table-responsive table-hover">
            <tr>
                <th>Component Name</th><th>Second Value</th>
            </tr>
            <!-- ko foreach: CentralData.dataWeRetrieved -->
            <tr>
                <td data-bind="text: firstName"></td><td data-bind="text: secondName"></td>
            </tr>
            <!-- /ko -->
        </table>
        <h3>End of Component One!</h3>
    </div>

app.js имеет привязки компонентов

const ko = require('knockout');

/**
 * The modules that follow are singleton modules that do not appear to conflict with bindings
 *
 */

const CentralData = require('./service-providers/central-data');   // Mock centralised data/model service
const CentralState = require('./service-providers/central-state'); // Mock centralised state service

/**
 * Register knockout web components - these work, but conflict with any central bindings
 */

ko.components.register(
    'component-one',
    require('./components/component-one/component.js')
);

ko.components.register(
    'component-two',
    require('./components/component-two/component.js')
);

ko.components.register(
    'component-three',
    require('./components/component-three/component.js')
);

/**
 * This code comes from http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html
 *
 * Telling Knockout to Skip Binding Part of a Page
 *
 * However, when used around a component, the component does not load/run!
 *
 */

ko.bindingHandlers.stopBinding = {
    init: function() {
        return { controlsDescendantBindings: true };
    }
};

ko.virtualElements.allowedBindings.stopBinding = true;


/**
 * centralViewModel should be loadable for "all of the page not managed by components"
 *
 * That is the goal of the project, which I am failing in badly at the moment
 *
 */

const centralViewModel = {
    bindingWorked : ko.observable('The binding worked. KO view model centralViewModel has a this context and was bound to the html correctly')
};

console.info('app.js applying bindings...');

/**
 * The next line should bind central viewmodel to everything, but conflicts with components!!
 */

ko.applyBindings(centralViewModel,document.body);

// ko.applyBindings(); // Pull in all of the components


/**
Note: to avoid binding issues, we should be able to add these html comments around each component
 <!-- ko stopBinding: true -->
 <component-name>
 <!-- /ko -->
 However - when we do, the components no longer work
 */
person brianlmerritt    schedule 27.04.2016
comment
Я не вижу никаких вложенных компонентов, которые используют разметку в стиле web component, хотя... это моя проблема. - person Nateous; 27.04.2016
comment
Извините, я думал, что <component-two></component-two>, например, это то, что вам нужно. - person brianlmerritt; 27.04.2016
comment
вложенный - это ключ для меня, один компонент внутри другого, оба с пользовательской разметкой внутри компонента. - person Nateous; 28.04.2016
comment
Если вы используете метод пользовательских компонентов, вы можете вкладывать столько, сколько хотите. Каждый компонент будет вызывать следующий. Трудной задачей для меня было заставить привязку ko работать на остальной части страницы за пределами нокаутирующих компонентов, не конфликтуя с внутренними привязками. - person brianlmerritt; 28.04.2016
comment
Иногда связывание контекста может быть затруднено. Я также использую qtip для некоторых всплывающих окон и должен выполнить привязку, когда он открывается, но вы должны быть осторожны, потому что KO не позволяет вам привязываться несколько раз к одной и той же разметке. Спасибо за советы, хотя! - person Nateous; 28.04.2016
comment
Не беспокойтесь — я проведу рефакторинг своего примера, включив в него вложенные компоненты и отключив привязку компонентов. - person brianlmerritt; 28.04.2016

Что ж, спасибо @Jeroen за то, что заставил меня привести лучший пример.

Моя проблема заключалась в том, что я заключал параметр в одинарные кавычки и использовал {{handle bars}} для привязки. как только я удалил их, кажется, что они работают нормально.

    <!-- does not work -->
    <child-component params="id: '{{$parent.id}}'"></child-component>

    <!-- wow, this does work! -->
    <child-component params="id: $parent.id"></child-component>
person Nateous    schedule 27.04.2016