KnockOutJS - кілька моделей перегляду в одному перегляді


201

Я думаю, що моє додаток зараз стає досить великим, занадто великим, щоб обробляти кожен View з одним ViewModel.

Тож мені цікаво, наскільки складно було б створити кілька ViewModels і завантажити їх все в один Перегляд. Зауваживши, що мені також потрібно мати можливість передавати дані X ViewModel у дані Y ViewModel, тому окремі ViewModels повинні мати можливість спілкуватися один з одним або принаймні знати один одного.

Наприклад, у мене <select>випадає, що випадаюче меню має вибраний стан, який дозволяє мені передавати ідентифікатор обраного елемента в <select>інший виклик Ajax в окремий ViewModel ....

Були оцінені будь-які моменти щодо спілкування з численними ViewModels в одному Погляді :)


12
Для тих, хто надходить на це запитання, прокрутіть повз прийняту відповідь. Тепер нокаут підтримує декілька обов'язкових контекстів . У гіганта немає потреби masterVM.
Керрі Кендалл

Відповіді:


150

Якщо всі вони повинні знаходитись на одній сторінці, один простий спосіб зробити це - мати модель перегляду, що містить масив (або список властивостей) інших моделей перегляду.

masterVM = {
    vmA : new VmA(),
    vmB : new VmB(),
    vmC : new VmC(),
}

Тоді ви masterVMможете мати інші властивості, якщо потрібно, для самої сторінки. Комунікація між моделями перегляду не складе труднощів у цій ситуації, оскільки ви можете передати ретрансляцію masterVM, або ви можете використовувати $parent/ $rootв прив'язки, або деякі інші користувацькі параметри.


2
Тож я міг би зробити щось на кшталт: data-bind = "text: masterVM.vmA", я припускаю, що все-таки можу використовувати ko.applyBindings з доданим елементом DOM. Припустимо, що також означатиме, що я міг би зробити: data-bind = "$ parent.masterVm"?
Кліун

12
@CLiown Ви можете використовувати with:прив'язку, тому ви не повторитесь
AlfeG

4
@CLiown Так, ви могли б зробити це, якщо ви прив'язані до masterVM. Ви також можете скористатися прив'язкою "з", щоб уникнути синтаксису крапок під час занурення в моделі під виду.
Джон Папа

1
Я думаю, що цей підхід є дуже обмежуючим ... Зараз у моєму випадку я використовую ASP.Net MVC4, це не допомагає, оскільки часткові перегляди мають власні ViewModels, а часткові / Змістові розділи не повинні перешкоджати один одному , а через умовне візуалізацію використовувати цей підхід буде дуже важко.
бхувін

1
@bhuvin, використовуючи <! - ko stopBinding: true ->, допоможе тобі з кількома моделями перегляду та розділами часткового перегляду. Дивіться knockmeout.net/2012/05/quick-tip-skip-binding.html для отримання додаткової інформації.
Micaël Félix

285

Тепер Knockout підтримує кілька моделей прив’язки. ko.applyBindings()Метод приймає необов'язковий параметр - елемент і його нащадків , до якого буде активований зв'язування.

Наприклад:

ko.applyBindings(myViewModel, document.getElementById('someElementId'))

Це обмежує активацію елемента з ідентифікатором someElementIdта його нащадками.

Детальнішу інформацію див. У документації .


72
Якщо ви хочете скористатися селектором jQuery, вам потрібно додати, [0]щоб вказати фактичний елемент DOM (замість об’єкта jQuery) так:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles

3
Це має бути прийнятою відповіддю. Ви все ще можете використовувати головний об’єкт, як у відповіді, що приймається в даний момент, а потім прив’язувати окремі моделі перегляду до відповідних елементів на сторінці. Це дозволить заощадити на продуктивності та обмежить область, необхідну для прив’язки даних.
Кевін Хайдет

Чи можливо спілкуватися viewModels один з одним за допомогою цього підходу? тобто у мене є TaskVM і NoteVM. Завдання може мати Примітки. Тому мій TaskVM повинен мати спостерігаючий масив, а саме примітки, тип яких - TaskVM. Чи можете ви поділитися прикладом для такого випадку?
ахмет

Напевно, найкраще запитати про спілкування між віртуальними машинами у новому запитанні.
Річард Налезинський

21

Це моя відповідь після завершення дуже великого проекту з великою кількістю ViewModels в одному огляді.

Перегляд Html

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <div id="container1">
        <ul>
            <li >Container1 item</li>
            <!-- ko foreach: myItems -->
            <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <div id="container2">
        <ul>
            <li >Container2 item</li>
            <!-- ko foreach: myItems -->
                <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <script src="js/jquery-1.11.1.js"></script>
    <script src="js/knockout-3.0.0.js"></script>
    <script src="js/DataFunction.js"></script>
    <script src="js/Container1ViewModel.js"></script>
    <script src="js/Container2ViewModel.js"></script>

</body>
</html>

Для цього представлення я створюю дві моделі подання для id = container1 та id = container2 у двох окремих файлах javascript.

Container1ViewModel.js

function Container1ViewModel()
{
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("ABC");
    self.myItems.push("CDE");

} 

Container2ViewModel.js

function Container2ViewModel() {
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("XYZ");
    self.myItems.push("PQR");

}

Потім після цих 2 моделей перегляду реєструються як окремі моделі перегляду в DataFunction.js

var container1VM;
var container2VM;

$(document).ready(function() {

    if ($.isEmptyObject(container1VM)) {
        container1VM = new Container1ViewModel();
        ko.applyBindings(container1VM, document.getElementById("container1"));
    }

    if ($.isEmptyObject(container2VM)) {
        container2VM = new Container2ViewModel();
        ko.applyBindings(container2VM, document.getElementById("container2"));
    }
});

Так, ви можете додати будь-яку кількість моделей перегляду для окремих знаків. Але переконайтеся, що не створюйте окрему модель перегляду для діва всередині зареєстрованого div.


Чи можливо зробити такий вид viewmodel всередині інших, а не бути окремими елементами DOM?
UserEsp

4

Перевірте плагін MultiModels на Knockout JS - https://github.com/sergun/Knockout-MultiModels


6
Яка перевага у цьому над просто ko.applyBindings (viewModel, document.getElementById ("divName"))? Це не просто синтаксичний цукор?
Паоло дель Мундо

1
@ Paolo del Mundo Це також додає залежність від плагіна LiveQuery.
Lars Gyrup Brink Nielsen

@PaolodelMundo мета плагіну - мати можливість використовувати набір виглядів моделей декаративно
Сергій Цвездін,

1

Для цього ми використовуємо компоненти. ( http://knockoutjs.com/documentation/component-overview.html )

Наприклад, у нас є бібліотека компонентів, яку ми розробляємо: https://github.com/EDMdesigner/knobjs

Якщо ви вкапаєтеся в коді, ви побачите, що, наприклад, ми використовуємо компонент кнопки в декількох місцях.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.