Posts tagged with 'SPA'

 

RealTime Charts With Wijmo & KnockoutJS

Friday, August 23, 2013 11:51 AM 0

Most web-developers know about KnockoutJS, and I hope that most of them have heard about (or used) the amazing stuff that Wijmo delivers. If you do not know about Wijmo, here a short summary…

“Wijmo offers you a complete suite of UI widgets for mobile and web application development. Wijmo includes full support for AngularJS & KnockoutJS.”

Wijmo is so much more than charting, but in this post I will show you how easy it is to use Wijmos line-chart and make it come alive with WebSockets and KnockoutJS.

Getting started

The goal with this post/tutorial is (as stated above) to create a Wijmo line-chart and make it alive with some real-time data. To have some data to display I will just randomize some numbers server-side.

NOTE: If you want to implement a working example your self, now is the time to create a new Visual Studio project (MVC3/MVC4) and add a default.html to the root of the project.

1: Getting to know the Wijmo line-chart

You do not have to use knockout or angular to bind data to the charts, but I can't recommend it strongly enough since it is so much easier than the “old” way.

Wijmo has a new set of docs that is awesome and can be viewed here (links to the line-chart docs)

Before we can start we need to reference some script resources to the default.html

<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.18/jquery-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="http://cdn.wijmo.com/themes/aristo/jquery-wijmo.css">
<link rel="stylesheet" type="text/css" href="http://cdn.wijmo.com/jquery.wijmo-complete.all.2.1.0.min.css">
<script type="text/javascript" src="http://cdn.wijmo.com/jquery.wijmo-open.all.2.1.0.min.js"></script>
<script type="text/javascript" src="http://cdn.wijmo.com/jquery.wijmo-complete.all.2.1.0.min.js"></script>
<script type="text/javascript" src="http://cdn.wijmo.com/wijmo/external/knockout-2.2.0.js"></script>
<script type="text/javascript" src="http://cdn.wijmo.com/interop/knockout.wijmo.3.20131.1.js"></script>

To create a static line-chart we need two things…

  1. A viewmodel containing data to bind to our chart.
    In line-charts the seriesList property is the key for adding data
  2. Some markup where we bind the viewmodel to the chart (with knockout).

Needless to say you ofcourse need to do the usual ko.applyBindings the activate knockout.

A basic example

So the most basic line-chart example would look like this.

<!DOCTYPE html>
<html>
<head>
    /*Script references should be here, omitted to save space*/
    <script type="text/javascript">
var viewModel = {
        seriesList: [{
              label: "Test",
              legendEntry: true,
              data: {
                x: ["1","2","3","4","5","6","7"],
                y: [10, 10, 11, 14, 17, 20, 25]
            },
            markers: {
                visible: true
            }
        }]
};
          $(function () {
              //Bind knockout (initialize stuff...)
              ko.applyBindings(viewModel);
          });
    </script>
</head>
<body>
    <div id="wijlinechart" data-bind="wijlinechart: { seriesList: seriesList }" style="width:600px;height:400px;"></div>
</body>
</html>

And the output from such example would look like

2: Adding real-time to the chart

Although the chart itself look really cool and you can add some seriously cool formattings on it (see the docs) in my opinion it is soo much cooler when the chart comes alive with real-time data!

There are ofcourse various ways to accomplish this, but I will use XSockets.NET to boost this line-chart.

This post is not about XSockets in depth so I will just cover the basics of getting started, and it is really not hard to do it.

Install XSockets

Open the package manager console. In the menu it is located under Tools > Library Package Manager > Package Manager Console.

To install xsockets just type
PM> Install-Package XSockets
and then hit enter…

You are done, we will not go into what happened there, but you will now have access to a “really fast and easy to work with real-time-framework

Adding realtime controllers

In XSockets you can create controllers that contain “action methods”, but the big difference compared to regular classes is that they are plugins and they are real-time.

We will need two different controller in this sample.One that our clients will connect to and subscribe for data, and another that will act as a data pump in this example

You can create the classes by yourself, but XSockets has scaffolders that can get you started. To read more about the scaffolder see http://xsockets.net/api/net-c/scaffolding-a-controller

The DataPumpController

As mentioned above we will need some kind of data pump to simulate data…
So I will open up the package manager console and type…
PM> Scaffold XSocketController XControllers\DataPump -longrunning true
This will create a new controller named DataPump in our current project in the folder XControllers.

We will not go into details on the C# since the serverside is mearly a simple data pump as stated earlier. One thing that might be interesting to know though is that the DataPump, defined as a longrunning controller cant be connected to from any client. Look at this controller as a singleton running inside the real-time server.

THE CODE

/// <summary>
/// A class representing datavalue, label and a timestamp
/// </summary>
public class TickModel
{        
    public List<int> Values { get; set; }
    public List<string> Times { get; set; }
    public string Label { get; set; }
}
    
/// <summary>
/// Just to simulate data we have a longrunning controller in XSockets... 
/// This one will tick data to the ChartDataController that will pass info to clients listening
/// It will push data to the other controller every second...
/// </summary>
[XBaseSocketMetadata("DataPump", Constants.GenericTextBufferSize, PluginRange.Internal)]
public class DataPump : XSocketController
{    
    //For sending data to the controller that the clients are connected to
  private static readonly ChartData ChartDataController;
    //For creating random data every second...
  private static readonly Timer Timer;
    
    //Chart data
  private static readonly List<TickModel> TickModels;    
    
    //NOTE: Some methods and members excluded to save space, the important stuff is only the elapsed event
  static void timer_Elapsed(object sender, ElapsedEventArgs e)
  {
      foreach (var tickModel in TickModels)
      {
            //If the lines has to many values... remove first
            if (tickModel.Values.Count >= Maxvalues){
                tickModel.Times.Remove(tickModel.Times.First());
                tickModel.Values.Remove(tickModel.Values.First());
            }
            tickModel.Values.Add(GetRandomInRange(tickModel.Values.Last()));
            tickModel.Times.Add(DateTime.Now.ToLongTimeString());
      }
        //send to clients... or actually to the controller that the clients are connected to...
        ChartDataController.Tick(TickModels);
  }
}

The ChartDataController

To add the ChartDataController I will just open the package manager console (once again) and type…
PM> Scaffold XSocketController XControllers\ChartData
This will create a new controller named ChartData in our current project in the folder XControllers.

The ChartDataController is the one that the clients will connect to, and it will only have one method… Tick!

Below you can see that I build an anonymous object that matches the JSON representation that we want to set the line-charts seriesList to… We coiuld ofcourse to it in the clients as well, but since I am a C# guy I did it in the server. This will simplify alot for me in the JavaScript..

THE CODE

public class ChartData : XSocketController
{
    public void Tick(List<TickModel> tickModels)
    {
        //Build an array that matches what we want to put into wijmos seriesList of the line-chart
        var data = tickModels.Select(p => new
            {
                label = p.Label,
                legendEntry = true,
                data = new
                    {
                        x = p.Times,
                        y = p.Values
                    },
                markers = new
                    {
                        visible = true,
                        type = "circle"
                    }
            });
        //Send the data to all clients listening for "tick"
        this.SendToAll(data, "tick");
    }
}

3: Connect and subscribe to real-time data

To sum up what we have got so far…

  • We created a static line-chart in step 1.
  • In step 2 we installed XSockets and created two controllers, one for pumping data and another for pushing data to clients subscribing…

So now it is time to connect to XSockets, get data and see our chart come to life!

First of all, add a reference to XSockets JavaScript API.

<script src="Scripts/XSockets.latest.js"></script>

In step one we did not have the seriesList as a observableArray, so this has to change together with some other setting that I now add to make the chart more nice. The important part is at the bottom… Where we set the seriesList : ko.observableArray([])

THE CODE

//Knockout VM with some settings for Wijmo...
var viewModel = {    
    showChartLabels: false,
    //When hover show the Y-value
    hint: {
        content: function () {
            return this.y;
        }
    },
    //The header of the chart
    header: {
        text: "Wijmo & XSockets.NET - Live Chart"
    },
    //Axis formatting
    //Rotate labels 45 degrees and have static Y-values between 0-100
    axis: {
        y: {
            labels: {
                style: {
                    rotation: -45
                }
            },
            autoMin: false,
            autoMax: false,
            min: 0,
            max: 100
        },
        x: {
            labels: {
                style: {
                    rotation: -45
                }
            }
        }
    },
    //The actual series data will come from xsockets...
    seriesList: ko.observableArray([])
};

Now we only have to connect to XSockets and subscribe to data

THE CODE

<script type="text/javascript">
    var conn = undefined;
    var updateChart = true;
    $(function () {
        //Connect to the default XSockets settings, localhost:4502 and the controller ChartData
        conn = new XSockets.WebSocket('ws://127.0.0.1:4502/ChartData');
        //Listen for open and bind when it happens
        conn.on(XSockets.Events.open, bindXSocketsEvents);
        //Bind knockout (initialize stuff...)
        ko.applyBindings(viewModel);
        //Pause updates if mouseover, and resume when mouseout
        $('#wijlinechart').bind('mouseover', function () {
            updateChart = false;
        }).bind('mouseout', function () {
            updateChart = true;
        });
    });
    var bindXSocketsEvents = function () {            
        conn.on('tick', function (data) {
            //When the "tick" event occurs, update knockout with new data to update the chart                 
            if (updateChart) {
                viewModel.seriesList(data);
            }
        });
    };
</script>

Summary

The simple sample above will provide a chart that looks something like below and it will be “alive” animating with a nice transition every second when new data arrives…

Wijmo is awesome, KnockoutJS is awesome and when you add XSockets.NET you can make really cool stuff happen!

If this is your first encounter with Wijmo I strongly recommend you to learn more, and I especially recommend you to look at the insane spreadjs

 

The project will full source code can be downloaded from github https://github.com/codeplanner/WijmoLiveLineChart

Regards

Uffe, Team XSockets.NET

Realtime SPA using AngularJS & XSockets.NET

Sunday, August 11, 2013 8:37 PM 0

A few weeks ago we posted a short guide that briefly describes how you can build a real-time SPA using KnockoutJS, back then we mentioned a few other frameworks that can help us out. This time we will show you how you can use AngularJS and XSockets.NET together.

Before we start i must point out that the more I dig into AngularJS the more neat features I find! - I'm starting to love AngularJS

 

Lets start..

A great way to learn and get introduced to AngularJS is work through the tutorial (http://docs.angularjs.org/tutorial/) which walks you through construction of an AngularJS powered web app.

As we will be relying on XSockets.NET and AngularJS i used Nuget to install the necessary things, first of all i just created a simple (empty) MVC4 application, Installed XSockekets.NET using "Install-Package XSockets" and after that i installed AngularJS from the same source (Nuget) using "Install-Package angularjs"

Our example

Our example application is an extramly simple thing that lets you list and register animals (animalApp) , when a user registers an animal all users is notified in realtime ( list is updated etc ) as well as when someone decides to remove an animal from the list , everyone is notified about that.

AngularJS consists of an large amount of nice things, for instace you have the possibillty to create your own custom angularservices, inject (DI) and access these  from your controllers for instance.

We will not depend on the AngularJS http service , instead we will make sure data is transported in real-time(WebSockets)  using XSockets.NET and a custom service.

Lets have a look at our backend (XSocketsController) which consists a few methods (getAnimals, addAnimal, removeAnimal) that will help us illustrate a real backend (?) . We are also using a model that will represent our Animals. As we focus on AngularJS and XSockets.NET we have choosen to "just" store the entities on a static list on controller List<Animal>

By just adding a class to the /Controller/Animal.cs folder of out MVC app we will have the backend setup and ready to serve.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using XSockets.Core.XSocket;
using XSockets.Core.XSocket.Helpers;
namespace XSockets.AngularJS.Example._0._1.Controller
{
    public class Animals : XSocketController
    {
        /// ivory belongs to elephants...Just saying.
     
        private static readonly List<Animal> animals;
        /// <summary>
        /// Just a simple XSockets controller that illustrates a "backend" 
        /// </summary>
        public void GetAnimals()
        {
            this.Send(animals,"getAnimals"); // Pass back the list of animals
        }
        /// <summary>
        /// Action that adds an "Animal" to our static list of animals. When added everyone is notified )
        /// </summary>
        /// <param name="animal"></param>
        public void AddAnimal(Animal animal)
        {
            animals.Add(animal);
            this.SendToAll(animal, "addAnimal"); // Notify all that we have a new animal
        }
        /// <summary>
        /// Remove an animal fro the list of Animals using it's Id ( Guid )
        /// </summary>
        /// <param name="id"></param>
        public void RemoveAnimal(Guid id)
        {
            var removedAnimal = animals.Find(a => a.Id.Equals(id));
            animals.Remove(removedAnimal);
            this.SendToAll(removedAnimal, "removeAnimal"); // Notify all that an animal is removed...
        }

        static Animals()
        {
            animals = new List<Animal>(); // Just set up a animals
            animals.Add(new Animal() { Name = "Cat",Description = "Cats are also animals"});
            animals.Add(new Animal() { Name = "Dog", Description = "Dogs can bark..."});
            animals.Add(new Animal() { Name = "Bird" , Description = "Birds can fly"});
        }
    }
    /// <summary>
    ///  A model that describes our animals
    /// </summary>
    public class Animal
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public Guid Id { get; set; }
        public Animal()
        {
            this.Id = Guid.NewGuid();
        }
    }
}

The class above represents our "complete" backend and we think we can skip the explanation of it as it is quite straight forward ( please let us know if you have ay questions, Use comments below )

So lets have a look how we set up our app and routes (app.js )

var animalApp = angular.module('animalApp', ['XSockets']).
  config(['$locationProvider', '$routeProvider', function ($locationProvider, $routeProvider) {
      $routeProvider.
          when('/animals/', { templateUrl: '/app/partials/animals.html', controller: AnimalsController }).
            when("/create/", { templateUrl: '/app/partials/create.html', controller: CreateAnimalController }).
              otherwise({ redirectTo: '/animals' });
  }]);

 

Custom service & wrapper for XSockets.NET's JavaScript API

To be able to do real-time comminication instead of regular http (ajax) calls we need to set up at custom service , We have choosen to do this with a module named XSockets ( injected into the app ) , the service will give use the possibility to hook up subscriptions to the XSockets.NET controller that futher on will refresh our model and views. We will publish data via this service to our controller. The service below is a simple wrapper for te XSockets.NET JavaScript API.

angular.module('XSockets', []).factory("xsocket", function($q, $rootScope) {
    var isConnected, listeners = {}, socket, queued = [];
    
    var Listener = (function () {
        function Listener(fn) {
            this._a = fn;
        }
        Listener.prototype.process = function (fn) {
            this._a = fn;
            return this;
        };
        Listener.prototype.invoke = function (a) {
            this._a(a);
            return this;
        };
        return Listener;
    })();
    function bind(eventName) {
        socket.on(eventName, function (a) {
            $rootScope.$apply(function () {
                listeners[eventName].invoke(a);
            });
        });
    }
    function publish(topic, data) {
        if (isConnected || typeof (socket) === "undefined") {
            socket.trigger(topic, data);
        } else {
            queued.push({ t: topic, d: data || {} });
        }
    }
    function subscribe(topic) {
        if (!listeners.hasOwnProperty(topic)) {
            listeners[topic] = new Listener();
            bind(topic, listeners[topic]);
            return listeners[topic];
        }
        return listeners[topic];
    };
    
    var connect = function (url) {
        var deferred = $q.defer();
        socket =  new XSockets.WebSocket(url);
        socket.on(XSockets.Events.open, function(conn) {
            $rootScope.$apply(function () {
                deferred.resolve(conn);
            });
        });
        return deferred.promise;
    };
    
  
    connect("ws://127.0.0.1:4502/Animals").then(function (ctx) {
        isConnected = true;
        queued.forEach(function (msg, i) {
            publish(msg.t, msg.d);
        });
        queued = [];
    });
    
    return {
        isConnected: isConnected,
        subscribe: subscribe,
        publish: publish
    };
});

As you can see the connect function will create a new connection to the XSocketsService located on localhost (you will probably have a configuration for this instead of hardcoding it in a real world scenario). We are also exposing a few  methods subscribe & publish, we will call those from the AngularJS Controllers (AnimalsController & CreateAnimalContoller ) later on. Our service wrappes the functinallity of the JavaScript API of XSockets.NET and needs to consider that AngularJS needs its state to be able to update views and models properly.

When we create a subsciption those are wrapped by the listener, each listener will have it .process callback ( shown below ) . First i hade the idea of using promisses for each callback but i ran into some trouble using those. ( If you are an AngularJS wizard ,please share any ideas if that would be possible )

Controllers & routes

Our application consits of two routes and controllers . /Animals/ ( AnimalController) will contain a view that lists all out animals and the /Create/ (CreateAnimalController) will contain a few form elements neccessary for registering animals. Lets have a look at the AnimalsController first.

AnimalController ( According to the AngularJS the proper way of creating a controller would be to use a module , but this works fine ? )

 
function AnimalsController($scope,xsocket) {
    $scope.animals = [];
    $scope.order = "Name"; // Order the data in the repater by the Name Property
    // Expose a function that will be used to remove an 'animal'
    $scope.removeAnimal =  function (id) {
        xsocket.publish("removeAnimal", { id: id }); // tel others and me that the animal is removed..
    };
  
    xsocket.subscribe("getAnimals").process(function (data) {
        $scope.animals = data; // data is retrived.
    });
  
    // If someone adds and animal, add it to the list
    xsocket.subscribe("addAnimal").process(function (added) {
        $scope.animals.unshift(added); // add the animal to the "list"
    });
    
    // Some has removed a animal, lets get rid of it from the list...
    xsocket.subscribe("removeAnimal").process(function (removed) {
        var index = $scope.animals.indexOf(removed);
        $scope.animals.splice(index, 1);
    });
    xsocket.publish("getAnimals"); // Get the list of animals
};

 

In the code above you see that we got access to the xsockets service and $scope , the scope is the glue between the model and the view ( see view below ) . As you see we call the .subscribe method on our service (xsocket.subscribe) and that we pass a "topic" for our subscription (i.e getAnimals). Each suscription established in the controller (AnimalController) relates to messages send by the XSocketsController. We are also doing a publish that says getAnimals, that wil trigger the getAnimals method on the controller and then subsequently our subscription will trigger the process(fn) callback in which updates the scope ( $scope.animals ) with the results ( List of Animas).

Lets have quick look at the view (angulartemplate) (app/partials/animals.html) to see how the model relates to the view

Animals.html ( AngularTemplate)

 
<ul>
    <li ng-repeat="animal in animals| orderBy:order" data-id="{{animal.Id}}">{{animal.Name}}
        <p>
            {{animal.Description}}
            &nbsp;<a ng-click="removeAnimal(animal.Id)" href="#">Remove </a>
        </p>
    </li>
</ul>

The view uses the ng-repeat directive to iterate the animals ( animal in animals ), we also added a orderBy attribute to get the animals ordered by its name ($scope.order).

Creating animals

We also have a controller responsible for creating animals. The controller will as the AnimalsController relay on our service ( xsockets) . By using the ng-model directive we glue the view and model togehter, And using the ng-click directive we can fire (publish) the model to the XSocketsContoller, fire the callback of our subscriptions created in the AnimalController (xsockets.subscribe("addAnimal").process(fn))

CreateAnimal ( AngularTemplate)

 <fieldset>
    <legend>Create a new animal</legend>
    <label for="name">Name:</label>
    <input type="text" ng-model="animal.Name" id="name" />
    <label for="description">Description</label>
    <input type="text" id="description" ng-model="animal.Description" />
    <div>
        <button ng-click="createAnimal()">Add animal</button>
    </div>
</fieldset>

As you can see in the there is a ng-click directive saying createAnimal() , this points to a method exposed in our CreateAnimalContoller uisng $scope 

 
function CreateAnimalController($scope,$location,xsocket) {
    $scope.animal = {
        Name: 'Ape',
        Description: 'Animals are nice...'
    };
    
    // Expose a methid that will be used to create an animal...
    $scope.createAnimal = function () {
        xsocket.publish("addAnimal", $scope.animal);
        $location.path('/animals/'); // Lets route/navigate to the list ...
    };
}

The createAnimal function of our controller will publish a message (addAnimal) to the XSocketsController our ours , then navigate to the /animals/ route

Complete example

You will find this example on the following repo on GitHub https://github.com/MagnusThor/XSockets.AngularJS.Animal.Example

[Edit: 3/2 2014 ] And the thing can be executed / tested on this url

http://magnusthor.github.io/XSockets.AngularJS.Animal.Example/src/#/animals/

 

Summary

AngularJS feels like the most competent MVVM frameworks i have been looking at, the more you experiment with it the more you will love it. I will for sure dig much more into AngularJS and can strongly recommend you to use it.I also suppose that there is a bunch ov AngularJS wizards out there that thinks thigs can be done differently, Feel free to comment and help us ut.

If you are new to AngularJS i can strongly recommend this Url - http://docs.angularjs.org/tutorial/ 

 

Building a real-time SPA using KnockoutJS, CodeFirst and XSockets.NET

Monday, July 15, 2013 4:34 PM 0

Building Single Page Applications aka. SPA is something that has become more popular this days. We can find a series of astute client-side JavaScript libraries helping us out to solve the most common tasks. KnockoutJS, AngularJS, DurandalJS and BreezJS are frameworks that we would recommend you to take a closer look into.

All of those frameworks delivers a wide range of functionality to solve time consuming issues such as dependency tracking, binding and associating DOM elements to objects and templating.

Compared to using a more straightforward approach using jQuery for such tasks those frameworks brings more standardized way of solving such tasks as mentioned above.

Binding and applying updates from the server to the UI is something that also can be streamlined and more effective.

In this blogpost we show you how you can publish, subscribe updates via a simple RealtimeMVC controller using XSockets.NET. The controller has a dependency to a simple domain model and EntityFramework.

The controller, EF and the simple domain model covers and briefly describes how the client in realtime interacts with backed in real-time and how the UI (SPA ) stays in sync with the data.

Note that the purpose of the post is to show the concept.

So what will we be building?

Shortly, the domain model describes things and the number likes each thing have. The UI will consist of a webform giving the user the possibility to create a “Thing” , A list of things with the number of likes each , and a action that places a like.

When a client places a like or create a new “thing”, the real-time controller and the client side will ensure that all clients are in sync.

Lets start!

We will be using Visual Studio and you will need a Internet connection because we will be adding a few Nuget Packages.

Step 1 - Create the MVC4 Project

Create the solution

  1. Create a new ASP.NET MVC4 Project C#
  2. (Install\Templates\Visual C#\ASP.NET MVC4 Webapplication)
  3. Name the Application e.g “MySimpleRealtimeSPA”
  4. Choose “Empty” when prompted to select project template
  5. Choose Razor as your Viewengine

Step 2 - Adding KnockoutJS and XSockets.NET Realimeframwork for .NET

Add the necessary Nuget packages. We will be relying on Entityframework codefirst, Knockout JS and XSockets.NET therefor we need to add the follwing packages to our solution.

  1. Open the Package Manager Console
  2. (View\Other Windows\Package Manager Console)
  3. Install KnockoutJS using “Install-Package knockoutjs”
  4. Install XSockets.NET using “Install-Package XSockets”

Note: EF is automatically added by the XSockets.NET package, therefore we want be needing to install it.

Step 3.a - Create the UI skeleton

First of all we add a new Razor View even though we are not aiming to use it more that once ( as we will be building a SPA )

  1. Add a new controller by right clicking the Controller folder of your soluion
  2. Name the controller “DefaultController” when prompted to enter the name
  3. You will now find a “DefaultControlle.cs” file in \Controllers
  4. Open the DefaultController.cs file
  5. Create the view by right-click return View() statement
  6. When prompted set the view name to “Index” and click ‘Add’
  7. You will now have a index.chtml file in the \View\Default folder
  8. Its now time to add the skeleton markup for our App - See steb 3.b

Step 3.b - The markup

Paste the following markup into the index.chtml file created.

<div>
    <fieldset>
        <legend>
            Wanna create a thing to like?
        </legend>
        <input type="text" name="caption" id="caption" placeholder="Give the thing a caption!"
        />
        <textarea name="description" id="description" placeholder="Describe what to like...">
        </textarea>
        <button id="createThing">
        </button>
    </fieldset>
</div>
<div>
    <h3>
        Things to like?
    </h3>
    <ul id="things">
        <li>
            <a>
            <span data-bind="text: Caption">The caption of the thing to like</span>&nbsp;
            (<mark>0</mark>)
            </a>
            <p>
                The description of the thing to like
            </p>
        </li>
        </ul>

Step 4 - Add the JavaScript references to the view (UI)

We will be needing a few JavaScript files in our sample. Add the following script tags to your view. we prefer to have them right before the end of the body tag :-)

All of the needed libraries can be found in the /scripts/ folder of your solution.

 

<script src="~/Scripts/jquery-1.9.1.js"></script>
<script src="~/Scripts/jXSockets.2.3.min.js"></script>
<script src="~/Scripts/knockout-2.3.0.debug.js"></script>
<script>
$(function(){
// Your custom JS will come here...
});
</script> 

..

Step 5 - Add a real-time controller

It’s now time for us the add a real-time controller to our solution. A real-time controller is an ordinary class that inherits from XSockets.Core.XSocket.XBaseSocket. For a start we don’t add any actions to the controller, we will get back to those later.

  1. Create a new class name RealtimeController.cs in the Controllers folder of your solution
  2. Make sure that it inherits XSockets.Core.XSocket.XBaseSocket to ensure that the real-time controller is plugged into the server when the server starts.
  3. We will also be needing a few extension methods later on , so lets also add a using as follows: using XSockets.Core.XSocket.Helpers;

The class will now look as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using XSockets.Core.XSocket.Helpers;
namespace MySimpleRealtimeSPA.Controllers
{
    public class RealtimeController: XSockets.Core.XSocket.XBaseSocket
    {
    }
} 

Step 6 - Configure, build

Now its time for us to connect to the real-time controller and verify that our XSockets service is launched properly and that the controller can be reached.

  1. Make sure that the development server of Visual Studio has “Enable edit and continue” option checked under the “Web” tab pane of the propertypage of the web.
  2. Build your solution
  3. Start the web app
  4. Browser will show you a 404 due to the fact that we are missing the Default Route , just type /Default/Index and you the view of yours will be fetched.

You can find a more detaild explanation of this here under - Get rid of the "stop development server" issue

Step 7 - Connect to the Real Time-controller (WebSocket) using the JavaScript API

Connect to the XSockets.Controller of yours (RealtimeController.cs) by adding the following code to a script tag in your index.cshtml ( View )

 

var ws;
$(function () {
    ws = new XSockets.WebSocket("ws://127.0.0.1:4502/RealtimeController", "RealtimeController");
    ws.subscribe(XSockets.Events.open, function (ctx) {
        console.log("ctx", ctx);
    });
});
Explanation

When the document is ready (loaded ) we are creating an new connection to the realtime controller using XSockets.WebSocket(url, subprotocol) , futher on we are creating a subscription for the open event that the server will fire when the client is connected, we are then displaying the ctx variable passed in the callback in the console.

To verify that the connection was successfully made openup the development console of (Chrome ) , it’t sholde have a log entry ctx

 

Step 8 - Create the domain model

Our application consist if an very simple domain-model that contains two different types of entities - Thing and Like.

  1. Create a file called domainmodel.cs ( or split up the classes below into seperate files if you desire )
  2. Paste the code found below

 

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace MySimpleRealtimeSPA.Models
{
    public class PersistentEntity
    {
        [Key]
        public int Id
        {
            get;
            set;
        }
        public DateTime Created
        {
            get;
            set;
        }
        public PersistentEntity()
        {
            this.Created = DateTime.Now;
        }
    }
    public class Like: PersistentEntity
    {
        public int Score
        {
            get;
            set;
        }
        public Thing Thing
        {
            get;
            set;
        }
    }
    public class Thing: PersistentEntity
    {
        public string Caption
        {
            get;
            set;
        }
        public string Description
        {
            get;
            set;
        }
        public virtual List <Like> Likes
        {
            get;
            set;
        }
    }
}

Step 9 - Create the database context for our domain model

As mentioned in the beginning of the blogpost will have a simple domain model that we will be accessing using via our real time controller and EntityFramework.

  1. Add a new folder to your solution named DataBase
  2. Add a new class named AppDbContext.cs to the folder
  3. Add the code find below to your class
using System.Data.Entity;
using MySimpleRealtimeSPA.Models;
namespace MySimpleRealtimeSPA.Database {
    public class AppDbContext: System.Data.Entity.DbContext {
        static AppDbContext() {
            System.Data.Entity.Database.SetInitializer(new DropCreateDatabaseIfModelChanges <DbContext> ());
        }
        public AppDbContext() {}
        public DbSet <Like> Likes {
            get;
            set;
        }
        public DbSet <Thing> Things {
            get;
            set;
        }
    }
}

Step 10 - Create the Knockout view models for our entities

Now it’s time for us to see the magic of KnockoutJS and see how we can combine KnockoutJS and XSockets.NET sofisticated publish and subscribe pattern.

The JavaScript below consist of three different
classes . Two of those represents our domain model and the last one covers our view in general. The thingsModel and likesModel reflects each entity and third appViewModel our application in general ( the list of things etc )

 

// model that represents our "things"
var thingModel = (function () {
    function thingModel(data) {
        this.Id = data.Id;
        this.Caption = data.Caption;
        this.Description = data.Description;
        this.Likes = ko.observableArray(ko.utils.arrayMap(data.Likes, function (like) {
            console.log(new likeModel(like));
            return new likeModel(like);
        }));;
    }
    return thingModel;
})();
// model that represents our Likes
var likeModel = (function () {
    function likeModel(data) {
        this.Id = data.Id;
        this.Score = data.Score;
        this.Created = data.Created;
    }
    return likeModel;
})();
// model that represents our app(view) in general 
var appViewModel = (function () {
    function appViewModel() {
        this.things = ko.observableArray();
        this.thing = ko.observable(new thingModel({}));
    }
    appViewModel.prototype.findById = function (obj) {
        var match = ko.utils.arrayFirst(this.things(), function (item) {
            return item.Id === obj.Id;
        });
        if (!match) return undefined;
        else return match;
    };
    appViewModel.prototype.delegate = function (obj, topic, cb) {
        obj.prototype[topic] = cb;
    };
    return appViewModel;
})();
 

Note: Worth mentioning here is that the appViewModel contains a method named .delegate(obj,topic, cb) . Using this method we can attach an event handler (listener) to the entity and fire a callback that passes the model itself. Within the callback, fired by the user or application we can publish the data to our backend for instance.

 

Step 11 - Add “Action-Methods” to our real-time controller

Now its time for us to add the action methods to our real time controller. Our application will need three different actions to be able to create and retrieve “Things” and “Likes” . Below is a list of Actions and a short explanation of those. We also recommend you to study the JavaScript API for further info regarding our JavaScript API

Things
Will return all “Things” in the database to the client “asking”.

ThingsSaveOrUpdate

Will create a new Thing and distribute it to all clients subscribing to the topic of “ThingsSaveOrUpdate”.

AddLikeToThing

Will register a like on a Thing, and notify all subscribers that a new like is registred.

1. Paste the following three methods to into the RealtimeController.cs file

 

 
public void Things() {
    var ctx = new AppDbContext();
    var things = ctx.Things;
    var all = new List < ThingViewModel > ();
    foreach(var thing in things) {
        all.Add(new ThingViewModel(thing));
    }
    this.Send(all.OrderByDescending(p = > p.Likes.Count), "Things");
    // Send (return) all exisiting things to the client using Topic 'Things'
}
public void ThingSaveOrUpdate(Thing model) {
    var ctx = new DataBase.AppDbContext();
    ctx.Things.Add(model);
    ctx.SaveChanges();
    this.SendToAll(new ThingViewModel(model), "ThingSaveOrUpdate"); // Lets notify all client about the new thing!
}
public void AddLikeToThing(int thingId, int score) {
    var ctx = new DataBase.AppDbContext();
    var thing = ctx.Things.SingleOrDefault(t = > t.Id.Equals(thingId));
    thing.Likes.Add(new Like() {
        Score = score
    });
    ctx.SaveChanges();
    this.SendToAll(new ThingViewModel(thing), "Liked"); // Lets notift all the client about the new like!
}

As you may notice we are calling this.SendTo(..) and this.Send(..) extention methods found in the XSockets.Core.XSocket.Helpers namespace. The diffrent between those are quite clear; SendToAll will send the object (ThingViewModel) as to all clients subscribing to "Liked", and Send will pass it back to the current client ( if subscribing ) only,

We havent yet created all nessessary code on the backend, as it is not possible to serialize the Entities as JSON due to complexity we need to create a viewmodel (non complex ) , in this case you can se above that im using a class called ThingViewModel .

2. Create a new class named ThingViewModel ( just add it to the model folder where you have the domain-model) and make sure you have a using pointing that namespace out in the RealtimeController. Paste the code below

 

using System;
using System.Collections.Generic;
namespace MySimpleRealtimeSPA.Models {
    public class ThingViewModel {
        public int Id {
            get;
            set;
        }
        public string Caption {
            get;
            set;
        }
        public string Description {
            get;
            set;
        }
        public DateTime Created {
            get;
            set;
        }
        public IList < LikeViewModel > Likes {
            get;
            set;
        }
        public ThingViewModel(Thing thing) {
            this.Id = thing.Id;
            this.Caption = thing.Caption;
            this.Description = thing.Description;
            this.Created = thing.Created;
            this.Likes = new List < LikeViewModel > ();
            foreach(var like in thing.Likes) {
                this.Likes.Add(new LikeViewModel(like));
            }
        }
    }
    public class LikeViewModel {
        public int Id {
            get;
            set;
        }
        public int Score {
            get;
            set;
        }
        public DateTime Created {
            get;
            set;
        }
        public LikeViewModel(Like like) {
            this.Id = like.Id;
            this.Score = like.Score;
            this.Created = like.Created;
        }
    }
} 

 

Step 12 - Wrapping things up on the client side (JavaScripts)

Its now time for us to wrap things up on the JavaScript on the client side, this is where we se the actual power of KnockoutJS and XSockets.NET . By just adding the following code to the document ready event ( where we ensured that we got the connection earlier ) we will tie the backend and the client’s view and model together. We placed a few comments inside the code that explains what we are doing ( hopefully you will be able to understand )

 

 
$(function () {
 
  // Create a new Connection to our Realtime controller
    ws = new XSockets.WebSocket("ws://127.0.0.1:4502/RealtimeController", "Realtimecontroller");
    ws.subscribe(XSockets.Events.open, function (connection) {
        ws.trigger("Things"); // Get all the "things"
    });
    // Create a new instance of our application viewmodel
    vm = new appViewModel();
    // attach a delagate for the "action" -> saveOrUpdate on our thingModel,
    vm.delegate(thingModel, "saveOrUpdate", function (model, event) {
        // Send a mesasge to the server using the topic, ThingSaveOrUpdate. We pass the model as a JSON literal
        ws.publish("ThingSaveOrUpdate", ko.toJS(model)); // Note, we are passing the complete model as XSockets.NET supports modelbinding (serverside)
    });
    // attach a delegate for the "action" -> like on our thingModel,
    vm.delegate(thingModel, "like", function (model, event) {
        // Send a message and add a like to the 'thing'
        ws.publish("AddLikeToThing", {
            thingId: model.Id,
            score: 5
        });
    });
    // Lets listen for inbound messages with the topic of 'ThingSaveOrUpdate' 
    ws.subscribe("ThingSaveOrUpdate", function (t) {
        vm.things.push(new thingModel(t)); // Add the thing as a thingModel to our observable array
    });
    // Someone liked a thing, find the thuing, and replace
    ws.subscribe("Liked", function (l) {
        vm.things.replace(vm.findById(l), new thingModel(l));
    });
    // Listen to all things , this will anly fire once ( after connect , as we below trigger Things )
    ws.subscribe("Things", function (allThings) {
        allThings.forEach(function (a, b) {
            vm.things.push(new thingModel(a));
        });
    });
    ko.applyBindings(vm);
});

Note: Above you can see how we use the .delagate method of our appViewModel to "subscribe" to the saveOrUpdate event for instance. When the callback fires we are doing a publish on the WebSocket (ws) , saying the topic is "ThingSaveOrUpdate" , this will pass the model and later on the ActionMethod of our RealtimeController will be invoked.

Step 13 - Apply UI binding to the UI using Knockout

In the beginning of the blogpost we created a skeleton of the UI , now its time for us to use Knockout to bind our ViewModels to the UI as well as we will attach “click” events that will fire our callbacks ( delegates ) and further on passthe model to the real-time controller. Knockout will also ensure that the UI is in sync.

To just replace the skeleton with this complete markup, and study the data-bind attributes on the markup.

 

    <div>
        <fieldset data-bind="with: thing">
            <legend>Wanna create a thing to like?</legend>
            <input type="text" name="caption" id="caption" placeholder="Give the thing a caption!" data-bind="value: Caption, valueUpdate: 'afterkeydown'" />
            <textarea name="description" id="description" placeholder="Describe what to like..." data-bind="value: Description, valueUpdate: 'afterkeydown'"></textarea>
            <button id="createThing"
                data-bind="click: saveOrUpdate">
                Create!</button>
        </fieldset>
    </div>
    <div>
        <h3>Things to like?</h3>
        <ul id="things" data-bind="foreach: things">
            <li>
                <a data-bind="click: like">
                    <span data-bind="text: Caption"></span>&nbsp;
                (<mark data-bind="text: Likes().length"></mark>)
                </a>
                <p data-bind="text: Description"></p>
            </li>
        </ul>
</div> 

Yes, you have after this 13 steps come to the end...

So what to do?

Just recompile and start the webapplication and navigate to /default/index -> open several browser windows to simulate two users or more.

Summary

As you can see KnockoutJS gives us many nice features for developing Rich Internet Applications (SPA) using JavaScript. Its easy to make our markup based interface responsive to changes in the underlying model. By just using the simple delegate shown above we are able to publish the entity to the realtime-controller by a few lines of code.

The client can also easy subscribe to changes by just establishing telling the controller its interests

This few pieces of code gives us an application where all the clients are in sync (ui and backend in sync also )

As and end of this summary i must point out a good resource when it comes to KnockoutJS - Have a look at Ryan Niemeyers blog/site http://knockmeout.net   , tons onf great stuff can be find there.

We also made this example available on GitHub in un furbished version  https://github.com/MagnusThor/XSockets.ILike.HTML5.App.Using.KnockoutJS.EF/