将viewmodel拆分为knockout.js中的多个viewmodel

时间:2014-08-11 22:38:24

标签: knockout.js

在Knockout.js中,当你的ViewModel变得非常大时,有不同的方法可以分成多个ViewModel,拥有一些较小的ViewModel而不是一个大的ViewModel总是一个好主意。我使用以下方法,并不确定是否有任何其他更好的方法来做到这一点。注意我使用require.js来定义我的ViewModel,但为了简单起见,我不在下面的示例中包含该代码。在下面的例子中,假设我在一个屏幕上工作,你可以编辑学生注册的课程。最初我在StudentViewModel中有所有与课程相关的功能(如添加/编辑/删除课程)。但我决定将它们移到CourseViewModel,然后在StudentViewModel中引用CourseViewModel。请注意,在创建CourseViewModel时,我传递了对student.courses可观察数组的引用。这是一个为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 个答案:

答案 0 :(得分:2)

我这样做的方法是维护主视图模型(big fat viewmodel)并在其中定义子视图模型。

e.g。

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

您可以使用主视图模型应用绑定,并随时随地使用子视图模型实例。

我尝试了不同的技术但显然失败了。这是我从KnockoutJS转移到DurandalJS的唯一原因。模块化编程非常有效,无需担心多个视图模型。

多个不同视图模型之间的另一种通信方法是在代码中引入 Pub-Sub 。有一个非常好的插件由Ryan Niemeyer称为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());