How to Break knockout view model in parts with requirejs

Muhammad Raheel picture Muhammad Raheel · Jun 18, 2014 · Viewed 8.3k times · Source

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?

Answer

GôTô picture GôTô · Jun 30, 2014

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