Using jQuery to directly call ASP.NET AJAX page methods | Encosia

Using jQuery to directly call ASP.NET AJAX page methods | Encosia.

An old favorite!

Animated Add & Remove with jQuery and Knockout

I’ve been doing so many cool things with jQuery and Knockout lately that have my developer soul bursting with glee. One of the things that I did most recently was to implement a small search application that allows a user to execute multiple searches and display the results as a collection of results. (That’s a little confusing. What I mean is that when you do one search, you get a box with the results. If you do another search, you get another box with another set of results.)

I wanted the interface to feel really fluid, and I figured the best way to do this would be to animate the appearance of the search results. I was using Knockout to databind results to the page, but this caused a problem: the results would appear on the page as soon as they were added to the collection.

Let’s look at an example of what I’m talking about so far:

var gcounter = 0;

var viewModel = function () {
    var self = this;
    self.items = ko.observableArray();
    
    self.add = function () {
        self.items.push(new itemViewModel("item " + ++gcounter));
    }
    
    self.remove = function (item) {
        self.items.remove(item);
    };
};

var itemViewModel = function(data) {
    var self = this;
    self.text = ko.observable(data);
};

ko.applyBindings(new viewModel());
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<div class="inline clickable" data-bind="click: add">
    <span class="ui-icon ui-icon-plus inline"></span>
    <span>Add</span>
</div>
<div data-bind="foreach: items">
    <div class="bigredbox clickable" data-bind="click: $parent.remove">
        <span class="ui-icon ui-icon-minus inline"></span>
        <span data-bind="text: text"></span>
    </div>
</div>

This example allows you to click ‘Add’ to add items, and remove items by clicking them. It’s very responsive, but it lacks a certain je ne sais quoi since items simply appear and disappear instantly. My first thought on addressing this was to make items fade into existence as they are added. We can do this in two steps. First, change the template for the data item to be hidden by default. Then, use jQuery to fade-in after the item is added to the collection. (Note that my hidden class contains just display: none and is defined in my css.)

var gcounter = 0;

var viewModel = function () {
    var self = this;
    self.items = ko.observableArray();
    
    self.add = function () {
        self.items.push(new itemViewModel("item " + ++gcounter));
        $(".bigredbox.hidden").fadeIn();
    }
    
    self.remove = function (item) {
        self.items.remove(item);
    };
};

var itemViewModel = function(data) {
    var self = this;
    self.text = ko.observable(data);
};

ko.applyBindings(new viewModel());
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<div class="inline clickable" data-bind="click: add">
    <span class="ui-icon ui-icon-plus inline"></span>
    <span>Add</span>
</div>
<div data-bind="foreach: items">
    <div class="bigredbox clickable hidden" data-bind="click: $parent.remove">
        <span class="ui-icon ui-icon-minus inline"></span>
        <span data-bind="text: text"></span>
    </div>
</div>

Ooh, that feels nice now, doesn’t it? But removing items still feels kinda lame. It would be really cool if items would fade away when they were removed! We can do that similarly to how we added the item. We need to employ a few tricks to make this happen, though. The click event’s second argument contains the control that was clicked in its target property. So, we can use event.target along with jQuery’s closest function to find the control we need to fade out. jQuery’s fadeOut method allows you to specify a callback to execute once it’s complete, so we’ll fade-out the selected item and remove it from the collection once the fade completes. That’s all we need to do, though; no HTML changes are needed.

var gcounter = 0;

var viewModel = function () {
    var self = this;
    self.items = ko.observableArray();
    
    self.add = function () {
        self.items.push(new itemViewModel("item " + ++gcounter));
        $(".bigredbox.hidden").fadeIn();
    }
    
    self.remove = function (item, event) {
        $(event.target).closest(".bigredbox").fadeOut(null, function() {
            self.items.remove(item);
        });
    };
};

var itemViewModel = function(data) {
    var self = this;
    self.text = ko.observable(data);
};

ko.applyBindings(new viewModel());

So that’s working great, but I still have a problem. When an item is removed, it fades away nicely, but then the results just flash together once the item disappears. It’d be nicer if that was also animated. jQuery’s slideUp method seems like it’d be perfect for this, so let’s just chain it together with fadeOut! Once again, there’s a little trick to this: you need to specify that the animations shouldn’t be queued. Luckily, that’s accomplished easily by specifying the correct option. Once again, this is a javascript-only change.

var gcounter = 0;

var viewModel = function () {
    var self = this;
    self.items = ko.observableArray();
    
    self.add = function () {
        self.items.push(new itemViewModel("item " + ++gcounter));
        $(".bigredbox.hidden").fadeIn();
    }
    
    self.remove = function (item, event) {
        $(event.target).closest(".bigredbox")
            .slideUp({queue: false})
            .fadeOut(null, function() {
                self.items.remove(item);
        });
    };
};

var itemViewModel = function(data) {
    var self = this;
    self.text = ko.observable(data);
};

ko.applyBindings(new viewModel());

Wooo, doggy! Now things are feeling very fluid. When we add an item, it fades into existence. Removing an item slides up and fades out. Everything feels really smooth and slick. Be sure to check out the jsfiddle for a working example!

Submit a Knockout-Bound jQuery Dialog when Enter is Pressed

There I was, happily coding an awesome logon prompt using the technique previously discussed here, when I ran into a problem: my form wasn’t submitting when I pressed the ‘enter’ key. That’s annoying. No self-respecting logon prompt should require you to move the mouse to a button and click!

So what to do?! Step one: don’t panic. Okay, good. Now you can use a few easy tricks to force the dialog to submit when enter is pressed.

Let’s look at the example that doesn’t work. I have a simple Knockout view model hooked up to a jQuery dialog. When I click the dialog’s “Login” button, it calls a login function. If I press the enter key, though, nothing happens. I take that back; one thing happens: you become annoyed that nothing happened.

var loginViewModel = function() {
    var self = this;
    self.password = ko.observable();
    self.username = ko.observable();
};

$("#loginDialog").dialog({
    buttons: {
        "Login": login
    }
});

function login() {
    // login stuff
}
<div id="loginDialog" title="Login">
    <form id="loginForm">
        <fieldset>
            <label for="user">Username</label>
            <input type="text" id="user" data-bind="value: username" />
            <label for="password">Password</label>
            <input type="password" id="password" data-bind="value: password" />
        </fieldset>
    </form>
</div>

The first thing we need to do is to bind our form to our view model using Knockout’s submit binding. With the submit binding in place, we can use jQuery to submit the form.

var loginViewModel = function() {
    var self = this;
    self.password = ko.observable();
    self.username = ko.observable();
    self.login = function() {
        // login stuff
    };
};

$("#loginDialog").dialog({
    buttons: {
        "Login": function () {
            $("#loginForm").submit();
        }
    }
});
<div id="loginDialog" title="Login">
    <form id="loginForm" data-bind="submit: login">
        <fieldset>
            <label for="user">Username</label>
            <input type="text" id="user" data-bind="value: username" />
            <label for="password">Password</label>
            <input type="password" id="password" data-bind="value: password" />
        </fieldset>
    </form>
</div>

Now we’re equipped to handle the enter keypress. So let’s do that…

var loginViewModel = function() {
    var self = this;
    self.password = ko.observable();
    self.username = ko.observable();
    self.login = function() {
        // login stuff
    };
};

$("#loginDialog").dialog({
    buttons: {
        "Login": function () {
            $("#loginForm").submit();
        }
    }
});
$("#loginDialog").keypress(function(event) {
    if (event.which == 13) {
        event.preventDefault();
        $("#loginForm").submit();
    }
});

That might seem like that should be it, but it’s not quite working. It seems to submit just fine, but login only succeeds when the button is pressed. What gives!? It’s a subtle thing that took me a little bit of time to realize. Databound values are only updated by default when focus leaves the control. So, if you enter a username, press tab, enter a password, then press enter, the password value in the view model hasn’t been updated yet! Argh!

No problem, though. We can change the value to update with each keypress.

<div id="loginDialog" title="Login">
    <form id="loginForm" data-bind="submit: login">
        <fieldset>
            <label for="user">Username</label>
            <input type="text" id="user" data-bind="value: username, valueUpdate: 'afterkeydown'" />
            <label for="password">Password</label>
            <input type="password" id="password" data-bind="value: password, valueUpdate: 'afterkeydown'" />
        </fieldset>
    </form>
</div>

Now we’re in business! The login works great whether you press the button or use the enter key.

Breathtaking Animations with jQuery UI Easings

I was building a small web application for a customer, and I wanted to display a login prompt in a modal dialog box when the user isn’t authenticated. jQuery gives me an easy way to do that with its dialog command, so no problem there. The core functionality I’m looking for is done with one line of javascript.

// simple dialog
$("#dialog").dialog();

The dialog shows and hides just fine, but I thought I’d add some visual flair by slapping an animation on it. An easy way to do this would be to use jQuery UI’s effect methods. There are a number of basic effects to choose from: fadeIn/fadeOut, slideUp/slideDown, or even just hide/show with a delay.

// basic animations
$("#dialog").dialog({
    hide: function () {
        $(this).fadeOut();
    },
    show:  function () {
        $(this).fadeIn();
    }
});

On their own, these are okay, ho-hum animations. If you really want to snazz it up, give jQuery UI’s easings a look. Easings can be used to control the animation progression to create interesting visual effects. So, I wanted my dialog box to spring open and quickly snap into place, then do the opposite when closing. The easeOutBack and easeInBack easings combined with the scale effect are exactly what I wanted.

// animations with easings
$("#dialog").dialog({
    hide: {
        effect: "scale",
        easing: "easeInBack",
    },
    show: {
        effect: "scale",
        easing: "easeOutBack",
    }
});

I created this Fiddle as a working example. Breathtaking, right?

Pretty Forms with CSS & jQuery

Let’s say you’re making a web form. You want it to look nice, so you’d like the input controls to line up and be consistently sized. You know that you shouldn’t be using tables for formatting, but how else can you avoid creating an ugly mess of labels smushed-up against their controls?

UglyForm

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <script type="text/javascript"></script>
    <style type="text/css"></style>
</head>
<body>
    <div>
        <label for="name">Name:</label><input type="text" name="name"/><br/>
        <label for="email">Email:</label><input type="text" name="email"/><br/>
        <label for="password">Password:</label><input type="password" name="password"/><br/>
        <label for="confirmPassword">Confirm:</label><input type="password" name="confirmPassword"/><br/>
        <label for="newsletter">Email me about stuff!</label><input type="checkbox" name="newsletter"/>
    </div>
</body>
</html>

I found a cool trick to fix the spacing of labels and controls using jQuery. The idea is simple: loop through all labels and set their widths equal to the widest. The logic to do this is a typical CS-101 find-the-max loop, but there’s also a not-so-obvious second step. In order for the widened labels to display, they must be floated to the left.

LessUglyForm

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script> 
    <script type="text/javascript">
         $(function() {
             var max = 0;
             $("label").each(function () {
                 if ($(this).width() > max)
                     max = $(this).width();
            });
            $("label").width(max + 5);
        });
    </script>
    <style type="text/css">
        label {
            float: left;
        }
    </style>
</head>
<body>
    <div>
        <label for="name">Name:</label><input type="text" name="name"/><br/>
        <label for="email">Email:</label><input type="text" name="email"/><br/>
        <label for="password">Password:</label><input type="password" name="password"/><br/>
        <label for="confirmPassword">Confirm:</label><input type="password" name="confirmPassword"/><br/>
        <label for="newsletter">Email me about stuff!</label><input type="checkbox" name="newsletter"/>
    </div>
</body>
</html>

Fixing the label spacing helps, but it’s still pretty ugly. You don’t want the textboxes rubbing shoulders like that, and why are the password boxes slightly shorter than the textboxes? We can fix both of those items with some simple CSS.

OkayForm

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script> 
    <script type="text/javascript">
        $(function() {
            var max = 0;
            $("label").each(function () {
                if ($(this).width() > max)
                    max = $(this).width();
            });
            $("label").width(max + 5);
        });
    </script>
    <style type="text/css">
        label {
            float: left;
        }
        input {
            margin: 2px;
        }
        [type=text], [type=password] {
            width: 150px;
        }
    </style>
</head>
<body>
    <div>
        <label for="name">Name:</label><input type="text" name="name"/><br/>
        <label for="email">Email:</label><input type="text" name="email"/><br/>
        <label for="password">Password:</label><input type="password" name="password"/><br/>
        <label for="confirmPassword">Confirm:</label><input type="password" name="confirmPassword"/><br/>
        <label for="newsletter">Email me about stuff!</label><input type="checkbox" name="newsletter"/>
    </div>
</body>
</html>

Okay, now we’re starting to look like a respectable form! We can make our form a little nicer by adding a fieldset control to house our controls, and we can add a label to controls through the fieldset’s legend. In order to facilitate auto-sizing of the fieldset–it’s 100% width by default–I moved the labels and inputs into a list, and that required another jQuery loop and some CSS. As final step, add more CSS to further improve aesthetics. For this example, I added a custom web font and made the fieldset legend bold and red.

PrettyForm

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script> 
    <script type="text/javascript">
        $(function() {
            var max = 0;
            $("label").each(function () {
                if ($(this).width() > max)
                    max = $(this).width();
            });
            $("label").width(max + 5);
            max = 0;
            $("fieldset").each(function() {
                $(this).find("li").each(function () {
                    var w = $(this).find("label").width() + $(this).find("input").width();
                    if (w > max)
                        max = w;
                });
                $(this).width(max + 10);
            });
         });
    </script>
    <link href='http://fonts.googleapis.com/css?family=Unkempt' rel='stylesheet' type='text/css'>
    <style type="text/css">
        body {
            font-family: 'Unkempt', sans-serif;
        }
        fieldset {
            margin: 10px;
            padding: 10px;
        }
            fieldset legend {
                font-weight: bold;
                color: maroon;
            }

            fieldset ul {
                margin: 0;
                padding: 0;
            }

            fieldset li {
                list-style: none;
                padding-bottom: 10px;
            }
        label {
            float: left;
        }
        input {
            margin: 2px;
        }
        [type=text], [type=password] {
            width: 150px;
        }
    </style>
</head>
<body>
    <fieldset>
        <legend>User Info</legend>
            <ul>
                <li><label for="name">Name:</label><input type="text" name="name"/></li>
                <li><label for="email">Email:</label><input type="text" name="email"/></li>
                <li><label for="password">Password:</label><input type="password" name="password"/></li>
                <li><label for="confirmPassword">Confirm:</label><input type="password" name="confirmPassword"/></li>
                <li><label for="newsletter">Email me about stuff!</label><input type="checkbox" name="newsletter"/></li>
            </ul>
    </fieldset>
</body>
</html>

Posting Data to an ASP.NET Page Method with Knockout

PostingDataToPageMethodWithKnockoutSample

Last time in my Knockout series of posts, I explored how to retrieve and bind data from an ASP.NET page method. That’s only half the battle, though. How can you take data captured and do interesting things with it? I’ve got an idea! How about passing it to an ASP.NET page method!

I’m going to use my example from last time with a few modifications. I added some entry controls to capture the user’s status, and I modified the GetStatus page method to return the user’s last status. The last status values will be displayed as read-only and will only be visible when a value exists. Here’s the ASPX and code-behind. Note that ASPX contains a button bound to a method in the view model that’s not yet implemented, and the code-behind has a UpdateStatus method.

default.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="adamprescott.net.Knockout.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-2.0.2.min.js"></script>
    <script src="Scripts/knockout-2.2.1.js"></script>
    <script type="text/javascript">
        $(function () {
            var viewModel = {
                wasHappy: ko.observable(),
                lastStatusText: ko.observable(),
                isCurrentlyHappy: ko.observable(),
                currentStatusText: ko.observable(),
                updateStatus: updateStatus,
            };
            ko.applyBindings(viewModel);
            getLastStatus();

            function updateStatus() {
                // todo: post data to page method
            }

            function getLastStatus() {
                $.ajax({
                    type: "POST",
                    url: "Default.aspx/GetStatus",
                    data: "{}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function (result) {
                        var data = result.d;
                        if (data == null) {
                            $("#lastTime").hide();
                            return;
                        }
                        $("#lastTime").show();
                        viewModel.wasHappy(data.HappyFlag);
                        viewModel.lastStatusText(data.Text);
                    }
                });
            }
        });
    </script>
</head>
<body>
    <div>
        <strong>How are you feeling?</strong><br/>
        Are you happy? <input data-bind="checked: isCurrentlyHappy" type="checkbox"/><br/>
        Tell me about it: <input data-bind="value: currentStatusText"/><br/>
        <button data-bind="click: updateStatus">Update Status</button>
    </div>
    <div id="lastTime">
        <strong>How you felt last time:</strong><br/>
        Were you happy? <input data-bind="checked: wasHappy" type="checkbox" disabled="true"/><br/>
        What you told me about it: <span data-bind="text: lastStatusText"></span>
    </div>
</body>
</html>

default.aspx.cs:

using System;
using System.Web.Services;

namespace adamprescott.net.Knockout
{
    public class Status
    {
        public bool HappyFlag { get; set; }
        public string Text { get; set; }
    }

    public partial class Default : System.Web.UI.Page
    {
        private static Status lastStatus = null;

        [WebMethod]
        public static Status GetStatus()
        {
            return lastStatus;
        }

        [WebMethod]
        public static void UpdateStatus(Status status)
        {
            lastStatus = status;
        }
    }
}

When the button is pressed, we need to collect values and put them into an object to be passed to our page method. That’s easy–just grab values from the view model:

var data = {};
data.HappyFlag = viewModel.isCurrentlyHappy();
data.Text = viewModel.currentStatusText();

Now that we’ve got our values, we just need to pass them to our page method. Once again, it’s jQuery to the rescue!

$.ajax({
    type: "POST",
    url: "Default.aspx/UpdateStatus",
    data: JSON.stringify({ 'status': data }),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function () {
        // todo: anything?
    }
});

Bam! We just passed data to the page method in the code-behind. Tutorial accomplished. However, I need to go a little further. Now that I just updated the status, I want my UI to update its view to show the latest status. So, when my call to UpdateStatus finishes successfully, I just need to make another call to GetStatus. Super easy!

Here’s the final ASPX.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="adamprescott.net.Knockout.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-2.0.2.min.js"></script>
    <script src="Scripts/knockout-2.2.1.js"></script>
    <script type="text/javascript">
        $(function () {
            var viewModel = {
                wasHappy: ko.observable(),
                lastStatusText: ko.observable(),
                isCurrentlyHappy: ko.observable(),
                currentStatusText: ko.observable(),
                updateStatus: updateStatus, 
            };
            ko.applyBindings(viewModel);
            getLastStatus();

            function updateStatus() {
                // todo: post data to page method
                return;
                var data = {};
                data.HappyFlag = viewModel.isCurrentlyHappy();
                data.Text = viewModel.currentStatusText();
                $.ajax({
                    type: "POST",
                    url: "Default.aspx/UpdateStatus",
                    data: JSON.stringify({ 'status': data }),
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function () {
                        getLastStatus();
                    }
                });
            }

            function getLastStatus() {
                $.ajax({
                    type: "POST",
                    url: "Default.aspx/GetStatus",
                    data: "{}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function (result) {
                        var data = result.d;
                        if (data == null) {
                            $("#lastTime").hide();
                            return;
                        }
                        $("#lastTime").show();
                        viewModel.wasHappy(data.HappyFlag);
                        viewModel.lastStatusText(data.Text);
                    }
                });
            }
        });
    </script>
</head>
<body>
    <div>
        <strong>How are you feeling?</strong><br/>
        Are you happy? <input data-bind="checked: isCurrentlyHappy" type="checkbox"/><br/>
        Tell me about it: <input data-bind="value: currentStatusText"/><br/>
        <button data-bind="click: updateStatus">Update Status</button>
    </div>
    <div id="lastTime">
        <strong>How you felt last time:</strong><br/>
        Were you happy? <input data-bind="checked: wasHappy" type="checkbox" disabled="true"/><br/>
        What you told me about it: <span data-bind="text: lastStatusText"></span>
    </div>
</body>
</html>

Databinding from an ASP.NET Page Method with Knockout

Last week, I wrote a brief post about how easy it is to do databinding with Knockout. The article presents a barebones example, but it fails to address an important issue: how to get data into the view model.

I live in a .NET world, and I’m usually working with small ASP.NET application. I’ve found that page methods are an easy and convenient way to get to the data I need. They’re easily accessible via jQuery, too. So let’s see how we can get data from an ASP.NET page method using jQuery and pass it along to our Knockout view model.

First, let’s get to know our page method. I created a simple Status class that will be returned from a page method, GetStatus. Here’s the entire code-behind for my page:

using System;
using System.Web.Services;

namespace adamprescott.net.Knockout
{
    public class Status
    {
        public bool HappyFlag { get; set; }
        public string Text { get; set; }
    }

    public partial class Default : System.Web.UI.Page
    {
        [WebMethod]
        public static Status GetStatus()
        {
            return new Status { HappyFlag = true, Text = "This just a default" };
        }
    }
}

We know what data we’re getting, so we can go ahead and create our view model and UI. Here’s what that looks like:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="adamprescott.net.Knockout.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-2.0.2.min.js"></script>
    <script src="Scripts/knockout-2.2.1.js"></script>
    <script type="text/javascript">
        $(function () {
            var viewModel = {
                isHappy: ko.observable(),
                statusText: ko.observable(),
            };
            ko.applyBindings(viewModel);
            
            // todo: get data from page method
        });
    </script>
</head>
<body>
    <input data-bind="value: statusText" /><br/>
    Happy? <input data-bind="checked: isHappy" type="checkbox" />
</body>
</html>

All that’s left is for us to do is call the page method and update the values in our view model. And, as I said before, jQuery makes it a snap!

$.ajax({
    type: "POST",
    url: "Default.aspx/GetStatus",
    data: "{}",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (result) {
        var data = result.d;
        viewModel.isHappy(data.HappyFlag);
        viewModel.statusText(data.Text);
    }
});

With that, we’re done. When the page loads, the view model is created and bound to the UI controls. We then make an asynchronous call to the page method using jQuery and update the values in our view model.

Here’s the complete ASPX file:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="adamprescott.net.Knockout.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-2.0.2.min.js"></script>
    <script src="Scripts/knockout-2.2.1.js"></script>
    <script type="text/javascript">
        $(function () {
            var viewModel = {
                isHappy: ko.observable(),
                statusText: ko.observable(),
            };
            ko.applyBindings(viewModel);
            
            $.ajax({
                type: "POST",
                url: "Default.aspx/GetStatus",
                data: "{}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (result) {
                    var data = result.d;
                    viewModel.isHappy(data.HappyFlag);
                    viewModel.statusText(data.Text);
                }
            });
        });
    </script>
</head>
<body>
    <input data-bind="value: statusText" /><br/>
    Happy? <input data-bind="checked: isHappy" type="checkbox" />
</body>
</html>

Two-Way Databinding with Knockout

Earlier this week, I wrote a post about two-way databinding with jQuery. I was looking for a fast & elegant way to do it, but I came up somewhat empty. A lot of what I was finding suggested using a different plug-in or framework, such as Knockout. I decided to give Knockout a whirl, and I’m an instant fan.

My favorite part is how the binding occurs declaratively in the HTML.

<input data-bind="checked: boolValue" type="checkbox" />
<input data-bind="value: textValue" />

That’s all you need to bind the values to the controls–nice, right!? Okay, but this is javascript, so what’s going on at the top? Surely, it’s a mess. Nope, it’s just as easy. Just create a view model and call Knockout’s applyBindings method.

var viewModel = {
    boolValue: ko.observable(true),
    textValue: ko.observable("Hello!")
};
ko.applyBindings(viewModel);

That’s it, I promise. To show that there’s nothing up my sleeve, here’s the entire page:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-2.0.2.min.js"></script>
    <script src="Scripts/knockout-2.2.1.js"></script>
    <script type="text/javascript">
        $(function () {
            var viewModel = {
                boolValue: ko.observable(true),
                textValue: ko.observable("Hello!")
            };
            ko.applyBindings(viewModel);
        });
    </script>
</head>
<body>
    <input data-bind="checked: boolValue" type="checkbox" />
    <input data-bind="value: textValue" />
    
    <div>The value of boolValue is <span data-bind="text: boolValue"></span></div>
    <div>The value of textValue is <span data-bind="text: textValue"></span></div>
</body>
</html>

The Knockout site has really good interactive tutorials for getting started. If you’re interested in learning or exploring further, definitely start there.

Two-Way Databinding with jQuery

I was working on a small data entry page and wanted to use jQuery to databind an object to my controls. I was expecting a simple command, like $(“#myControl”).databind(obj.Value), but was surprised to find that one did not exist. The Internet kept telling me to look elsewhere–mostly Knockout–but I was sure that this could be accomplished with jQuery alone.

It turns out that it is easy to do with jQuery, but it’s all manual. I created a function named databind and, for each control, I populate it with the desired property’s value and create an event handler to update the value when the control changes.

function databind() {
    var ctl;

    // a checkbox
    ctl = $("#uxMyCheckbox");
    ctl.attr('checked', model.BoolValue);
    ctl.change(function () { model.BoolValue = this.checked; });

    // a textbox
    ctl = $("#uxMyTextbox");
    ctl.val(model.TextValue);
    ctl.change(function () { model.TextValue = this.value; });
}

It’s not quite as elegant as I was hoping for, but it’ll do for now. I’ll probably check out Knockout for the future, though.