Friday, March 30, 2012

ASP.NET MVC 3 - Converting / Serializing .Net objects into JSON format in View


In ASP.NET MVC often we might need to use / manipulate Model objects or its property inside the javascript. In order to achieve that, we usually try to serialize the .Net object and store it in a javascript variable which will then be accessed further in javascript.

Using Razor view engine, we can achieve this easily. In the following, I'll explain two approaches with a simple View(.cshtml) snippet to understand the concept. 

Approach 1: (Using Json.Encode(...))

Snippet 1: (Index.cshtml)

@model Web.POC.Models.FeedModel
@{
    ViewBag.Title = "Feed viewer";
}

<script type="text/javascript">
    var entries = @Html.Raw(Json.Encode(Model.FeedEntries));    
</script>


Approach 2: (Using JavaScriptSerializer)

Snippet 2: (Index.cshtml)

@model Web.POC.Models.FeedModel
@{
    ViewBag.Title = "Feed viewer";
}

@{
   System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
}
<script type="text/javascript">
    var entries = @Html.Raw(serializer.Serialize(Model.FeedEntries));    
</script>


Assumptions:

As specified, the above snippets are just to understand the concept. In that, consider that we're having a model "FeedModel" which holds a property called "FeedEntries" of some custom type which we're trying to convert into JSON object.

Also note that we need to use the HTML.Raw() to indicate that the output should not be HTML encoded.


Monday, March 12, 2012

ASP.NET - Avoid multiple postbacks for control set using validators by disabling the button


In ASP.NET disabling the button when a postback got initiated through button click and avoiding multiple postbacks or submits until the specific response is processed is one of the common thing that we need to implement. This is especially  needed for some long running operations. During my initial days, I achieve this as specified here. Later, I followed as specified here in an article by Abhijit Jana. Few days back one of my friend asked me about how to disbale the button to avoid multiple submits / postbacks for control set that are using ASP.NET validation. To achieve that, I tried a sample and came up with two approaches.

Let us consider a scenario that we have a text box, a required field validator and button tied together using validation group.

Approach 1: (Using jQuery and a button proxy)

  • Apply CSS style="display:none;"  to the button you want to disable.
  • Include a new button for display purpose and add a jQuery that validates the validation group using the function Page_ClientValidate() passing the validationgroup as parameter. 
  • Based on the return value of Page_ClientValidate(), raise the click event of the hidden button using jQuery and disable the display button. 
The following script snippet helps us to achieve that.

Snippet 1:(script)

<script type="text/javascript">
    $(document).ready(function () {
        initAction();
    });

    function initAction() {
        $('#Button2').click(function (event) {
            event.preventDefault();

            if (Page_ClientValidate('ValGroup1')) {
                this.disabled = true;
                $('#Button1').click();
            }

        });
    }
</script>


Here is the full implementation of the same.

Snippet 2:(DisableButtonOnClickApp1.aspx)

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            initAction();
        });

        function initAction() {
            $('#Button2').click(function (event) {
                event.preventDefault();

                if (Page_ClientValidate('ValGroup1')) {
                    this.disabled = true;
                    $('#Button1').click();
                }

            });
        }
    </script>

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <table border="0" cellpadding="0" cellspacing="0">
            <tr>
                <td>
                    <asp:Label ID="Label1" runat="server" Text="Label 1 : "></asp:Label>
                </td>
                <td>
                    <asp:TextBox ID="TextBox1" runat="server" ValidationGroup="ValGroup1"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="RequiredFieldValidator"
                        ControlToValidate="TextBox1" ValidationGroup="ValGroup1"></asp:RequiredFieldValidator>
                </td>
            </tr>
            <tr>
                <td colspan="2" style="text-align: center;">
                    <asp:Button ID="Button1" runat="server" Text="Hide Button" Style="display: none;"
                        ValidationGroup="ValGroup1" onclick="Button1_Click" />
                    <asp:Button ID="Button2" runat="server" Text="Display Button" />
                </td>
            </tr>
            <tr>
            <td colspan="2" style="text-align: center;">
                <asp:Label ID="StatusMessageLabel" runat="server" Text=""></asp:Label>
            </td>
            </tr>
        </table>
    </div>
    </form>
</body>
</html>


Snippet 3:(DisableButtonOnClickApp1.aspx.cs)

public partial class DisableButtonOnClickApp1 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        StatusMessageLabel.Text = "Button 1 click .......";
    }
}


If you are not much interested in using one additional control to achieve this, the following approach might help you.

Approach 2: (Using GetPostBackEventReference with PostBackOptions and UseSubmitBehavior)

The idea for this approach evolved from the article I specified above. Following snippets helps you to understand the implementation easily. Here we're going to use ClientScript.GetPostBackEventReference with PostBackOptions and Button.UseSubmitBehavior to achieve the resultant.

Snippet 4: (DisableButtonOnClickApp2.aspx.cs)

public partial class DisableButtonOnClickApp2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        DisableButtonOnClick(Button1, "ValGroup1");
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        StatusMessageLabel.Text = "button 1 click......";
    }

    private void DisableButtonOnClick(Button buttonControl, string validationGroup)
    {
        StringBuilder disableButtonScriptBuilder = new StringBuilder();
        PostBackOptions postBackOptions = new PostBackOptions(buttonControl);

        postBackOptions.ValidationGroup = validationGroup;
        postBackOptions.Argument = "";
        postBackOptions.PerformValidation = true;
        postBackOptions.ActionUrl = "";
        postBackOptions.TrackFocus = false;
        postBackOptions.ClientSubmit = false;
        postBackOptions.RequiresJavaScriptProtocol = true;

        disableButtonScriptBuilder.Append(ClientScript.GetPostBackEventReference(postBackOptions, false));
        disableButtonScriptBuilder.Append("; if(Page_ClientValidate('");
        disableButtonScriptBuilder.Append(validationGroup);
        disableButtonScriptBuilder.Append("')){this.value='Processing...';this.disabled = true;}");

        //buttonControl.OnClientClick = ClientScript.GetPostBackEventReference(postBackOptions, false) + "; if(Page_ClientValidate('" + validationGroup + "')){this.value='Processing...';this.disabled = true;}";
        buttonControl.OnClientClick = disableButtonScriptBuilder.ToString();
        buttonControl.UseSubmitBehavior = false;
    }
}

Snippet 5: (DisableButtonOnClickApp2.aspx)

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <table border="0" cellpadding="0" cellspacing="0">
            <tr>
                <td>
                    <asp:Label ID="Label1" runat="server" Text="Label 1 : "></asp:Label>
                </td>
                <td>
                    <asp:TextBox ID="TextBox1" runat="server" ValidationGroup="ValGroup1"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="RequiredFieldValidator"
                        ControlToValidate="TextBox1" ValidationGroup="ValGroup1"></asp:RequiredFieldValidator>
                </td>
            </tr>
            <tr>
                <td colspan="2" style="text-align: center;">
                    <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
                </td>
            </tr>
            <tr>
            <td colspan="2" style="text-align: center;">
                <asp:Label ID="StatusMessageLabel" runat="server" Text=""></asp:Label>
            </td>
            </tr>
        </table>
    </div>
    </form>
</body>
</html>


Based on your comfort, use any of the above two approaches.
Creative Commons License
This work by Tito is licensed under a Creative Commons Attribution 3.0 Unported License.