Knockout is a standalone JavaScript implementation of the Model-View-ViewModel pattern with templates.For more info http://en.wikipedia.org/wiki/KnockoutJS
Introduction
This article shows how to add Knockout bindings to the Admin view which we have created in
Part 4Knockout is a standalone JavaScript implementation of the Model-View-ViewModel pattern with templates.
Model is a set of classes representing the data coming from the services or the database.
View is the code corresponding to the visual representation of the data the way it is seen and interacted with by the user.
ViewModel serves as the glue between the View and the Model. It wraps the data from the Model and makes it friendly for being presented and modified by the view.
Lets start by creating a View-Model first
Add the following implementation to Admin view
@model BooksStore.Models.Book
@{
ViewBag.Title = "Admin";
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.0.0.js")"></script>
<script type="text/javascript">
function BooksViewModel() {
var self = this;
self.Books = ko.observableArray();
var baseUri = '@ViewBag.ApiUrl';
self.create = function (formElement) {
// If valid, post the serialized form data to the web api
$(formElement).validate();
if ($(formElement).valid()) {
$.post(baseUri, $(formElement).serialize(), null, "json")
.done(function (o) { self.Books.push(o); });
}
}
self.update = function (product) {
$.ajax({ type: "PUT", url: baseUri + '/' + Book.Id, data: Book });
}
self.remove = function (Book) {
// First remove from the server, then from the UI
$.ajax({ type: "DELETE", url: baseUri + '/' + Book.Id })
.done(function () { self.Books.remove(Book); });
}
$.getJSON(baseUri, self.Books);
}
$(document).ready(function () {
ko.applyBindings(new BooksViewModel());
})
</script>
}
<h2>Admin</h2>
<div class="content">
<div class="float-left">
<ul id="update-products" data-bind="foreach: books">
@*The li element occurs within the scope of the foreach binding. That means Knockout will render the element once for each product in the products array. *@
<li>
<div>
<div class="item">Book ID</div> <span data-bind="text: $data.Id"></span>
</div>
<div>
<div class="item">Name</div>
<input type="text" data-bind="value: $data.Name" />
</div>
<div>
<div class="item">Deal Price ($)</div>
<input type="text" data-bind="value: $data.DealPrice" />
</div>
<div>
<div class="item">Selling Price ($)</div>
<input type="text" data-bind="value: $data.SellingPrice" />
</div>
<div>
<input type="button" value="Update" data-bind="click: $root.update" />
<input type="button" value="Delete Item" data-bind="click: $root.remove" />
</div>
</li>
</ul>
</div>
<div class="float-right">
<h2>Add New Book</h2>
@*This binding calls the create function on the view-model to create a new product.*@
<form id="addProduct" data-bind="submit: create">
@Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
@Html.EditorForModel()
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
</div>
</div>
Now lets add the Authorization for Admin
In Solution Explorer, expand the Filters folder and open the file named InitializeSimpleMembershipAttribute.cs. Locate the SimpleMembershipInitializer constructor. After the call to WebSecurity.InitializeDatabaseConnection, add the following code
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Threading;
using System.Web.Mvc;
using WebMatrix.WebData;
using BooksStore.Models;
using System.Web.Security;
namespace BooksStore.Filters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
const string adminRole = "Administrator";
const string adminName = "Administrator";
if (!Roles.RoleExists(adminRole))
{
Roles.CreateRole(adminRole);
}
if (!WebSecurity.UserExists(adminName))
{
WebSecurity.CreateUserAndAccount(adminName, "password");
Roles.AddUserToRole(adminName, adminRole);
}
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
}
}
Now add the Following attribute to the Admin method and to the controller
[Authorize(Roles = "Administrator")]
Now only administrators can view the Admin page. Also, if you send an HTTP request to the Admin controller, the request must contain an authentication cookie.