Split viewmodel into multiple viewmodels in knockout.js

泪湿孤枕 提交于 2021-01-08 02:38:54

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!