Translate

Showing posts with label KnockoutJS. Show all posts
Showing posts with label KnockoutJS. Show all posts

Sunday, 24 August 2014

KnockoutJS and AutoPostBack="true" - I

I had to check this out. What could be the difference if the developer were to use KO and not ASP.Net?

The only difference is the programming language of use - C# or jQuery / Javascript.

The resultant output is this below


No button click event just the AutoPostBack property of the drop down list set to true.

I will first share the ASP.Net code and then dwell into the equivalent KO code.

You need JSon.Net installed and referenced to the project, an app_id to consume the JSon data resultset from openexchangerates.org, VS 2012 for web and you are good to go.

The HTML source of the .aspx page

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="GetExchangeRates.aspx.cs" Inherits="GetExchangeRates" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        Currency  
        <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
        </asp:DropDownList>
  
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

    
    </div>
    </form>
</body>
</html>


Here is the aspx code behind.

using System;
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json;
    public partial class GetExchangeRates : System.Web.UI.Page
    {
        static JSon_SampleData.CurrencyRates obj;
        Dictionary rateValues;
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                obj = new JSon_SampleData.CurrencyRates();
                obj = Download_Serialized_ExchangeRate("http://openexchangerates.org/api/latest.json?app_id=");
                rateValues = new Dictionary();
                rateValues = obj.Rates;
                foreach (var raate in rateValues)
                {
                    DropDownList1.Items.Add(raate.Key);
                }
                Session["rateValues"] = rateValues;
            }
        }

        private static T Download_Serialized_ExchangeRate(string url) where T : new()
        {
            using (var w = new WebClient())
            {
                var json_data = string.Empty;                
                try
                {
                    json_data= w.DownloadString(url);
                }
                catch (Exception) { }
                return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject(json_data) : new T();
            }
        }

        protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
        {
            rateValues = (Dictionary)Session["rateValues"];
            foreach (var raate in rateValues)
            {
                if (raate.Key == DropDownList1.SelectedItem.Text)
                {
                    TextBox1.Text = raate.Value.ToString();
                    break;
                }
            }

        }
}


And the Class to hold the JSon data.

using System.Collections.Generic;

namespace JSon_SampleData
{
    public class CurrencyRates
    {
        public string Disclaimer { get; set; }
        public string License { get; set; }
        public int TimeStamp { get; set; }
        public string Base { get; set; }
        public Dictionary Rates { get; set; }
    } 
    
}

Reference the JSon Data class in your ASP.Net website.

I will post the KO code in the next part and get back to the BDD and Agile part.

Saturday, 23 August 2014

KnockoutJS, Jasmine and Phantom - I

What AngularJS or Javascript with RegisterClientScript blocks could not do, KnockoutJS does and satisfactorily simply !!

What this means, in Asp.Net terms, is equivalent to setting AutopostBack=true or using a jQuery callback function.

Working on client-server technology, especially for Asp.Net developers, frequently makes one think, "If only the code did not do so many round-trips to the server with post-backs and could do simple UI changes that reflect back instantly to the user...".

I mention this, not as a declaration of my own long-felt personal wish but, because this is what the KnockoutJS documentation or the help resources miss out that does not make more ASP.Net developers take to KO nor is there sufficient mention that because it is plain Javascript, it helps Agile development methods to quickly tap into the many already available unit testing and functional testing tools like Jasmine, Slim or PhantomJS and set up a robust team of "high speed development" corridors!

KO also makes things more interesting to the technical-jargon-smitten-adrenaline junkies, who must have a technical discussion on design patterns and architecture to even say "Hello World!" !.

Because KO enables client-client 'post', it means a fresh look at the way the view-model works and is understood in MVM becomes important - now, it becomes MVVM (the additonal 'V' in the model is actually viewmodel together).

The additional tier in the architecture is ok, not as a compromise that you cannot do anything about anyway, but seriously as an efficient workaround that not only improves performance but also helps Agile immensely!! How?

With and because of KO, you do not need to think of Selenium as an additional tool to burden your team with because testing the VM itself with Jasmine or other unit testing tools should suffice !!

And also, there is no need to learn an additional tool like Slim to integrate your tests because PhantomJs provides a command-line executable (or rather, an executable).

That is a lot of advantages of KO, I hope I am not putting down other equally or more efficient language tools. Yes, KO is not a framework as AngularJS probably is.

So, here goes as I whet my appetite...

HelloWorld.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello, KnockoutJS</title>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script type="text/javascript" src="knockoutjs.3.2.0\content\scripts\knockout-3.2.0.js"></script>
    <script type="text/javascript" src="HelloKO-Script.js"></script>
</head>
<body>
    <p>First name: <input data-bind="value: firstName" /></p>
    <p>Last name: <input data-bind="value: lastName" /></p>
    <h3>Hello, <span data-bind="text: fullName"> </span>!</h3>
  </body>
</html>

Of course, the reference to the jQuery script is still necessary because of the $ functiion callback in the below script.

And the Knockout script (and no pun intended!)

// HelloKO-Script.js

var HelloViewModel = function (firstname, lastname) {
    var self = this;

    self.firstName = ko.observable(firstname);
    self.lastName = ko.observable(lastname);

    self.fullName = ko.computed(function () {
        return self.firstName() + " " + self.lastName();
    }, self);
};

$(function () {
    ko.applyBindings(new HelloViewModel("Ravichandran", "Jv"));
});

Simple four terms to explain is all that is required - the ViewModel that is, quite apparently, the viewmodel, the observable method of KO that 'observes' the 'fields', the computed keyword of KO to take an action   and the applyBindings that applies - here is the magic! - the KO bindings, in this example the 'data-bind' to the 'value:' binding.

The above program will simply output this - 


But the magic is when you make any change to either of the field and,

The applyBindings is what activates KO and the callback magic with the help of the $ jQuery callback mechanism to make the UI update happen!

You can download KO separately or use the NuGet tool in VS 2012. I used the latter - copy the package after downloading with NuGet into the relevant folder and modify the script src path.

The Jasmine tests are equally simple !

All you need in Jasmine is a spec file (same name as the CUT or Script Under Test) and the Jasmine framework.

The spec file

"HelloKO-Script-spec.js"

describe("My Name", function () {
    it("concatenates firstName and lastName and displays full name", function () {
        var target = new HelloViewModel("Ravichandran", "Jv");
        expect(target.fullName()).toBe("Ravichandran Jv");
    });
});

The describe keyword describes the function and gives it a name as parameters, defines a target variable 'target' and calls the 'expect' method of the Jasmine framework to match a given value with a call to the HelloKO-Script.js method, fullName().


To run and see the test results, you could use your own CSS or PhantomJS or Slim.

Step 1
Download Jasmine and PhantomJS and place the downloaded folders in the bin/root or wherever you have the HTML page.

Step 2
Create a new HTML page and insert the below code -

<!DOCTYPE HTML>
<html>
<head>
  <title>Jasmine Test Runner</title>
  <link rel="stylesheet" type="text/css" href="Jasmine\lib\jasmine-1.2.0\jasmine.css" />
    <script type="text/javascript" src="Jasmine\lib\jasmine-1.2.0\jasmine.js"></script>
    <script type="text/javascript" src="Jasmine\lib\jasmine-1.2.0\jasmine-html.js"></script>

    <script type="text/javascript" src="phantom-jasmine-master\lib\console-runner.js"></script>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script type="text/javascript" src="knockoutjs.3.2.0\content\scripts\knockout-3.2.0.js"></script>

  <!-- The KnockoutJS script source file -->
  <script type="text/javascript" src="helloko-script.js"></script>

  <!-- The spec Jasmine file -->
  <script type="text/javascript" src="helloko-script-spec.js"></script>
</head>
<body>

    <!-- The Phantom script to invoke the console0runner -->
<script type="text/javascript">
    var console_reporter = new jasmine.ConsoleReporter()
    jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
    jasmine.getEnv().addReporter(console_reporter);
    jasmine.getEnv().execute();
</script>

</body>
</html>

That is it! Run the above HTML page and see the results. If your steps 1 & 2 were correct, you should see the below result screen else make sure the <script tags' src location are matching with your path.

If you do not like the PhantomJS script, you could use Slim instead but for that you will need to download Slim, know how to use and start the fitNesse server, write the Slim test suite and finally run the Slim fixture !!

With PhantomJS, you modify just the TestRunner HTML page as and when you need to modify the path to the script source file and the Jasmine spec file.

Ideally, they say, you should mock the jQuery $ method, too, but that, again, as they say, is yet another story - more in the context of TDD !