Friday, June 7, 2013

ViewModel inheritance in knockout

Problem : ViewModel inheritance in knockout.


Problem Description: Knockout view models aren't as simple as a simple object that can be easily extended, specially when your view model can contain computed observable which should be executed immediately. If you are already familiar with various ways of inheritance in javascript using various frameworks or just plain javascript methods, then you probably must have already figured out why the immediate executing computed observable poses a major blockade in using them.


Solution

                var Person = function () {
                var self = this;
                self.Name = 'Base';
                self.KoName = ko.observable('Person Name');
                self.FullName = ko.computed(function () {
                    //alert('into koFullName');
                    //alert(self.Name);
                    
                    return self.KoName() + ' Full Name in base';
                });
                self.getName = function () {
                    return self.KoName();
                };
            };

            var Employee = function () {
                var self = this;
                Person.apply(self, arguments); //arguments if any
               
                Extend(self);

                self.KoName('Employee');
                
                self.JoinDate = ko.observable('01/01/2009');
               
                self.FullName = ko.computed(function () {
                    var baseName = self.base.FullName();
                    return baseName+ '  Employeeee Overridden: ' + self.KoName() + ' Full Name';
                });
                self.getName = function () {
                    return 'Employeeee : ' + self.KoName();
                };
            };

            var Client = function () {
                var self = this;
                Person.apply(self, arguments); //arguments if any
                Extend(self);
                self.KoName('Client');
                self.FullName = ko.computed(function () {

                    return 'Client Overridden: ' + self.KoName() + ' Full Name';
                });
                self.getName = function () {
                    return 'Client : ' + self.KoName();
                };

            };

            function Extend(self) {
                var base = { };
                base = { };
                for (propName in self) {
                    var propValue = self[propName];
                    base[propName] = propValue;

                }

                self.base = base;
                return self;
            }

        var employeeVm = new Employee();

        alert(employeeVm.FullName()); //this alerts  "Employee Full Name in base  Employeeee Overridden: Employee Full Name"
        var clientVm = new Client(); 
        alert(clientVm.FullName()); //this alerts "Client Overridden: Client Full Name"

As you can see here Person is the base ViewModel which is extended by Employee and Client. Each of these derived classes invokes the Person function to apply all the properties and functions from Person to itself. Then they call Extend function which basically is responsible to create base property in the viewmodel with the existing properties and functions. Remember that you must call this function exactly after invoking Person function and before adding or overriding the existing functions from base class. This is required to due to the way Extend function creates a new base property and copies the existing properties and functions to it. This Extend function  lets you access your base class using base keyword and still call it later if you want.
If you have a better solution to this then please let me know. I'd really really appreciate that.