View:
Knockout.js supports binding of model data directly to DOM elements, so the first thing that we will look at is one of the templates that are used for the views. Here's what this example uses for the contacts list view template:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="nine.columns.centered"> | |
<p class="row"> | |
<a href="#/create" class="small button radius">Create Contact</a> | |
</p> | |
<div class="row"> | |
<div class="five columns header">FirstName</div> | |
<div class="five columns header">LastName</div> | |
<div class="two columns header">Phone</div> | |
</div> | |
<div data-bind="foreach: contacts"> | |
<div class="row"> | |
<div class="five columns" data-bind="text: firstName"/> | |
<div class="five columns" data-bind="text: lastName"/> | |
<div class="two columns" data-bind="text: phone"/> | |
</div> | |
</div> | |
</div> |
ViewModel:
The example defines a single ViewModel that is used for both of the available views. The code, which is fairly similar to that described at http://knockoutjs.com/examples/contactsEditor.html, is shown below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function ( viewModel, $ ) { | |
viewModel.ContactsViewModel = function ( contacts ) { | |
var self = this; | |
self.contacts = ko.observableArray( ko.utils.arrayMap( contacts, function ( contact ) { | |
return { firstName: contact.firstName, lastName: contact.lastName, phone: contact.phone }; | |
})); | |
self.addContact = function () { | |
var data = appFsMvc.utility.serializeObject( $("#contactForm") ); | |
$.ajax({ | |
url: "/api/Contacts", | |
data: JSON.stringify( data ), | |
type: "POST", | |
dataType: "json", | |
contentType: "application/json" | |
}) | |
.done(function () { | |
toastr.success( "You have successfully created a new contact!", "Success!" ); | |
self.contacts.push( data ); | |
window.location.href = "#/"; | |
}) | |
.fail(function () { | |
toastr.error( "There was an error creating your new contact", "<sad face>" ); | |
}); | |
}; | |
}; | |
})( appFsMvc.ViewModels = appFsMvc.ViewModels || {}, jQuery ); |
Another thing to notice is the routing mechanism used in this example. Since Knockout.js doesn't provide built in URL routing, I've used Sammy.js to accommodate the need. Here's what the router looks like:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function ($) { | |
appFsMvc.App = function( contactsViewModel ) { | |
return $.sammy( "#content", function () { | |
var self = this; | |
this.use( Sammy.Cache ); | |
this.contactViewModel = contactsViewModel; | |
this.renderTemplate = function ( html ) { | |
self.$element().html( html ); | |
ko.applyBindings( self.contactViewModel ); | |
}; | |
// display all contacts | |
this.get( "#/", function() { | |
this.render("/Templates/contactDetail.htm", {}, function ( html ) { | |
self.renderTemplate( html ); | |
}); | |
}); | |
// display the create contacts view | |
this.get( "#/create", function() { | |
this.render("/Templates/contactCreate.htm", {}, function ( html ) { | |
self.renderTemplate( html ); | |
}); | |
}); | |
}); | |
}; | |
$(function () { | |
$.getJSON( "/api/contacts", function ( data ) { | |
var viewModel = new appFsMvc.ViewModels.ContactsViewModel( data ); | |
appFsMvc.App( viewModel ).run( "#/" ); | |
}); | |
}); | |
})(jQuery); |
Lastly, we'll get a quick look at the API Controller that is written in F#. Here's the code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System.Web.Http | |
open FsWeb.Models | |
type ContactsController() = | |
inherit ApiController() | |
let contacts = seq { yield Contact(FirstName = "John", LastName = "Doe", Phone = "123-123-1233") | |
yield Contact(FirstName = "Jane", LastName = "Doe", Phone = "123-111-9876") } | |
member x.Get() = | |
contacts | |
member x.Post ([<FromBody>] contact:Contact) = | |
contacts |> Seq.append [ contact ] |