Posts Tagged ‘javascript’

Screenshot“Kaboom!” is one of those things you stumble upon and intrigues you from the start. It probably needs more work (not to mention documentation), but certainly gives you a peak at what I believe could be the next big thing in the ASP.NET MVC world. Having just finished a CMS system where I used a very rich JQuery client, I found this a very probable next step. Already using “jquery.forms” to submit all my forms via ajax POST and using “$.getJSON” for all my GET actions, my views started to get pretty lean. I thought, what if I had a JQuery ViewModel that would handle my UI commands and handle all my communication with my controller? A quick search lead me to “Kaboom!”.

The first thing I worried about was testability. “QUnit” (http://docs.jquery.com/QUnit) seems to be a very powerful testing framework that would probably give me more coverage than what I had before! UnitTesting – Check :)

So lets look at one of the samples in the codeplex download, specifically the Asp.Net MVC sample…

We start with a “Person” Model:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

And a “PersonController” class which has a Search action:

public class PersonsController : Controller
{
    public JsonResult Search(string searchString)
    {
        List persons = new List();
        persons.Add(new Person { FirstName = "Kozin", LastName = "Osot" });
        persons.Add(new Person { FirstName = "Setesyci", LastName = "Rynaugh" });
        persons.Add(new Person { FirstName = "Atheck", LastName = "Garash" });

        return Json(persons
            .Where(p => p.FirstName.ToLower().Contains(searchString.ToLower()) ||
                p.LastName.ToLower().Contains(searchString.ToLower())).ToList());
    }
}

Then we create a “SearchViewModel” js file and put this in our “ViewModels” folder like so:

var SearchViewModel = {
    Initialize: function(args, callback) {
        Kaboom.register("Search", SearchViewModel.Search);
        SearchViewModel.SearchResults = new Array();
        callback();
    },

    Ready: function() {
        SearchViewModel.Search();
    },

    SearchString: '',
    SearchResults: null,
    Search: function() {
        $.getJSON('/Person/Search',// You can set this as a hidden field on your View with 'Url.Action(..' and simply do $('#searchSource').val()
            { searchString: SearchViewModel.SearchString },
            SearchViewModel.PopulateSearchResults);
    },

    PopulateSearchResults: function(data) {
        SearchViewModel.SearchResults = data;
        Kaboom.notify(SearchViewModel, "SearchResults");
    }
}

And our “Search” view would hook up to our view model like so…

<head runat="server">
    <title>Search</title>
    <% string version = DateTime.Now.Ticks.ToString(); %>
    <script type="text/javascript" src="../../ViewModels/Persons/SearchViewModel.js?id=<%= version %>"></script>
    <script type="text/javascript" src="Scripts/jquery-1.3.2.js?id=<%= DateTime.Now.Ticks.ToString() %>"></script>
    <script type="text/javascript" src="Scripts/json2.js?id=<%= DateTime.Now.Ticks.ToString() %>"></script>
    <script type="text/javascript" src="Scripts/kaboom.js?id=<%= DateTime.Now.Ticks.ToString() %>"></script>

</head>
<body>
    Quick start shows how to communicate with an aspMVC controller.....<br />
    <input type="hidden" id="viewmodel" viewmodel="SearchViewModel" debug="0" />
    <div id="Debug"></div>
    Search:<br />
    <input type="text" bindto="SearchString" mode="TwoWay" /><br />
    <input type="button" value="Search" command="Search" />
    <br />
    <table bindto="SearchResults">
        <thead>
            <tr>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Options</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>$FirstName</td>
                <td>$LastName</td>
                <td><a href="#" onclick="alert('$FirstName')">Delete</a></td>
            </tr>
        </tbody>
    </table>
</body>

You can bind all your view actions to commands.

<input type="button" command="Save" value="Bound to Save command via jQuery(element).click()" /><br /><br />
<input type="button" command="Save" trigger="dblclick" value="Bound to Save command via jQuery(element).dblclick()" /><br /><br />
<input type="button" command="Save" trigger="blur" value="Bound to Save command via jQuery(element).blur()" /><br /><br />
<input type="button" command="Save" trigger="customaction" value="Bound to Save command via jQuery(element).customaction()" /><br /><br />

… and it has support for other controls and more complex bindings.

<select bindto="Person.Salutation"
         datatextfield="Name"
         datavaluefield="Id"
         datasourceid="Salutations"
         onbind="ProgrammaticallyBindIt" >
   <option value="0">[select]</option>
</select>

There are loads of other examples, including binding to Tables, Divs, Spans, Checkboxes etc. You can download the framework here.


Loading dynamic data into an ordered- or unordered list cannot be simpler.

First we create a template for each LI row:

var listRow = "<li id=\"{0}\">{1}</li>";

Then we call the ajax method and handle the JSON results:

// Now using my $.stringFormat method
// (see tag 'string format')
// we append the template with the correct values to the ul or ol
$.getJSON("http://somedomain/getsomedata", function(data, status) {
   $.each(data, function() {
   var listRowPopulated = $.stringFormat(listRow, [this.id, this.title]);
      $(listRowPopulated).appendTo("#someul");
    });
});

When designing a rich user interface with JQuery it is very useful to replace default hyperlink functionality with ajax calls. The first method will turn the <a> functionality into an ajax call using the “href” attribute as source. The second method will do the same, but will ask “Are you sure?” first (very usefull for deletes etc…).

The ajaxReload var can then be set to a function that would handle the ajaxCall. These methods would usually be located in a ‘common.js’ file.

// GLOBAL VARS
var ajaxReload = function() { };

$(".ajaxCall").live("click", function(e) {
    e.preventDefault();
    $.get($(this).attr("href"), ajaxReload);
});

$(".yesNoAjaxCall").live("click", function(e) {
    e.preventDefault();
    if (confirm('Are you sure?')) {
        $.get($(this).attr("href"), ajaxReload);
    }
});

The reason behind using ‘live’ instead of ‘bind’ or ‘click’ is because I want to bind all future loaded ‘a’ tags too. Usually ‘bind’ or ‘click’ will only find the static ‘a’ tags that are available on page load.