Как пользовательские элементы в Knockout должны взаимодействовать со своими соавторами?

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

Как всегда, зависит от того, что считать хорошей архитектурой ;-)

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

В моем случае:

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

Учитывая пользовательский элемент с одной кнопкой сохранения, которая должна активироваться только после того, как что-то изменилось, мы могли бы передать координатор следующим образом:

function CustomElement(params) {
    var coordinator = params.coordinator;
    var enabled = this.enabled = ko.observable(false);

    this.save = function() {
        coordinator.save();
    }

    coordinator.onchange(function(hasChanges) {
        enabled(hasChanges);
    });
}

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

function ParentView() {
    this.coordinator = new CustomElementCoordinator();
}

И передать его через параметры:

<custom-element params="coordinator: coordinator"></custom-element>

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

custom-elements
    - custom-element
        - coordinator.js
        - model.js
        - template.html

Что вы думаете? Я что-то напутал или неправильно к этому подхожу?


person Thomas Eyde    schedule 07.03.2015    source источник
comment
Но... но... почему? Для меня это звучит так, как будто вы хотите реализовать контроллер MVC (например, найденный в Angular) в KO (MVVM); тогда как в KO представление уже делает это (например, оно передает значения вашей модели компоненту через представление; более того, оно может напрямую изменять вашу модель, поэтому предлагаемые «onchange» и «save» всегда неявно выполняются в наблюдаемых) . Так что, на мой взгляд, это просто ненужный дополнительный шаг...   -  person Tyblitz    schedule 08.03.2015
comment
@Tyblitz, как бы вы разработали пользовательские элементы для взаимодействия друг с другом или с любым другим компонентом? Почему я не хочу, чтобы элемент-а был связан с элементом-б. И если мне нужны два экземпляра element-a в представлении, я не хочу, чтобы события из одного мешали другому. Допустим, три элемента — это разные фильтры, один элемент — это список, а основная модель представления ссылается на фактическую службу, которая выполняет запрос и возвращает отфильтрованный результат. Допустим, список используется и в других представлениях, но с другим сервисом и без фильтра.   -  person Thomas Eyde    schedule 09.03.2015
comment
По сути, я бы использовал централизованную главную виртуальную машину в качестве координатора вместо создания одной для каждого компонента, что, я думаю, хорошо сочетается с нисходящий характер JS/DOM/KO. Например, проверьте эту скрипту, которая использует компонент списка и 2 компонента фильтра, все с тем же шаблоном, но измененными массивами. Надеюсь, он достаточно точно описывает ситуацию, которую вы описали.   -  person Tyblitz    schedule 10.03.2015
comment
Интересный! Давайте сравним записи. Я создал скрипку, в которую добавил несколько дополнений, чтобы лучше показать, что я имею в виду. В общем, я считаю плохой практикой объявлять наблюдаемое в одном представлении, а затем привязываться к нему в другом. Также использование наблюдаемых для межкомпонентной связи кажется неправильным. В скрипке я пытаюсь удалить связь между компонентами и формализовать коммуникационный контракт в их собственных классах.   -  person Thomas Eyde    schedule 10.03.2015
comment
Это выглядит очень, очень аккуратно. У меня есть некоторые мысли. Возможно, нам следует продолжить в этой теме Я начал, чтобы не загромождать комментарии (если это станет что-то, вы можете сослаться на это в ОП). (Ответ на ваш последний комментарий там же)   -  person Tyblitz    schedule 10.03.2015


Ответы (1)


В довольно большом споре о межкомпонентной коммуникации я придерживаюсь мнения, что чем проще, тем лучше.

Каков самый старый и самый надежный способ общения между элементами DOM (какими компонентами они станут в конечном итоге)? Конечно, события!

Ваш компонент должен использовать Knockout для работы с внутренним состоянием. Однако добавление API событий может творить чудеса с точки зрения совместимости. Если все ваше приложение однажды не будет управляться с помощью Knockout (и, поверьте мне, это вполне может случиться), ваш компонент не будет полностью бесполезным.

Это так же просто, как:

$(window).on("myEvent.myComponent", this.handleMyEvent) //listen to the world
$("#myNode").trigger("finished.myComponent", ["param1", "param2"]) // talk to the world

Если вы хотите захватить элемент узла вашего компонента при его внедрении, взгляните на стиль createViewModel в соответствии с этим вопросом: Как получить доступ к пользовательскому элементу в компоненте Knockout?

person Guilherme Rodrigues    schedule 11.03.2015
comment
Я действительно не поклонник строковых событий. Я экспериментировал с этим и обнаружил, что сама строка может создавать жесткую связь между пользовательскими элементами. Я вижу риск того, что один пользовательский элемент может перестать работать, когда мы удалим другой. - person Thomas Eyde; 11.03.2015
comment
Выберите строки в именах событий или именах функций :) - person Guilherme Rodrigues; 11.03.2015