Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting knockout view model into multiple files

My view model started getting very large so I decided to split it into multiple files. I have already tried many different approaches but nothing was working.

My view model looks like:

namespace.model = function(constructorParam) {
    var self = this;

    self.param1 = ko.observable(constructorParam.param1);
    self.param2 = ko.observable(privateFunction(constructorParam));

    self.clickEvent = function() {
        // do something with params
        // call some private funcitons
        privateFunction2(self.param2);
    };

    function privateFunction(param) {
        // do some stuff
    }

    function privateFunction2(param) {
        // do some stuff
    }
};

I need to access private functions and observable parameters across multiple files. My final model should look like this:

// file 1 
// contains constructor and param initialization + many common private helper funcitons
namespace.model = function(constructorParam) {
    var self = this;

    self.param1 = ko.observable(constructorParam.param1);
    self.param2 = ko.observable(privateFunction(constructorParam));

    function privateFunction(param) {
        // do some stuff
    }

    function privateFunction2(param) {
        // do some stuff
    }
};

// file 2
// contains event hendlers
self.clickEvent = function () {
    // i need to acces properties from namespace.model
    self.param1

    // call some private funcitons
    privateFunction2(self.param2);
};

// view model initialization
ko.applyBindings(new namespace.model(initValues));

Is it possible to achieve something like this with knockout? Thanks

like image 686
Marian Ban Avatar asked Dec 10 '12 10:12

Marian Ban


2 Answers

I would take a look at a library like RequireJS which could be used to split your viewmodel into different 'modules' which are then loaded into your main ViewModel.

There are some very simple examples of using RequireJS with Knockout on the Knockout website here.

Take a look at some really helpful posts by John Papa on building Single Page Apps here.

like image 156
kzhen Avatar answered Sep 17 '22 12:09

kzhen


Finally I've found a way how to do it here. Here is a complete example:

<div>
    Name: <input data-bind="value: name" type="text" /> <br /> 
    Surname: <input data-bind="value: surname" type="text" /><br />
    Fullname: <span data-bind="text: fullName"></span><br />
    <button data-bind="click: showName">Show Name</button>
</div>

<script>

    Function.prototype.computed = function () {
        this.isComputed = true;
        return this;
    };

    Object.prototype.makeComputeds = function () {
        for (var prop in this) {
            if (this[prop] && this[prop].isComputed) {
                this[prop] = ko.computed(this[prop], this, { deferEvaluation: true });
            }
        }
    };
    // file 1
    var namespace = namespace || {};

    namespace.model = function (params)
    {
        var self = this;

        self.name = ko.observable(params.name);
        self.surname = ko.observable(params.surname);

        self.makeComputeds();
    };

    // file 2
    (function () {
        function showFullName(fullName) {
            alert(fullName);
        }

        ko.utils.extend(namespace.model.prototype, {

            showName: function() {
                showFullName(this.fullName());
            },
            // computed observable
            fullName: function() {
              return this.name() + " " + this.surname();
            }.computed()

        });

    })();

    ko.applyBindings(new namespace.model({ name: "My Name", surname: "My Surname" }));

</script>

EDIT

There is a project called Durandal which combines RequireJS and KnockoutJS. Worth to look if you are interested in SPA architecture best practices for KnockoutJS.

like image 44
Marian Ban Avatar answered Sep 18 '22 12:09

Marian Ban