How to Break knockout view model in parts with req

2019-03-09 04:05发布

问题:

I am currently working on an application which is enlarging itself due to so much functionality. Here i am going to present some sample code to understand.

function test(){
    var self = this
    /*  Define Properties   */
    self.TaskSection = ko.observable()
    .
    .
    /*  Define Get Requrest */
    self.GetTasks = function(){

    }
    .
    .
    /*  Define Post Requrest    */
    self.PostTask  = function(){

    }
    .
    .

    /*  Define Helper Methods   */
    self.FormatDate  = function(){

    }   
    .
    .
    /*  Define Navigation Methods   */
    self.HomePage  = function(){

    }   
    .
    .
    /*  End */
}

OK. Pretty simple. You can see the sample model but it is now difficult to work with it as each section contains many functions. Lets assume more then 10 functions in each section. Now I want to manage the application using requirejs. This is what i have tried.

The Structure

app/
    js/
        /Collections/   /*  For ObservableArrays    */
        /Events/        /*  For Collections and Models  */
        /Helpers/       /*  For Collections and Models  */
        /Models/        /*  Default Properties  */

Currently what I want is now break the model in 3 to 4 parts.

  • Collection.js where I define only observableArray()
  • Events.js where I want to define server related functions
  • Helpers.js where I want to define functions to do some internal work.

How can I achieve this. This is what I have tried.

define(["knockout"],function (ko) {
    function test(){
        var self = this
        self.TaskList = ko.observanleArray()
    }
    return new test()
});

define(["knockout","TaskList"],function (ko,TaskList) {
    var events  = function() {
        var self = this
        self.AddItem = function (data) {
            TaskList.push(TaskModel)
        }
        self.RemoveItem = function (data) {
            TaskList.remove(data)
        }
    }
    return new events()
});

define(["knockout","TaskList"],function (ko,TaskList) {
    var helpers  = function() {
        var self = this
        self.SortTaskList = function (data) {
            TaskList.sort()
        }
    }
    return new helpers()
});

Here I dont know how to merge them. TaskList in events.js and helper.js is undefined. I know I need to pass TaskList as parameter but I don't want to use function way. Instead I want to use literal way to merge these two files into Tasklist.js viewmodel.

How can I do this?

回答1:

I think this is an example of what you can do (this is an example, in real life you would split into separate js files):

Define ko as a module (not so useful as it is, you could remove the reference to "knockout")

define("knockout", function () {
    return ko;
});

Define a module for the TaskList

define("TaskList", ["knockout"],function (ko) {
    function TaskList(){
        var self = this;
        self.NameInput = ko.observable("");
        self.DescInput = ko.observable("");
        self.TaskList = ko.observableArray();
    }
    return new TaskList();
});

Define a module for the Events and reference the TaskList

define("Events", ["knockout","TaskList"],function (ko, obj) {
    var events  = function() {
        var self = this;
        self.AddItem = function (data) {
            var inputData;
            if (typeof(data.Name) === 'undefined') {
                inputData = { Name: obj.NameInput(), 
                              Description:  obj.DescInput() };
            } else
                inputData = data;
            obj.TaskList.push(inputData);
        }
        self.RemoveItem = function (data) {
            obj.TaskList.remove(data);
        }
    }
    return new events();
});

Define a module for the Helpers that also references the TaskList

define("Helpers", ["knockout","TaskList"],function (ko, obj) {
    var helpers  = function() {
        var self = this;
        self.SortTaskList = function (data) {
            obj.TaskList.sort();
        }
    }
    return new helpers();
});

Define a main module that will put all modules together

define("Main", ["knockout","TaskList", "Events", "Helpers"], 
       function (ko, obj, e, h) {
    var main  = function() {
        var self = this;
        self.Tasks = obj;
        self.Events = e;
        self.Helpers = h;
    }
    return new main();
});

Finally, call the main module and try to add an Item to the TaskList through the Events module

require(["Main", "knockout"], function (main, ko) {
   main.Events.AddItem({ Name: "My first task", Description: "Start the job"});
   main.Events.AddItem({ Name:"My second task", Description:"Continue the job"});
   main.Events.AddItem({ Name: "My last task", Description: "Finish the job"});
   ko.applyBindings(main);
   console.log(main.Tasks.TaskList().length);
});

Updated Demo



回答2:

One thing to consider here is that require.js doesn't just want you to make modules within a single JavaScript file, it wants you to break the modules out into separate files to keep the modules from getting oversized. The problem you are running in to is that you don't have any way of naming your modules currently so that the others know about them. Consider this -

Tasklist.js

define(["knockout"],function (ko) {
    function test() {
        var self = this;
        self.TaskList = ko.observableArray();
    };
    return new test();
});

Events.js

define(["knockout","app/TaskList"],function (ko,TaskList) {
    var events  = function() {
        var self = this;
        self.AddItem = function (data) {
            TaskList.push(TaskModel);
        };
        self.RemoveItem = function (data) {
            TaskList.remove(data);
        };
    }
    return new events();
});

Helpers.js

define(["knockout","app/TaskList"],function (ko,TaskList) {
    var helpers = function() {
        var self = this;
        self.SortTaskList = function (data) {
            TaskList.sort();
        };
    }
    return new helpers();
});

Of course this assumes you already have a main.js or some entry point with require.js configuration set up to let require know where to find the files. If you don't have that it would look something like this -

Main.js

requirejs.config({
    baseUrl: 'lib',
    paths: {
        app: '../app'
    }
});

Which assumes you have something along the lines of this for your file structure -

(project dir)
/app/
Main.js
Events.js
TaskList.js
Helpers.js

Now when you load require.js in your html file and point to main.js as the entry point all of your modules will be loaded.