Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Creating a Minimalistic Ajax CRM System with Gaia Ajax Widgets

3.00/5 (7 votes)
4 Sep 20072 min read 1   531  
An article about creating an Ajax CRM system using Gaia Ajax Widgets
Screenshot - gaia_ajax_crm.png

Introduction

Today virtually a million different Ajax Frameworks exist, and most of them want you to do a lot of JavaScript development. Gaia Ajax Widgets is different since it does not require you to learn JavaScript and the whole development process can be focused around an Event Driven application model.

Today we'll create a small Ajax Application featuring a minimalistic CRM system with an Ajaxified DataGrid which shows: the Customers in your "database", and a Modal Ajax Window which is for creating new Customers. When you finish this article you should be pretty well aquinted with Gaia Ajax Widgets and it's simple model for creating Ajax Solutions in ASP.NET.

Using the Code

Most of the code you see in this solution should be pretty well known to most ASP.NET developers. However, there are a couple of interesting points which should be emphasized. When you have non-Gaia controls and you wish to re-render in Ajax Callbacks you must wrap those controls inside any Gaia Container Widget (e.g. Gaia Panel, PlaceHolder, Window or any other Gaia Control that can contain chold controls). Then when you wish to re-render those controls you must call the ForceAnUpdate for the Gaia Ajax Container control to wrap "non-Ajax controls." An example of this can be seen when DataBinding the repeater in the code below.

C#
// Notice how we must FORCE an update of the Ajax Container Widget
// wrapping our Repeater...!
if (Manager.Instance.IsAjaxCallback)
    repeaterPlaceHolder.ForceAnUpdate();

Notice also that the featured Ajax Solution in this sample does not contain ONE single line of JavaScript! Also notice that everything is controlled using an Event Application Model. This means that everytime something happens in the core where you need to decide upon what to do, you will get an Event raised for which you can define an Event Handler.

The sample you see here uses these widgets:

  • Gaia Ajax Button
  • Gaia Ajax DropDownList
  • Gaia Ajax TextBox
  • Gaia Ajax DateTimePicker
  • Gaia Ajax RadioButtons
  • Gaia Ajax CheckBoxes
  • Gaia Ajax Window
  • Gaia Ajax DraggablePanel
  • Gaia Ajax PlaceHolder
  • ASP.NET Repater

Also, the code is heavily commented and should be pretty self explanatory, though if you have questions I'll try to monitor the forums section here and answer as frequently as possible. Have a nice day!

About Gaia Ajax Widgets

The download contains everything you need to open, code and run the solution. Gaia Ajax Widgets is Free and Open Source Software (GPL) which means you can create Open Source and Free software yourself without having to pay anything for the library. Though if you wish to create closed-source software you can also purchase a commercial license for using the library.

Codebehind of the Solution

C#
using System;
using System.Collections.Generic;
using Gaia.WebWidgets;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // If this is the initial hit on the page we build a default 
            // Database to show our user
            BuildDefaultDatabase();
            RebindRepeater();
        }
    }
#region DataGrid/Repeater stuff

    // This just re-databinds our ASP.NET Repeater and flush 
    private void RebindRepeater()
    {
        // Here we sort the Customers according to whatever value is selected 
        // in the Sorting DropDownList object...!
        Customers.Sort(
            delegate(Customer left, Customer right)
        {
            switch (sortDdl.SelectedValue)
            {
            case "Name":
                return left.Name.CompareTo(right.Name);
            case "Address":
                return left.Address.CompareTo(right.Address);
            case "BirthDate":
                return left.BirthDate.CompareTo(right.BirthDate);
            case "Male":
                return left.Male.CompareTo(right.Male);
            default:
                throw new ApplicationException("System error...!!");
            }
        });
        customerRep.DataSource = Customers;
        customerRep.DataBind();

        // Notice how we must FORCE an update of the Ajax Container Widget 
        // wrapping our Repeater...!
        if (Manager.Instance.IsAjaxCallback)
            repeaterPlaceHolder.ForceAnUpdate();
    }

    // Here we're building a default "database", note that in a real 
    // application you'd use an ACTUAL
    // database and NOT the Session object to store this data ,)
    private void BuildDefaultDatabase()
    {
        List list = new List();
        list.Add(new Customer(Guid.NewGuid(), "Thomas Hansen", 
            "Galactica 614", new DateTime(1974, 5, 16), true));
        list.Add(new Customer(Guid.NewGuid(), "Jan Blomquist", 
            "Astronomicum 792", new DateTime(1977, 12, 23), true));
        list.Add(new Customer(Guid.NewGuid(), "Stian Solberg", "Uranus 1161", 
            new DateTime(1977, 8, 11), true));
        list.Add(new Customer(Guid.NewGuid(), "Kariem Ali", "Milky Way 384", 
            new DateTime(1982, 4, 7), true));
        Session["customers"] = list;
    }
    private Customer GetCustomer(Guid id)
    {
        // Looping through to FIND the Customer
        Customer current = Customers.Find(
            delegate(Customer idx)
        {
            if (idx.Id == id)
                return true;
            return false;
        });
        return current;
    }
    // Returns the Id of the Customer inside the repeater item
    private static Guid GetCustomerId(
        System.Web.UI.WebControls.RepeaterItem repItem)
    {
        HiddenField idField = repItem.Controls[1] as HiddenField;
        Guid id = new Guid(idField.Value);
        return id;
    }
    // This method is being called by the OnTextChanged Event from our NAME 
    // TextBox
    protected void NameChanged(object sender, EventArgs e)
    {
        // Getting the control first...
        TextBox edit = (TextBox)sender;

        // Retrieving the Repeater row
        System.Web.UI.WebControls.RepeaterItem repItem = (
            System.Web.UI.WebControls.RepeaterItem)edit.Parent;

        // Finding current Customer
        Customer current = GetCustomer(GetCustomerId(repItem));

        // updating the Customers name...
        current.Name = edit.Text;
    }
    // This method is being called by the OnTextChanged Event from our NAME 
    // TextBox
    protected void AddressChanged(object sender, EventArgs e)
    {
        // Getting the control first...
        TextBox edit = (TextBox)sender;

        // Retrieving the Repeater row
        System.Web.UI.WebControls.RepeaterItem repItem = (
            System.Web.UI.WebControls.RepeaterItem)edit.Parent;

        // Finding current Customer
        Customer current = GetCustomer(GetCustomerId(repItem));

        // updating the Customers name...
        current.Address = edit.Text;
    }
    // This method is being called by the OnTextChanged Event from our NAME 
    // TextBox
    protected void BirthDateChanged(object sender, EventArgs e)
    {
        // Getting the control first...
        DateTimePicker edit = (DateTimePicker)sender;

        // Retrieving the Repeater row
        System.Web.UI.WebControls.RepeaterItem repItem = (
            System.Web.UI.WebControls.RepeaterItem)edit.Parent;

        // Finding current Customer
        Customer current = GetCustomer(GetCustomerId(repItem));

        // updating the Customers BirthDate...
        if (edit.Value.HasValue)
            current.BirthDate = edit.Value.Value;
    }
    protected void MaleCheckedChanged(object sender, EventArgs e)
    {
        // Getting the control first...
        RadioButton edit = (RadioButton)sender;

        // Retrieving the Repeater row
        System.Web.UI.WebControls.RepeaterItem repItem = (
            System.Web.UI.WebControls.RepeaterItem)edit.Parent;

        // Finding current Customer
        Customer current = GetCustomer(GetCustomerId(repItem));

        // updating the Customers Sex...
        current.Male = edit.Checked;
    }
    protected void FemaleCheckedChanged(object sender, EventArgs e)
    {
        // Getting the control first...
        RadioButton edit = (RadioButton)sender;

        // Retrieving the Repeater row
        System.Web.UI.WebControls.RepeaterItem repItem = (
            System.Web.UI.WebControls.RepeaterItem)edit.Parent;

        // Finding current Customer
        Customer current = GetCustomer(GetCustomerId(repItem));

        // updating the Customers Sex...
        current.Male = !edit.Checked;
    }
#endregion
    // Called when Sorting order changes...
    protected void sortDdl_SelectedIndexChanged(object sender, EventArgs e)
    {
        // Since all the logic happens with the Rebind method anyway we 
        // just dispatch this call to that method :)
        RebindRepeater();
    }
    // Shorthand accessor for our "Database"
    public List Customers
    {
        get { return (List)Session["customers"]; }
    }
    // This one is being called when the Create New Customer button is 
    // pushed...!
    protected void createNew_Click(object sender, EventArgs e)
    {
        // Showing Ajax Window just by setting it's Visible property to TRUE
        newCustomerWnd.Visible = true;
    }
    // This one is being called when the user is FINISHED creating a new 
    // Customer and clicks the "Create" button...!
    protected void createNewCustomer_Click(object sender, EventArgs e)
    {
        try
        {
            Customer n = new Customer();
            n.Name = newName.Text;
            n.Address = newAdr.Text;
            n.BirthDate = newDate.Value.Value;
            n.Male = newMale.Checked;
            newCustomerWnd.Visible = false;
            Customers.Add(n);
            RebindRepeater();
        }
        catch (Exception err)
        {
            Manager.Instance.AddScriptForClientSideEval("alert('something " + 
                "went wrong while trying to create new customer!" + 
                "Date error...??');");
        }
    }
}

The ASPX Code for the Solution

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

<!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>CodeProject Tutorial - A Minimalistic Ajax CRM system with 
        Gaia</title>

    <link href="mac_os_x.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <!-- This Button will make sure the Window becomes Visible when 
            clicked -->
        <gaia:Button 
            runat="server" 
            ID="createNew" 
            Text="Create new Customer"
            OnClick="createNew_Click" />
        
        <!-- Creating a Draggable Panel just for fun ;) -->        
        <gaiaExt:DraggablePanel 
            runat="server" 
            style="padding:35px;border:solid 1px 
                #aaa;background-color:#aaf;width:600px;cursor:move;"
                ID="dragger">
            Try to move me around...! ;)

            <!-- We must wrap our ASP.NET Repeater inside a Gaia Container  
                 Control (here the PlaceHolder) in order to be able to 
                 RE-render the Repeater in Gaia Ajax Callbacks...! -->
            <gaia:PlaceHolder 
                runat="server" 
                ID="repeaterPlaceHolder">
                <table style="background-color:#ddf;border:solid 1px 
                    #aaa;cursor:default;">
                    <asp:Repeater runat="server" ID="customerRep">

                        <ItemTemplate>
                            <tr>
                                <td>
                                    <gaia:HiddenField 
                                        runat="server" 
                                        Value='<%# DataBinder.Eval(
                                            Container.DataItem, "Id")%>' />
                                    <gaia:TextBox 
                                        runat="server" 
                                        AutoPostBack="true" 
                                        OnTextChanged="NameChanged"
                                        Text='<%# DataBinder.Eval(
                                            Container.DataItem, "Name")%>' />
                                </td>
                                <td>
                                    <gaia:TextBox 
                                        runat="server" 
                                        AutoPostBack="true" 
                                        OnTextChanged="AddressChanged"
                                        Text='<%# DataBinder.Eval(
                                          Container.DataItem, "Address")%>' />
                                </td>
                                <td>
                                    <gaia:DateTimePicker 
                                        runat="server" 
                                        CssClass="mac_os_x"
                                        HasDropDownButton="true" 
                                        Format="yyyy.MM.dd"
                                        Width="80px" 
                                        HasTimePart="false"
                                        AutoPostBack="true" 
                                        OnTextChanged="BirthDateChanged"
                                        Text='<%# ((DateTime)DataBinder.Eval(
                                            Container.DataItem, 
                                            "BirthDate")).ToString(
                                            "yyyy.MM.dd")%>' />
                                </td>
                                <td>
                                    <gaia:RadioButton
                                        runat="server" 
                                        GroupName="maleGroup" 
                                        Text="Male" 
                                        AutoPostBack="true" 
                                        OnCheckedChanged="MaleCheckedChanged"
                                        Checked='<%# DataBinder.Eval(
                                         Container.DataItem, "Male").Equals(
                                         true)%>' />
                                    <gaia:RadioButton
                                        runat="server" 
                                        GroupName="maleGroup" 
                                        Text="Female" 
                                        AutoPostBack="true" 
                                        OnCheckedChanged=
                                          "FemaleCheckedChanged"
                                        Checked='<%# !DataBinder.Eval(
                                          Container.DataItem, "Male").Equals(
                                              true)%>' />
                                </td>
                            </tr>
                        </ItemTemplate>
                    </asp:Repeater>
                </table>
            </gaia:PlaceHolder>

        </gaiaExt:DraggablePanel>

        <!-- Adding sorting to the Grid -->
        <gaia:DropDownList 
            runat="server" 
            ID="sortDdl" 
            AutoPostBack="true" 
            OnSelectedIndexChanged="sortDdl_SelectedIndexChanged">

            <asp:ListItem Text="Name" />
            <asp:ListItem Text="Address" />

            <asp:ListItem Text="BirthDate" />
            <asp:ListItem Text="Male" />

        </gaia:DropDownList>

        <!-- Actual Ajax Window, this is the declarative .aspx element 
            to create an Ajax Window which is Modal -->
        <gaia:Window 
            runat="server" 
            ID="newCustomerWnd" 
            Visible="false"
            CssClass="mac_os_x" 
            CenterInForm="true" 
            Width="450" 
            Modal="true"
            Height="200">

            <table style="margin:15px;border:solid 1px #ccc;">
                <tr>
                    <td>Name: </td>
                    <td>
                        <gaia:TextBox 
                            runat="server" 
                            ID="newName" />
                    </td>
                    <td>Birth Date: </td>
                    <td>
                        <gaia:DateTimePicker 
                            runat="server" 
                            CssClass="mac_os_x"
                            HasDropDownButton="true" 
                            Format="yyyy.MM.dd"
                            Width="80px" 
                            HasTimePart="false"
                            Text="1982.01.01"
                            ID="newDate" />
                    </td>
                </tr>
                <tr>
                    <td>Address: </td>
                    <td>
                        <gaia:TextBox 
                            runat="server" 
                            ID="newAdr" />
                    </td>
                    <td>Male: </td>
                    <td>
                        <gaia:CheckBox
                            runat="server" 
                            ID="newMale" />
                    </td>
                </tr>
                <tr>
                    <td colspan="4" style="text-align:right;">
                        <gaia:Button 
                            runat="server" 
                            ID="createNewCustomer" 
                            OnClick="createNewCustomer_Click"
                            Text="Create" />
                    </td>
                </tr>
            </table>
        </gaia:Window>
    </div>
    </form>
</body>
</html>

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here