Разделить режим просмотра на несколько режимов просмотра в knockout.js

В Knockout.js, когда ваша ViewModel становится довольно большой, есть разные способы разделить на несколько ViewModels, и всегда полезно иметь несколько меньших ViewModels вместо одного большого. Я использую следующий подход и не уверен, есть ли другой лучший способ сделать это. Примечание. Я использую require.js для определения моих ViewModels, но я не включаю этот код в приведенный ниже пример ради простоты. В следующем примере скажем, что я работаю на экране, где вы можете редактировать курсы, в которых учащийся участвовал. Вначале у меня были все связанные с курсом функциональные возможности (такие как добавление/редактирование/удаление курсов) в StudentViewModel. Но я решил перенести их в CourseViewModel, а затем ссылку на CourseViewModel в StudentViewModel. Обратите внимание, что при создании CourseViewModel я передаю ссылку на наблюдаемый массив student.courses. Это хороший способ иметь небольшие viewmodels для View или есть ли лучший способ сделать это?

function Course(data) {
 data = data || {};
 this.id = ko.observable(data.id);
 this.name = ko.observable(data.name); 
}

function Student(data) {
 data = data || {};
 this.id = ko.observable(data.id);
 this.firstName = ko.observable(data.firstName); 

 this.courses = ko.observableArray($.map(data.courses, function (item) { return new Course(item); }));
}

function CourseViewModel(studentid, courses) {
 var self = this;
 // please note below is a reference to courses observable function 
 self.courses = courses;

 this.addCourse = this.addCourse.bind(this);
 this.editCourse = this.editCourse.bind(this);
 this.removeCourse = this.removeCourse.bind(this);
}

ko.utils.extend(CourseViewModel.prototype, {
 addCourse: function(course) {
 var self = this;
 self.courses.push(course);
 },
 editCourse: function(course) {
 var self = this;
 // find the course and update it 
 },
 removeCourse: function(course) {
 var self = this;
 self.courses.remove(course);
 }
});

// main ViewModel which will be used for binding 
function StudentViewModel(id) {
 var self = this;
 self.id = ko.observable(id);
 self.student = ko.observable();
 self.courseViewModel = ko.observable();

 // retrieve student object from server 
 (function() {
 var data = dataService.getStudent(id);
 self.student(new Student(data));
 // please note below I am passing a reference to courses observable function 
 self.courseViewModel(new CourseViewModel(id, student.courses));
 )();
}

// binding 
ko.applyBindings(new StudentViewModel(5));
1 ответ

Мой способ сделать это - сохранить master viewmodel (большой толстый viewmodel) и определить sub viewmodels внутри него..

например

var MasterVM = {
 subVM1 : SubViewModel1(),
 subVM2: SubViewModel2()
};

Вы можете применять привязки с помощью master viewmodel и использовать экземпляры sub viewmodel всякий раз, когда и где вам нужно.

Я пробовал разные методы, но они, похоже, не сработали. Это единственная причина, по которой я перешел в DurandalJS только от KnockoutJS. Модульное программирование работает так хорошо, не беспокоясь о нескольких режимах просмотра.

Другим способом связи между несколькими различными режимами просмотра является введение Pub-Sub в ваш код. Для этого очень хороший плагин Райана Нимейера под названием KO Postbox (https://github.com/rniemeyer/knockout-postbox)

Я нашел полезными в разных сценариях. Хотя я бы пошел с первым подходом.

Совместное использование моделей между несколькими режимами просмотра:

//Shared Models for both the ViewModels
var profileModel = function(vm){
 var self = this;
 self.first = ko.observable("Bob");
 self.last = ko.observable("Smith");
 self.vm = ko.observable(vm);
};

var officeModel = function(vm){
 var self = this;
 self.header = ko.observable("Administration");
 self.vm = ko.observable(vm);
};


var viewModel1 = function(){
 var self = this;
 self.profileModel = new profileModel("Called from viewModel1");
 self.officeModel = new officeModel("office model Called from viewModel1");
};

var viewModel2 = function(){
 var self = this;
 self.profileModel = new profileModel("Called from viewModel2");
 self.officeModel = new officeModel("office model Called from viewModel2");
};

//the overall view model
var viewModel = function(){
 var self = this;
 self.profile = new profileModel(),
 self.office = new officeModel(),
 self.viewModel1 = new viewModel1(),
 self.viewModel2 = new viewModel2() 
};

ko.applyBindings(new viewModel());

licensed under cc by-sa 3.0 with attribution.