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>
Advertisement

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>

Credential-less Authentication in ASP.NET

There are times when you may wish to authenticate a user in an ASP.NET web application without requesting a password. For example, I was working on a client application that had a web counter-part. I needed to authenticate the user by using just their login. Fortunately, the .NET Framework gives us a simple way to accomplish this with the FormsAuthentication.SetAuthCookie method.

FormsAuthentication.SetAuthCookie("adam", true);

One nuance:

The forms-authentication ticket supplies forms-authentication information to the next request made by the browser.

This means you can’t call SetAuthCookie and then execute code that assumes an authenticated user on the next line. A simple workaround is to use a redirect.

%d bloggers like this: