2

I have a project which uses the revealing Module pattern and prototyping. This has been great for helping me manage large amounts of Javascript code using Knockout JS. This has been straight forward for standard observables and actions etc. However when I have come to create a computed observable I can't seem to get it working.

I have read this article: Difference between knockout View Models declared as object literals vs functions

Which seems to describe exactly what I want as I am using an object literal. However I can't seem to implement it correctly.

Here is the HTML:

<div data-bind="with: MyForm">
    <p>First Name: <span data-bind="text: formValues.FirstName"></span></p> 
    <p>Last Name: <span data-bind="text: formValues.LastName"></span></p>
    <p>Full Name: <span data-bind="text: formValues.FullName"></span></p>   
</div>

Here is the Javascript:

window.Test = window.Test || {};

Test.Main = function () {
    this.viewModel = {};
    this.setupViewModel();

    return {
        viewModel: this.viewModel

    };
};
Test.Main.prototype.setupViewModel = function () {
    var viewModel = function () {
        var vm = this;

        this.MyForm = {
            formValues: {
                FirstName: ko.observable("Joe"),
                LastName: ko.observable("Bloggs")
            }
         }
    };

    /*
    viewModel.MyForm.formValues.FullName = ko.computed(function() {
        return this.FirstName() + " " + this.LastName();
    }, vieModel.MyForm.formValues);
    */
    this.viewModel = new viewModel();
    ko.applyBindings(this.viewModel);

    return this;
}

var mainApplication = new Test.Main();

I have created a simple JsFiddle below to illustrate this code: http://jsfiddle.net/dontbesorry80/2Ltb790z/

I have commented out what I thought would be the solution as it doesn't work. Any help in tweaking this jsFiddle to work (correctly display Full Name) would be greatly appreciated.

Community
  • 1
  • 1
dontbesorry80
  • 567
  • 1
  • 6
  • 12

1 Answers1

1

This piece of code seems to be working.

Test.Main.prototype.setupViewModel = function () {
    var viewModel = function () {
        var vm = this;

        this.MyForm = {
            formValues: {
                FirstName: ko.observable("Joe"),
                LastName: ko.observable("Bloggs")
            }
         }
    };

    this.viewModel = new viewModel();

    this.viewModel.MyForm.formValues.FullName = ko.computed(function() {
        return this.FirstName() + " " + this.LastName();
    }, this.viewModel.MyForm.formValues);

    ko.applyBindings(this.viewModel);

    return this;
}

Instead of attaching FullName property to constructor function you have to create the viewModel first, and then attach computed variable to it.

Usage of this is crucial for getting proper scoping inside computed function.

In the referenced SO answer you can see exactly same scenario:

var viewModel = {
   first: ko.observable("Bob"),
   last: ko.observable("Smith"),
};

viewModel.full = ko.computed(function() {
   return this.first() + " " + this.last();
}, viewModel);

First - viewModel is created with first & last properties, then - property full is added to the viewModel object.

Hope this helps.

Slawek
  • 2,592
  • 1
  • 24
  • 26