Rohan Büchner
Rohan Büchner

Reputation: 5403

Extend javascript generic view model. (Knockout)

Context: I'm quite new to what I like to think of as, "serious javascript/jquery coding", my previous attempts would probably be considered treason :P.

My question: I've noticed a pattern in some of our client side view models and would like to consolidate some of them into a single .js file.

Everything seems to be working for most scenarios, except for the screens where i'd need to create an additional set of observables, that don't necessarily map to my JS object returned from the server.

 var AdminPages = AdminPages || {};  

 AdminPages.SimplePageVM: function (options) {

            var self = this;

            self.hasChanges = function () {};        
            self.isValid = function () {};

            // CRUD Actions
            self.get = function () {
                $.ajax({
                   url: options.getUrl,
                   dataType: 'json',
                   data: !$.isEmptyObject(options.someId) ? { someId: options.someId} : null,
                   success: function (result) {            
                       self.observables = ko.mapping.fromJS(result);
                       ko.editable(self.observables);
                       ko.applyBindings(self, $('form')[0]);
                   },
                   error: function (result) {}
                });
            };
            self.save = function () {};
            self.edit = function () {};
            self.cancel = function () {};

            // Initialise the viewmodel on create
            self.get();                      
  }

Id like to add the following to the view model. I'm thinking i need to create an entirely new object, (as self.observables only get created on the success of the get function), and then add my new object and its properties on item bind.

what id like to add:

 self.newObject.IsPercentageEvaluation = 
            ko.computed(function () {
                var isPercentage = self.observables.IsPercentageBased() == 'true';    
                  if (isPercentage) {                        
                      self.observables.BalancePercentage('40');
                  } else {
                      self.observables.BalancePercentage('');
                  }
                return isPercentage;
            });

And to call it all:

$(function () {
        var obj = {
             IsPercentageEvaluation = ko.computed(...);
        };

        AdminPages.SimplePageVM({
            getUrl: '@Url.Action("Get", "SomeController")',
            editUrl: '@Url.Action("Update", "SomeController")',
            organisationId: '@ViewBag.OrganisationID',
            newObject: obj
        });

} ($));

I'd just like to confirm if this is the correct way of approaching this situation? Or if there is a better way, eg making use of a certain java script pattern, or something to that extent?

Upvotes: 1

Views: 1220

Answers (1)

photo_tom
photo_tom

Reputation: 7342

I worked on a large project last spring and we tried followed a pattern similar to what you are using.

There are issues that need to be considered-

  • Inside your ajax.success function, we routinely needed ability to modify the returned view mode. For example, add ko.computed's. I would suggest that you add an overrideable function for this that you call before the ko.applybindings.
  • You need ability to handle situation where your application has a problem returning the data. For example, database is down or a web service is offline. You need to have a graceful way of handling these situations. We did this by extending our view model so that these conditions were returned on separate properties.
  • If you are returning row data to be displayed in table data, you may have to modify your ajax.success function to handle an array of data. We always seemed to run into issues with this.

I do like your view model. It is a flexible and extensible piece of code. I will be borrowing it on our next project.

Upvotes: 1

Related Questions