Click here to Skip to main content
Click here to Skip to main content

A pragmatic introduction to DOJO for form based CRUD database operations with ASP.NET

, 20 Jul 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
A pragmatically introduction to DOJO for form based CRUD database operations with ASP.NET

Overview  

In this introduction I will show you how to create a web based form for database CRUD (Create Read Update Delete) operations based on Dojos datagrid. The data editing is done in a popup frame, not directly in the grid. The datagrid form supports keyboard navigation (cursor, Enter for edit, Delete for record deletion and F2 for adding a new record). This article is based on what I learned while using Dojo for implementing a CRUD web based system. Maybe some is wrong or misinterpreted by me, so please don’t hesitate to contact me if you find any errors or have suggestions. 

In the “using the code” section you will find how to use the code to implement a simple company phone list application in less than 90 minutes.

This is how it will look like :

This is a screenshot of editing a record:

Download the Visual Web Developer Express 2010 Solution of the general introduction 

Introduction   

As a programmer you face very often the task to create forms for data editing that are used by users with different levels of computer experience. Nearly every user is able to browse the Internet, so it is widely common to use web based systems instead of desktop applications, especially in business environments.

This article will show you how to use the Dojo JavaScript framework to build a simple data create/read/update /delete operations (CRUD) form .
 

 

Background 

I was looking for a way to create web based (ASPX on IIS) forms for CRUD database operations.

Key requirements to the framework 

I had four key requirements

  • The data should be shown in some kind of data grid with keyboard navigation support 
  • The operations should not generate a full postback on saving/deleting items
  • Editing should be done in a popup window. Inline editing should be possible too
  • The used framework should have an open license, so it should be free to use 

On the list of evaluated frameworks I had nearly all free frameworks (JavaScript or ASPX based).

The grid control the in the default aspx controls was not what I was thinking about. The main missing feature was the keyboard navigation. Another drawback was that the users experience of the default grid control is far beyond a desktop grid.

I evaluated several grid controls for JQuery which and noticed every grid had its pros & cons. I didn’t found one that does all the tasks for me, especially the inline editing seems to be a huge issue.

DHTMLX is nearly the perfect toolkit, it’s running at client side, has dozens of controls, is very mature and has a healthy support forum. The only bad thing about it is its license. It’s free for GPL’d projects, but I can’t go this way all the time. If you have a budget for it, give it a try, it has nearly every base feature you need for normal operations and is very customizable, you won’t be sorry. 

Dojo is a JavaScript toolkit that runs at client side and had nearly all features I was looking for and as an extra it offers a lot of other controls. It is licensed: “Academic Free License >= 2.1 OR the modified BSD license” which is more than perfectly for my use case. It seems to be very mature but it lacks a little of documentation. The online documentation is quite ok but there are no books about Dojo available that cover the current version. I did a few prototypes that cover inline editing as well as editing in a popup window. This article is focused on editing in a popup window. 

Dojo has three main objects, dojo that has the common methods, dijit the user interface object and dojox that covers addition dojo projects like grids and charting. (This article is about dojox.grid) 

Referencing dojo in your html/aspx page

Dojo has to be referenced together with it’s style files to the head tag of your html file.
The default CSS style is named claro. No other references are required to use Dojo. Needed modules are defined later and loaded by Dojo internally. This makes Dojo very different than other JavaScript frameworks where you have to include every .js file which modules you use.

Building the user interface

In Dojo you have the option to build the UI using html like tags or create JavaScript objects at runtime. I’ve chosen to create the grid and toolbar at runtime in JavaScriptand just added a few divs and a span as a placeholder for the controls.
I placed an additional toolbar at the top of the screen with buttons to Add, Edit and Delete records.
(The toolbar object is defined in dijit/Toolbar)

The popup where the user is working on the data is realized as an Dojo dijit/Dialog object that shows a separate aspx page that handles the code for adding and update the data to the database and calls a JavaScript function in case of saving o.k. or error.
 


Getting the data to the grid

Dojo provides an abstraction layer for data that should be bound to controls with an object in dojo.data depending if it should be writable or read only. This abstraction layer is able to handle paging, loading on demand and has several other features. In most cases I experience a number of records between a few dozens to a few hundreds, so I decided to load all records on page load and work with them. Due to the fact that we use AJAX callbacks, there is no need to reload the whole page, so we do o.k. from a performance view. But if you are expecting huge datasets please check the dojo.data section in the documentation. 

This sample contains a small SqlCE database called Customers.sdf (located in the App_Data folder) which contains one table for the customers. On the “page load” event all records are fetched, and injected to the JavaScript code.  

Sorting the data 

Dojos grid supports sorting on clicking on the table header columns like nearly all grid controls. The sorting is done at client side but it’s case sensitive by default, which is very uncommon. This means you have A to Z in capital letters at the top, than the lower cased a to z. To make the sort behavior the expected order a custom comparator has to be implemented on datastore (not the grid) level.

Getting rid of the mouseover in the grid 

The grid controls CSS style defines a mouseover bar that looks pretty but does not work in my scenario (not from in a technical way, it irritates the user on identifying which row is currently selected). I tried to overwrite the style dynamically as well as statically in my aspx page without success. So it ended up that I edited the CSS file “claroGrid.css” directly to hide the mouseover bar.
 

KeyBoard navigation

The grid supports row selection using the cursor keys once it has the focus. I added additional event handlers to capture the enter key stroke to open the edit popup. In dojo this is done by using the dojo.connect function.   

Delete a record 

The deletion process at database level is done in a separate aspx page which is provided with the record id as id URL parameter. The page is called via JSONP and will report it’s result by “OK:” or something else that is displayed to notify the user. This could be implemented to the edit record page but I decided to have it separate to make the code more readable. 

 

Database connectivity

I used a “SQL Server Compact Edition” database file for this project. If you have trouble accessing it, please check if you have installed the 3.5 version to your server/development machine.


I will provide a download link in the references section below.

I had to add code to the global.asax to make the database file accessible to ASP.NET .
   

Interesting code segments (in order of appearance in the sources)

I will explain important or interesting code segments in this section.
 

Variables

I declared this global variable in my JavaScript:

var deleteUrl = "./services/DeleteCustomer.aspx";
var editUrl = "./services/EditCustomer.aspx";
var gridColumns = [  // name is the column name, field is the fieldname in the store 
                    { name: "ID", field: "CustomerID", width: "50px" },
                    { name: "CompanyName", field: "CompanyName", width: "auto", editable: false },
                    { name: "ContactTitle", field: "ContactTitle", width: "auto", editable: false },
                    { name: "ContactName", field: "ContactName", width: "auto", editable: false },
                    { name: "Address", field: "Address", width: "auto", editable: false },
                    { name: "City", field: "City", width: "auto", editable: false },
                    ] ;
var idColumnName = "CustomerID"; 
var defaultSortField = "CompanyName";
var defaultSortDescending = false;
var caseInsitiveSortedColumns =["CompanyName","ContactTitle"...]; // !*** Add columns that should be sorted case insensitive here !
var popUpDialogWidth = "600px";         // Height of the popup Dialog
var popUpDialogHeight = "380px";        // Width of the popup Dialog
var popUpDialogIframeWidth = "100%";   // It's not necessary to adjust this
var popUpDialogIframeHeight = "330px"; // Adjust this if you change the Dialogs height
var gridData= <%=Daten%>
 

The deletUrl and the editUrl are the URL addresses that points to the web pages that are used as a data service.

The gridColumns Array defines the data store and the grid layout. Possible options in this array:
 

  • name -> The displayed column title in the header of the grid
  • field -> The name of the data field provided by the injected JavaScript (see customer.aspx.cs)
  • width -> The width of the column (possible values: 50px, auto)
  • editable -> Indicates if the cells value is editable in the grid (false for this project) 

The idColumnName gets the name of the id data field used in all services. (It’s essential that this is the same in all services aspx files!) 

The defaultSortField gets the name of the data field that should be used for the default sorting within the grid after loading, the variable defaultSortDescending indicates the sort direction.

As mentioned earlier, Dojo sorts by default case sensitive the grids values. All columns, that should be sorted case insensitive have to be added with their display name to the array caseInsensitiveSortedColumns.

Loading Dojo modules

Loading the Dojo modules will be done using the require method that Dojo provides and will automatically create instances of the module objects available in a function that is called directly after the module loading that can be used for initialization: 

require([   "dojox/grid/DataGrid", 
            "dojo/data/ItemFileWriteStore", 
            "dojo/date/locale", 
            "dojo/_base/lang", 
            "dijit/form/HorizontalSlider", 
            "dojox/grid/cells/dijit", 
            "dojox/grid/Selection", 
            "dojo/store/JsonRest", 
            "dojo/store/Memory", 
            "dojo/store/Cache", 
            "dojo/data/ObjectStore", 
            "dojo/query", 
            "dijit/Toolbar", 
            "dijit/form/Button", 
            "dojo/_base/array", 
            "dojo/parser", 
            "dijit/layout/ContentPane", 
            "dijit/layout/BorderContainer", 
            "dijit/Dialog", 
            'dojo/data/ItemFileWriteStore', 
            'dojo/io/script'
        ],
function (  DataGrid, 
            ItemFileWriteStore, 
            locale, 
            lang, 
            HorizontalSlider, 
            Cells_dijit, 
            Selection, 
            JsonRest, 
            Memory, 
            Cache, 
            ObjectStore, 
            query, 
            Toolbar, 
            Button, 
            array, 
            parser, 
            cContentPane, 
            borderContainer, 
            dialog, 
            ItemFileWriteStore, 
            Script)
{ .... });

Please note that the name of the objects that are generated are defined in the function parameter.

Creating the toolbar

The toolbar is created by using the following code and can easily extended by adding new buttons to the array buttonDefinition :

// Create the toolbar buttons based on the definition in this array
// format: id, label, image
var buttonDefinition = [
                        ["new", "New", "NewPage"],
                        ["edit", "Edit", "Copy"],
                        ["delete", "Delete", "Delete"]
                        ];
toolbar = new Toolbar({}, "toolbar"); // The last parameter defines the span tag that takes the toolbar

array.forEach(buttonDefinition, function (but)
{
    var button = new Button(
    {
        // Note: The Dojo docu says buttons should always specify a label for accessibility reasons.
        // To hide the label just set showLabel:false
        label: but[1],
        showLabel: true,
        iconClass: "dijitEditorIcon dijitEditorIcon" + but[2],
        id: but[0],
        onClick: toolbarButtonClick
    });
    toolbar.addChild(button);
});

The images to the buttons are provided by the Dojo framework, no additional image files are needed, they are bundled with the Dojo framework.
 

Creating the data store for the grid

The grids data store is created by just using one line of code using the data that is fetched by the aspx.cs file and injected as an JavaScript array into the global variable gridData. 

gridStore = new ItemFileWriteStore({ data: gridData });

Make the column sorting case insensitive

To make columns sorting case insensitive, two things are needed: 

  • A comparator Map for the grid store
  • The comparator function itself 
 

Setting up the comparatorMap is done by this code: 

// Create the case insensitive columns comparator
gridStore.comparatorMap={};
array.forEach(caseInsitiveSortedColumns, function (colName)
{
    gridStore.comparatorMap[colName] = caseInsensitiveComparator;
});

The inner function is looping through the list of Column Names that should be sorted case insensitive and adds a comparator for this column to the comparatorMap.
 

The implementation of the comparator compares two values and returns a numeric value smaller, equal or greater than zero based on the comparison:

function caseInsensitiveComparator (a,b) 
{
    if (a.toLowerCase() < b.toLowerCase())
    {
        return -1
    } 
    else if (a.toLowerCase() > b.toLowerCase()) 
    {
        return 1;
    }
    else 
    {
        return 0;
    }
} 

The most important point is that the strings will be converted to lower case before comparing them.

Create the grid (finally)

Creating the grid is done by instantiating a new DataGrid object and defining to which html div tag the grid should be added:
grid = new DataGrid(
{
    "class": "grid",
    rowsPerPage: "10000",
    width: "auto",
    store: dataStore = gridStore,
    sortFields:[{attribute:defaultSortField,descending: defaultSortDescending}],
    structure: gridColumns  // The column setup
}, "grid"); // grid is the HTML div tag where we create the grid in

The parameters are self-explaining the only two things to note are the store assignment, where we assign the previous generated store object and the structure assignment which gets the data from the global variable array named gridColumns.

Adding keyboard event handlers

Event handler in Dojo will be added to controls using the dojo.connect method. I added handler for the Enter key, the Delete key and the F2 key.

dojo.connect(grid, "onKeyPress", function (e)
{
    switch(e.charOrCode)
    {
        case dojo.keys.ENTER:
        {
            ...
            break;
        }
        case dojo.keys.DELETE:
        {
            ...
            break;
        }
        case dojo.keys.F2:
        {
            ...
            break;
        }
    }
});  


Using the code  

In this section I will show how to use the code by creating a simple company intranet phone list which stores the employees name, the surname, the office number and the internal phone number:

Download the complete Visual Web Developer Express 2010 Solution of the Company Phone List


Needed files

To implement the code you need to download the zip file “Dojo-CRUD-Sample.zip” and unzip it somewhere to your file system. (Alternatively you could download the “CompanyPhoneList.zip” which contains complete “Microsoft Visual Web Developer 2010 express” solution.
The steps below assumes that you work with the “Dojo-CRUD-Sample.zip” )
 


Preparing the project

Create a new blank project named CompanyPhoneList in Visual Studio or Visual Web Developer. The programming language selection should be set to C#. (In Visual Studio 2010 you should select “Empty ASP.NET-Webapplication” ).  

Copy the dojo folder from the downloaded and extracted zip file by dragging it to the solution explorer and drop it on the project name. (If you use Visual Studio instead of Visual Web Developer make sure you drop it on the project, not the solution. In Visual Studio your solution could have more than one project.) 

Do the same thing for the css folder to have style sheet information for the pages.

Right click on the project in the solution explorer and select Add -> ASP.NET-Folder -> App_Data
This folder will hold the XML file we use as a database called PhoneList.xml .

Right click again on the project in the solution explorer and click on Add -> New folder and name it “services” .

Add three additional websites, one for the phone list, one for the data edit service and a third one for the record deletion service. In theory both service functions could be implemented in one page, but I prefer to have it separate. We will need these files:

 

Name 

Location 

Purpose

CompanyPhoneList.aspx

/

Main phone list page 

CompanyPhoneList_Edit.aspx

/services/

Saving edited/new records 

CompanyPhoneList_Delete.aspx

/services/

Deletion of records 

 

Your solution should now look like this (Your result may vary a little depending on your Windows/VS/VWD language, mine is German): 

 

You might want to right click on the “CompanyPhoneList.aspx” file and select “make it startup page”.

CompanyPhoneList.aspx

In the CompanyPhoneList.aspx.cs file we start implementing the needed database access functionality. Internally we work with a DataTable that is stored in (serialized to) the App_Data folder. If the file does not exist the Page will create a new blank database. 

 

Replace the whole source code except the class definition by this code (Overwrite any existing PageLoad event handler): 

public string dataInJsArrayFormat = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
    DataTable dtData;
    string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
    try
    {
        if (!Page.IsPostBack)
        {
            if (File.Exists(databaseFileName))
            { // Load existing database
                dtData = new DataTable();
                dtData.ReadXml(databaseFileName);
            }
            else
            { // Create new database
                dtData = new DataTable("PhoneList");
                dtData.Columns.Add(new DataColumn("id", typeof(Int32)));
                dtData.Columns[0].AutoIncrement = true;
                dtData.Columns[0].AutoIncrementSeed = 1;
                dtData.Columns[0].AutoIncrementStep = 1;
                dtData.Columns.Add(new DataColumn("name", typeof(String)));
                dtData.Columns.Add(new DataColumn("surname", typeof(String)));
                dtData.Columns.Add(new DataColumn("officeNo", typeof(String)));
                dtData.Columns.Add(new DataColumn("phoneNo", typeof(String)));
                dtData.WriteXml(databaseFileName, XmlWriteMode.WriteSchema);
            }
            // Database is existing now, read it and response as JS array

            StringBuilder sbResult = new StringBuilder();
            int rowCounterExported = 0;
            foreach (DataRow dr in dtData.Rows)
            {
                rowCounterExported++;
                if (rowCounterExported > 1)
                    sbResult.Append(",");
                sbResult.Append("{" + enq("id") + ":" + enq(dr["id"].ToString()) + ",");
                sbResult.Append(enq("name") + ":" + enq(dr["name"].ToString()) + ",");
                sbResult.Append(enq("surname") + ":" + enq(dr["surname"].ToString()) + ",");
                sbResult.Append(enq("officeNo") + ":" + enq(dr["officeNo"].ToString()) + ",");
                sbResult.Append(enq("phoneNo") + ":" + enq(dr["phoneNo"].ToString()) );
                sbResult.Append("}");
            }
            string resultText = " { identifier: 'id', label: 'CompanyPhoneList', items:[";
            resultText += sbResult.ToString();
            resultText += "]}";
            dataInJsArrayFormat = resultText;
        }
    }
    catch (Exception eX)
    {
        Response.Write("Error:" + eX.Message);
    }
}
// Enquotes a given String and encodes the new lines and encodes the quotes as well as double quotes
private string enq(string txt)
{
    string result = txt.Replace("\"", "\\\"");
    result = result.Replace("\'", "\\\'");
    result = result.Replace("\n", "\\\n");
    result = result.Replace("\r", "\\\r");
    return "\"" + result + "\"";
} 

The source code is pretty forward and self-explaining. All it does is to load or create a ADO.NET DataTable from a XML file.
Let the IDE fix all unresolved references with the right using statements. After that a build should do without any error. Now switch to the CompanyPhoneList.aspx in source code view.
 

Open the unzipped Customers.aspx in an editor of your choice and copy everything starting at the “<head” tag to the clipboard and paste it and replace everything in In the CompanyPhoneList.aspx starting at the “<head” tag. 

Do the following modifications:   

  • At the <title> tag add the text CompanyPhoneList
  • Update the assignments of the service url
    var
    deleteUrl = "./services/CompanyPhoneList_Delete.aspx";
    var
    editUrl = "./services/CompanyPhoneList_Edit.aspx";
     
  • Change the assignment of the gridColumns value to:
    var
    gridColumns = [

    { name: "Surname",field: "surname", width: "auto", editable: false },

    { name: "Name",field: "name", width: "auto", editable: false },

    { name: "Officeno", field: "officeNo",width: "auto", editable: false },

    { name: "Phone no", field: "phoneNo", width: "auto", editable: false}

    ];
  • Update the idColumnName assignment
    var
    idColumnName = "id";

  •  Update the default sort field assignment

    var defaultSortField = "Surname"; 

  • Update the caseInsitiveSortedColumns
    var caseInsitiveSortedColumns =["surname","name","officeNo","phoneNo"];

  • Change the gridData assignment to this value:
    var gridData= <%=dataInJsArrayFormat%>; 

Pressing Ctrl-F5 should build and run the solution show up an empty grid if everything went fine. 


CompanyPhoneList_Edit.aspx

Add this JavaScript code to the head element of the .aspx page for the edit popup, this will set the focus to the element at parameter:

<script language="javascript" type="text/javascript">
    function setFocusAndSelectText(elemntName)
    { //Set the focus and to the Company Name field and select it's content
        document.getElementById(elemntName).focus();
        document.getElementById(elemntName).select();
    }
</script> 

Replace the existing body tag by this one which does focus and select the value in the
surname textbox:

<body onload="window.setTimeout('setFocusAndSelectText(\'tbSurname\');',200);">

Remove the existing div tag from the form tag (if any was created by VS) and add this tags to the form tag: 

<asp:Panel runat="server" ID="pnSurname" GroupingText="Surname">
<asp:TextBox ID="tbSurname" runat="server" AutoComplete="Off" Width="95%"></asp:TextBox><asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="tbSurname" ErrorMessage=" *" ForeColor="Red" Font-Bold="true"></asp:RequiredFieldValidator>
</asp:Panel>
<asp:Panel runat="server" ID="pnName" GroupingText="Name"><asp:TextBox ID="tbName" runat="server"  AutoComplete="Off" Width="95%"></asp:TextBox></asp:Panel>
<asp:Panel runat="server" ID="pnOfficeNo" GroupingText="Office no"><asp:TextBox ID="tbOfficeNo" runat="server" AutoComplete="Off" Width="95%"></asp:TextBox></asp:Panel>
<asp:Panel runat="server" ID="pnPhoneNo" GroupingText="Phone no"><asp:TextBox ID="tbPhoneNo" runat="server"  AutoComplete="Off" Width="95%"></asp:TextBox></asp:Panel>  
<asp:Panel ID="Panel1" runat="server" Width="100%" HorizontalAlign="Right">
<br />
<asp:Button ID="btSave"  runat="server" Text="SAVE" onclick="btSave_Click" />
</asp:Panel>

This will add a panel with a description and an input field to the popup. 


Next we have to add code to the CompanyPhoneList_Edit.aspx.cs file. Add this code to the automatic generated Page_Load event it will load the record that should be edited:

DataTable dtData;
string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
try
{
    string id2Edit = string.Empty;
    try
    {
        id2Edit = Request.Params["id"].ToString();
    } 
    catch { }
    if ((!Page.IsPostBack) && (!String.IsNullOrEmpty(id2Edit)))
    {
        if (File.Exists(databaseFileName))
        { // Load existing database
            dtData = new DataTable();
            dtData.ReadXml(databaseFileName);
            DataRow[] dr = dtData.Select("id = " + id2Edit);
            if ((dr != null) && (dr.Length == 1))
            {
                tbName.Text = dr[0]["name"].ToString();
                tbSurname.Text = dr[0]["surname"].ToString();
                tbOfficeNo.Text = dr[0]["officeNo"].ToString();
                tbPhoneNo.Text = dr[0]["phoneNo"].ToString();
            }
            else
            { // record not found
                Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Record not found, maybe already deleted!\");", true);
            }
        }
        else
        {
            Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Record not found, maybe already deleted!\");", true);
        }
    }
}
catch (Exception eX)
{
    Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Error:" + eX.Message + "\");", true);
}


This is the code that does the actual save process that has to be inserted below the
Page_Load event:
 

protected void btSave_Click(object sender, EventArgs e)
{
    DataTable dtData;
    string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
    try
    {
        string id2Edit = string.Empty;
        bool newRecordAdded = false;
        try
        {
            id2Edit = Request.Params["id"].ToString();
        }
        catch { }
        if (File.Exists(databaseFileName))
        { // Load existing database
            dtData = new DataTable();
            dtData.ReadXml(databaseFileName);
            if (!String.IsNullOrEmpty(id2Edit))
            {
                DataRow[] dr = dtData.Select("id = " + id2Edit);
                if ((dr != null) && (dr.Length == 1))
                {
                    dr[0]["name"] = tbName.Text;
                    dr[0]["surname"] = tbSurname.Text;
                    dr[0]["officeNo"] = tbOfficeNo.Text;
                    dr[0]["phoneNo"] = tbPhoneNo.Text;
                    dtData.AcceptChanges();
                }
                else
                { // record not found
                    Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Record not found, maybe already deleted!\");", true);
                }
            }
            else
            { // Add new record
                newRecordAdded = true;
                DataRow drNew = dtData.NewRow();
                drNew["name"] = tbName.Text;
                drNew["surname"] = tbSurname.Text;
                drNew["officeNo"] = tbOfficeNo.Text;
                drNew["phoneNo"] = tbPhoneNo .Text;
                dtData.Rows.Add(drNew);
                dtData.AcceptChanges();
                id2Edit =  drNew["id"].ToString();
            }
            // Save the database file
            dtData.WriteXml(databaseFileName, XmlWriteMode.WriteSchema);
            // Database is writen to disk, create the JSON Javascript answer object (array) that transmits all entered values to the grids page to update the view
            StringBuilder sb = new StringBuilder();
            sb.Append("{ \"name\" : \"");
            sb.Append(encodeJsonSpecialChars(tbName.Text));
            sb.Append("\",\"surname\":\"");
            sb.Append(encodeJsonSpecialChars(tbSurname.Text));
            sb.Append("\",\"officeNo\":\"");
            sb.Append(encodeJsonSpecialChars(tbOfficeNo.Text));
            sb.Append("\",\"phoneNo\":\"");
            sb.Append(encodeJsonSpecialChars(tbPhoneNo.Text));
            sb.Append("\",\"id\":\"");
            sb.Append(id2Edit.ToString());
            sb.Append("\"}");
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "ret", "retVal=" + sb.ToString(), true);
            if (newRecordAdded == true)
                Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.newRecordSaved(retVal);", true);
            else
                Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.editedRecordSaved(retVal);", true);
 
        }
        else
        {
            Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Database not found!\");", true);
        }
    }
    catch (Exception eX)
    {
        Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Error:" + eX.Message + "\");", true);
    }
} 

One additional helper function has to be added and we are done with this code file:
(Placing it directly below the btSave_Click event would do fine)
 

//Encodes the entered values to make it JSONP compatible
//An (well proved working) alternative is to use Newtonsofts Json.dll, but I don't want to bundle it with this
private string encodeJsonSpecialChars(string txt)
{
    string result = txt.Replace("\"", "\\\"");
    result = result.Replace("\'", "\\\'");
    result = result.Replace("\n", "\\\n");
    result = result.Replace("\r", "\\\r");
    return result;
}


If you build the project and open it in a browser record editing should work as well as adding a new record. Please remind the Key board shortcuts F2 for new record and Enter for editing the currently selected record. 

CompanyPhoneList_Delete.aspx

In the .aspx file remove all all lines except the first one. This o.k. because this page only response to a JSONP request. 

 
Switch to the code file (CompanyPhoneList_Delete.aspx.cs) and add this code that does the actual deletion of the record to the automatic generated Page_Load event:

string resultText = string.Empty;
string callBackFuncName = string.Empty;
try
{
    Response.Clear();
    Response.ContentType = "text/javascript";
    DataTable dtData = new DataTable();
    string id2Delete = String.Empty;
    string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
    try
    {
        callBackFuncName = Request.Params["callback"].ToString();
    }
    catch { }
    try
    {
        id2Delete = Request.Params["id"].ToString();
    }
    catch { }
    if (!String.IsNullOrEmpty(id2Delete))
    {
        // Read the database file, remove the record and save it again
        dtData.ReadXml(databaseFileName); // No further testing of existence needed
        DataRow[] dr = dtData.Select("id = '" + id2Delete + "'");
        if ((dr != null) && (dr.Length == 1))
        {
            dtData.Rows.Remove(dr[0]);  // Remove the row
            dtData.WriteXml(databaseFileName, XmlWriteMode.WriteSchema); // Write the file
            resultText = "OK:";
        }
        else
            throw new Exception("Record to delete not found !");
    }
    else
        throw new Exception("Record to delete not specified!");
}
catch (Exception eX)
{
    resultText = "Error:" + eX.Message;
}
Response.Write(callBackFuncName + " ('" + resultText + "');");
Response.End();

 

Conclusion 

Using Dojo you could easily create web based forms for CRUD database operations using Microsoft’s ASP.NET platform. 

References 

The Dojo toolkit’s homepage (2012-07-20 07:16):
http://dojotoolkit.org/

The Dojo foundations homepage (2012-07-20 07:20):
http://dojofoundation.org/

SQL Server Compact Edition Version 3.5 could be downloaded here (2012-07-20 07:16):
http://www.microsoft.com/de-de/download/details.aspx?id=5783

Legal Stuff 

Microsoft, ASP.NET, Visual Studio and Visual Web Developer are registered trademarks of
Microsoft Corporation in the United States and other countries.  (http://www.microsoft.com)
 

I didn’t found any trademark information about the Dojo framework. Maybe it is trademarked by the Dojo foundation. In case it is, it is mentioned by this.  

History 

20120720 Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

FiegeU

Germany Germany
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberMember 1059208219-Mar-14 1:45 
GeneralRe: My vote of 5 PinmemberFiegeU22-Mar-14 11:08 
GeneralRe: My vote of 5 PinmemberMember 1059208223-Mar-14 1:23 
GeneralNeed help with JsonRest PinmemberMember 95708934-Nov-12 7:12 
AnswerRe: Need help with JsonRest PinmemberFiegeU4-Nov-12 10:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141015.1 | Last Updated 20 Jul 2012
Article Copyright 2012 by FiegeU
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid