Recently I have been reading a number of articles and watching training videos from Pluralsight about Javascript and KnockoutJs. After reading the “Hello world, with Knockout JS and ASP.NET MVC 4!” by Amar Nityananda I wanted to see if I could apply the techniques of what I’d learnt to a relatively simple example. After reading the original article I couldn’t help but think “this Js could be better structured, I think I could do this” … so this is what I came up with.
To get an understanding of the problem please read the original article first.
I’ve only concentrated on the client side JavaScript as this was the challenge …
// setup the namespace
var my = my || {};
$(function () {
my.Customer = function () {
var self = this;
self.id = ko.observable();
self.displayName = ko.observable();
self.age = ko.observable();
self.comments = ko.observable();
};
my.vm = function () {
var
// the storing array
customers = ko.observableArray([]),
// the current editing customer
customer = ko.observable(new my.Customer()),
// visible flag
hasCustomers = ko.observable(false),
// get the customers from the server
getCustomers = function() {
// clear out the client side and reset the visibility
this.customers([]);
hasCustomers(false);
// get the customers from the server
$.getJSON("/api/customer/", function(data) {
$.each(data, function(key, val) {
var item = new my.Customer()
.id(val.id)
.displayName(val.displayName)
.age(val.age)
.comments(val.comments);
customers.push(item);
});
hasCustomers(customers().length > 0);
});
},
// add the customer from the entry boxes
addCustomer = function() {
$.ajax({
url: "/api/customer/",
type: 'post',
data: ko.toJSON(customer()),
contentType: 'application/json',
success: function (result) {
// add it to the client side listing, this will add the id to the record;
// not great for multi user systems as one client may miss an updated record
// from another user
customers.push(result);
customer(new my.Customer());
}
});
};
return {
customers: customers,
customer: customer,
getCustomers: getCustomers,
addCustomer: addCustomer,
hasCustomers: hasCustomers
};
} ();
ko.applyBindings(my.vm);
});
The main points I was trying to cover are:
- Code organisation through namespaces – I don’t want any potential naming conflicts. This isn’t a big issue in a small application but once they start growing it’s good to try and avoid putting definitions into the global namespace.
- Expose the details of the view model through the Revealing Module pattern – this keeps details clean as well as improved data binding clarity.
I haven’t gone into too much detail as the rest of the project infrastructure is very similar to the original article and can be found there. I wanted to post this as an example of how to make the Js structured.
Happy to discuss further; contactable in the comments or via twitter.
Updated Edit
After a comment from ranga I have read the link posted and update the code (see below). I have moved the view model and the Customer declaration outside of the on document ready event. I have also change hasCustomers to be a computed value. The interesting read about the performance hit about the events firing on array manipulation was really interesting – worth a read.
// setup the namespace
var my = my || {};
my.Customer = function () {
var self = this;
self.id = ko.observable();
self.displayName = ko.observable();
self.age = ko.observable();
self.comments = ko.observable();
};
my.vm = function () {
var
// the storing array
customers = ko.observableArray([]),
// the current editing customer
customer = ko.observable(new my.Customer()),
// visible flag
hasCustomers = ko.computed(function () {
return customers().length > 0;
}),
// get the customers from the server
getCustomers = function () {
// clear out the client side
this.customers([]);
// get the customers from the server
$.getJSON("/api/customer/", function (data) {
var items = new Array();
$.each(data, function (key, val) {
var item = new my.Customer()
.id(val.id)
.displayName(val.displayName)
.age(val.age)
.comments(val.comments);
items.push(item);
});
customers(items);
});
},
// add the customer from the entry boxes
addCustomer = function () {
$.ajax({
url: "/api/customer/",
type: 'post',
data: ko.toJSON(customer()),
contentType: 'application/json',
success: function (result) {
// add it to the client side listing, this will add the id to the record;
// not great for multi user systems as one client may miss an updated record
// from another user
customers.push(result);
customer(new my.Customer());
}
});
};
return {
customers: customers,
customer: customer,
getCustomers: getCustomers,
addCustomer: addCustomer,
hasCustomers: hasCustomers
};
} ();
$(function () {
ko.applyBindings(my.vm);
});
Keep the feedback coming, I’m always up for learning and improving.