My first real-world single-page app (SPA) was written using the Knockout library, and it opened my eyes in terms of how powerful JavaScript has become. It appealed to me due to my familiarity with the Model-View-ViewModel pattern, and it was compatible with the jQuery controls used in the project.
As a C# developer, there were a few conventions I had to learn. Both JavaScript and C# are C-like languages, and I’ve used various versions of JavaScript for several years. But in my limited experience, I hadn’t encountered a technique used prevalently in Knockout.
The Technique
A ViewModel contains properties that must notify subscribers on change. In C#, one typically makes a ViewModel implementing INotifyPropertyChanged, then each observable property calls a method to raise the PropertyChanged event. Since properties aren’t necessarily supported in a browser’s JavaScript interpreter, knockout uses a different pattern. Here’s an example ViewModel adapted from the Knockout documentation:
varviewModel = {
name: ko.observable('Bob'),
age: ko.observable(123)
};
Since JavaScript is a dynamic language, you should try to change the value of one of the properties using an assignment operator. Each property is actually a function, and it can be changed by passing the new value in as an argument. This example will change the name to ‘Chris’.
viewModel.name(‘Chris’);
If you’re a C# developer, you may be wondering how to retrieve the value. With no arguments, the function returns the stored value.
viewModel.name();
This works exactly the same as a variable. In effect, the technique used by Knockout to create observables allows for variables with getters and setters, which I find rather fascinating.
Now in C#
I first attempted to implement this same technique in C# by implementing conversion operators. This works to a degree, but it doesn’t feel quite the same. The JavaScript variable is a function that holds a value and can change it. How can I implement that?
The function I want can take one or zero arguments. There’s one way to achieve that, but it means allowing any number of arguments. Here’s the delegate type I came up with.
publicdelegate T Observable(params T[] args);
I usually only encounter the params keyword in a method declaration, but it works in a delegate as well. If you want to be truer to the JavaScript version, you could use a non-generic version. In practice, this delegate will take one or zero arguments, so the generic constraint is appropriate.
You can view the ko.observable function as a static factory method that puts together the necessary pieces. In this case, I need it to create the Observable delegate using a closure to alternate execution paths. I’m going to violate typical C# naming conventions for illustration purposes.
publicstaticclassko
{
publicstaticObservable observable(T initialValue)
{
T value = initialValue;
return args =>
{
if (args != null&& args.Length > 0)
{
value = args[0];
// notify subscribers
}
return value;
};
}
}
The observable method stores the initial value in variable and returns an Observable using a lambda statement. The statement captures the outer variable, setting it if args is neither null nor empty. It then returns the value.
Here’s a program to prove it works.
classProgram
{
staticvoid Main(string[] args)
{
var name = ko.observable("Bob");
Debug.Assert(name() == "Bob");
name("Chris");
Debug.Assert(name() == "Chris");
}
}
Should I Use This
C# is an object-oriented language, and although recent versions borrow from other paradigms, constructs already exist for scenarios where this is useful. However, I can’t predict every situation one might encounter when creating an application or framework, and this is another tool in your belt. At worst, it makes a great party trick!