This project is read-only.
  1. Create a new MVC 4 Web Application
  2. Choose the Web API template
  3. Add nuget "knockoutspa" package

In Models Folder, Add Product Class:

    public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }

In Models Folder, Add ProductContext Class:

    public class ProductContext
    {
        static IList<Product> productlist = CreateProductList();

        static IList<Product> CreateProductList()
        {
            return new List<Product>()
            {
                new Product()
                {
                    ID = 1,
                    Name = "Mountain Bike",
                    Price = 1995.99M
                },
                new Product()
                {
                    ID = 2,
                    Name = "Road Bike",
                    Price = 1549.95M
                },
                new Product()
                {
                    ID = 3,
                    Name = "Helmet",
                    Price = 29.95M
                },
                new Product()
                {
                    ID = 4,
                    Name = "Shorts",
                    Price = 39.95M
                }
            };
        }

        public IList<Product> Products
        {
            get
            {
                return productlist;
            }
        }
    }

Update Values WebApi Controller:

    public class ValuesController : ApiController
    {
        ProductContext context;

        public ValuesController()
        {
            context = new ProductContext();
        }

        // This is Primary Get (using GET)
        public HttpResponseMessage<IQueryable<Product>> GetProducts()
        {
            var query = context.Products.AsQueryable<Product>();
            return new HttpResponseMessage<IQueryable<Product>>(query);
        }

        // This is Single Get (using GET)
        public HttpResponseMessage<Product> GetProduct(int id)
        {
            var prod = context.Products.Where(p => p.ID == id).FirstOrDefault();

            if (prod == null)
                return new HttpResponseMessage<Product>(HttpStatusCode.NotFound);

            return new HttpResponseMessage<Product>(prod, HttpStatusCode.OK);
        }

        // This is Delete (using DELETE)
        public HttpResponseMessage DeleteProduct(int id)
        {
            var prod = context.Products.Where(p => p.ID == id).FirstOrDefault();

            if (prod == null)
                return new HttpResponseMessage(HttpStatusCode.NotFound);

            context.Products.Remove(prod);

            return new HttpResponseMessage(HttpStatusCode.OK);
        }

        // This is Add (using POST)
        public HttpResponseMessage<Product> PostProduct(Product add)
        {
            add.ID = context.Products.Max(p => p.ID) + 1;
            context.Products.Add(add);
            return new HttpResponseMessage<Product>(add, HttpStatusCode.Created);
        }

        // This is Update (using PUT)
        public HttpResponseMessage<Product> PutProduct(int id, Product update)
        {
            var prod = context.Products.Where(p => p.ID == id).FirstOrDefault();

            if (prod == null)
                return new HttpResponseMessage<Product>(HttpStatusCode.NotFound);

            prod.ID = update.ID;
            prod.Name = update.Name;
            prod.Price = update.Price;

            return new HttpResponseMessage<Product>(prod, HttpStatusCode.OK);
        }
    }

Update _references.js with correct references: 

/// <reference path="jquery-1.6.4.js" />
/// <reference path="jquery-ui-1.8.11.js" />
/// <reference path="jquery.validate.js" />
/// <reference path="knockout.debug.js" />
/// <reference path="modernizr-2.0.6-development-only.js" />
/// <reference path="spa.js" />

 Add appjs folder and productsview.js file, which will be the real-time client app:

// Create a Namespace
var prodapp = prodapp || {};

prodapp.viewModel = function () {
    var self = this;

    // The boolean here determines if we are buffering changes (can be overridden on each dataSet)
    self.data = new spa.dataContext(false);

    // The boolean here can override the default for the context
    self.data.AddSet("Values", "ID");

    // Create a View from the DataSet we just created
    self.view = self.data["Values"].CreateView();

    // Somewhere to hold the item we have Selected
    self.selectedItem = ko.observable();

    // function to Add an add function with default values
    self.addItem = function () {
        var newItem = new spa.dataEntity({
            ID: 0,
            Name: "New-Item-Name",
            Price: 0
        });
        self.view.AddItem(newItem);
        self.selectedItem(newItem);
    };

    // function to Delete an item in the view
    self.deleteItem = function (item) {
        self.view.DeleteItem(item);
        if (item == self.selectedItem())
            self.selectedItem(null);
    };

    // function to Refresh our View
    self.refresh = function () {
        self.view.Refresh(true);
    };

    // Start a refresh immeidately on load
    self.view.Refresh(true);

    // Public Return Items
    return {
        Items: self.view.ViewItems,
        SelectedItem: self.selectedItem,
        Refresh: self.refresh,
        AddItem: self.addItem,
        Delete: self.deleteItem,
    }
};

$(document).ready(function () {
    // Bind Once the page is loaded
    ko.applyBindings(new prodapp.viewModel());
});

Now Update the /Home/Index.cshtml view as follows to create the bindings:

@{
    ViewBag.Title = "Products SPA Demo";
}
<script type="text/javascript" src="~/Scripts/knockout.js"></script>
<script type="text/javascript" src="~/Scripts/knockout.mapping-latest.js"></script>
<script type="text/javascript" src="~/Scripts/spa.min.js"></script>
<script type="text/javascript" src="~/appjs/productsview.js"></script>
<input type="button" value="Add" data-bind="click:AddItem" />
<input type="button" value="Refresh" data-bind="click:Refresh" />
<div style="clear: both;">&nbsp;</div>
<section>
    <ul data-bind="foreach: Items" class="prodlist">
        <li data-bind="click:$root.SelectedItem"><span data-bind="text:Entity.Name"></span> ($<span data-bind="text:Entity.Price"></span>)
        </li>
    </ul>
</section>
<section data-bind="with:SelectedItem, visible: SelectedItem">
    <h1></h1>
    <ul class="prodview">
        <li>
            <label>Delete This Item</label>
            <input type="button" value="Delete" data-bind="click:$root.Delete" />
        </li>
        <li>
            <label class="prodview-label" for="state">Current State</label>
            <input class="prodview-input" disabled id="state" data-bind="value:EntityState" />
        </li>
        <li>
            <label class="prodview-label" for="id">ID</label>
            <input class="prodview-input" disabled id="id" data-bind="value:Entity.ID" />

        </li>
        <li>
            <label class="prodview-label" for="name">Name</label>
            <input class="prodview-input" id="name" data-bind="value:Entity.Name" />
        </li>
        <li>
            <label class="prodview-label" for="price">Price</label>
            <input class="prodview-input" id="price" data-bind="value:Entity.Price" />
        </li>
    </ul>
</section>

 

Last edited May 1, 2012 at 10:19 PM by rposener, version 4

Comments

chepalle Feb 1, 2013 at 2:04 PM 
Updated controller:

public class ValuesController : ApiController
{
ProductContext context;

public ValuesController()
{
context = new ProductContext();
}

// This is Primary Get (using GET)
public IQueryable<Product> GetProducts()
{
var query = context.Products.AsQueryable<Product>();
return query;
}

// This is Single Get (using GET)
public Product GetProduct(int id)
{
var prod = context.Products.Where(p => p.ID == id).FirstOrDefault();

if (prod == null)
throw new HttpResponseException(HttpStatusCode.NotFound);

return prod;
}

// This is Delete (using DELETE)
public HttpResponseMessage DeleteProduct(int id)
{
var prod = context.Products.Where(p => p.ID == id).FirstOrDefault();

if (prod == null)
return new HttpResponseMessage(HttpStatusCode.NotFound);

context.Products.Remove(prod);

return new HttpResponseMessage(HttpStatusCode.OK);
}

// This is Add (using POST)
public HttpResponseMessage PostProduct(Product add)
{
add.ID = context.Products.Max(p => p.ID) + 1;
context.Products.Add(add);
return Request.CreateResponse<Product>(HttpStatusCode.Created,add);
}

// This is Update (using PUT)
public HttpResponseMessage PutProduct(int id, Product update)
{
var prod = context.Products.Where(p => p.ID == id).FirstOrDefault();

if (prod == null)
throw new HttpResponseException(HttpStatusCode.NotFound);

prod.ID = update.ID;
prod.Name = update.Name;
prod.Price = update.Price;

return Request.CreateResponse<Product>(HttpStatusCode.OK, prod);
}
}