问题
In Knockout.js, when your ViewModel gets quite big, there are different ways to split into multiple ViewModels and it is always a good idea to have a number of smaller ViewModels instead of having one big one. I am using the following approach and not sure if there is any other better way of doing this. Note I am using require.js to define my ViewModels but I am not including that code in the example below for the sake of simplicity. In the following example let's say that I am working on a screen where you can edit courses that a student is enrolled in. Initially I had all courses related functionality (such as add/edit/remove courses) in the StudentViewModel. But I decided to move them to CourseViewModel and then have a reference to the CourseViewModel in StudentViewModel. Please note when creating CourseViewModel, I am passing a reference to student.courses observable array. Is this a good way to have small viewmodels for a View or is there any better way of doing this?
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:
My way of doing it is maintain master viewmodel (big fat viewmodel) and define sub viewmodels inside it..
e.g.
var MasterVM = {
subVM1 : SubViewModel1(),
subVM2: SubViewModel2()
};
You can apply bindings with master viewmodel and use sub viewmodel instances whenever and wherever you need.
I tried different techniques but they failed apparently. That's the only reason I moved to DurandalJS from KnockoutJS only. Modular programming works so well without worrying about multiple viewmodels.
Another method of communication between multiple distinct viewmodels is to introduce Pub-Sub in your code. There is a very very good plugin for that by Ryan Niemeyer called KO Postbox (https://github.com/rniemeyer/knockout-postbox)
I found both useful in different scenarios. I would go with first approach though.
Sharing models between multiple viewmodels :
//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());
来源:https://stackoverflow.com/questions/25253547/split-viewmodel-into-multiple-viewmodels-in-knockout-js