Build an AJAX Based ASP.NET Web Tag Application - Part 2
 
Published: 05 Nov 2008
Abstract
In this second part of the series, Xianzhong delves deeper into the system design and implementation of the web tag application, which involves all the web tag related functions with the help of relevant source code and screenshots. He examines the different ways of web tag manipulation, such as displaying and moving the web tag category list, moving and removing a web tag, as well as adding, removing and modifying a web tag Category. Towards the end of the article he also examines how to add and modify a new web tag.
by Xianzhong Zhu
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 45462/ 59

Displaying the Web Tag Category List

To gain a more intuitive reference, let us again take a look at the running time snapshot of the main and only page (Default.aspx) in this system.

Figure 1 - One of the running time snapshots of the web tag page

As shown above, the web tag category list is shown on the left, where users can click one of the categories to see relevant tag info on the larger right part.

On the whole, it takes two steps to accomplish the aim of displaying the tag category list:

1.    Author the server-side page ListSection.aspx, whose functionality is inquire the section data table, and then compose the HTML code with the returned data.

2.    On the client side, use the JavaScript code to manipulate the XMLHttpRequest object to trigger the request to page ListSection.aspx, and then use the returned HTML data to render the tag category list on the page.

Next, let us take a look at the behind-code for page ListSection.aspx, as is shown in Listing 1.

Listing 1 - The behind-code for page ListSection.aspx

protected void Page_Load(object sender, EventArgs e)
{
    Database db = DatabaseFactory.CreateDatabase("DatabaseConnectionString");
    string sqlCommand = "SELECT id,name,[order] FROM section ORDER BY [order]";
    DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);
    StringBuilder readerData = new StringBuilder();
    using (IDataReader dataReader = db.ExecuteReader(dbCommand))
    {
        readerData.Append("<ul id=\"section_list\">");
        while (dataReader.Read())
        {
            readerData.Append("<li id=\"");
            readerData.Append("li_" + dataReader["id"]);
            readerData.Append("\">");
            readerData.Append(dataReader["name"]);
            readerData.Append("</li>");
        }
        readerData.Append("</ul>");
    }
    Response.Write(readerData.ToString());
 
}

Considering that there are generally not many tag categories and the HTML code required by the tag list is also simple, herein we have directly used the connecting string mode to output the result string. Apparently, this solution only applies to cases most like this. However, if the page contents to render are rather complex, it would be better to fall back upon the XSLT transformation solution. In later examples we will discuss this kind of method.

Let us continue to look at the possible returned HTML code by page ListSection.aspx (note the factual rendering contents do not contains the ENTER and SPACE chars).

Listing 2

<ul id="section_list">
      <li id="li_5">Java</li>
      <li id="li_1">Ajax</li>
      <li id="li_3">ASP</li>
      <li id="li_6">Ruby</li>
      <li id="li_7">JavaScript</li>
</ul>

Next, let us take a look at the client-side implementation. As is mentioned above, the client side will send out requests to page ListSection.aspx in the Ajax mode, and then render the returned data onto the web page. On the client side, we use a <div/> element with id being "sections" to hold and display the tag category list. Listing 3 indicates the crucial piece of code.

Listing 3 - Sending Ajax request and rendering the tag category list

var ajax = new Ajax.Request("ListSection.aspx", {onComplete: InitSection});
 
function InitSection(xmlhttp) {
  // Show tag category list
  $("sections").innerHTML = xmlhttp.responseText;
……

The code above used the "Ajax.Request" class provided by the Prototype framework. Herein, the "Ajax.Request" class sends an Ajax request to page ListSection.aspx. And if the call succeeds, the callback function"'OnComplete" is triggered, which in turn will invoke another function, InitSection, to append the returned data to the tag category list related <div/> element. That is it.

Next, let us discuss how to move the web tag category related items.

Moving the Web Tag Category

Above all, we should remember that the tag categories in table "section" is ordered by the field "order," which greatly facilitates the later tag tidying which possibly requires adjusting the orders of the tag categories. In this case, we naturally realized the Sortable object supplied by the script.aculo.us framework, which provided the easy drag & drop manipulation to change the tag list order. Of course, the first step for this is still to get this operation related data ready.

In the previous section in Part 1, we leveraged the storage process "MoveSection" to encapsulate the moving tag category related operations. So, in the behind-code file, what is left for us to do is only invoke the storage process "MoveSection," which is done inside page MoveSection.aspx).

Listing 4

public partial class MoveSection : System.Web.UI.Page
{
    protected void Page_Load(object sender,
                               EventArgs e)
    {
        if ((Request.Params["oid"] != null) &&
            (Request.Params["noid"] != null))
        {
                  //prepare for the input arguments for the 
                   storage process: the old 'order' and the new one
            int iOrder = Convert.ToInt32(Request.Params["oid"]);
            int iNewOrder = Convert.ToInt32(Request.Params["noid"]);
 
       //set up reference to the database
            Database db = 
              DatabaseFactory.CreateDatabase("DatabaseConnectionString");
       //define the SP 'MoveSection' object
            string sqlCommand = "MoveSection";
            DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
 
         //add the input arguments for the SP
            db.AddInParameter(dbCommand, "order", DbType.Int32, iOrder);
            db.AddInParameter(dbCommand, "new_order", DbType.Int32, iNewOrder);
            //execute the SP
            db.ExecuteNonQuery(dbCommand);
        }
    }
}

Note to access page MoveSection.aspx, you have to provide two arguments, oid and noid, which represents the order before and after moving the tag category, respectively.

Now, let us focus on how to achieve the result of mouse dragging the tag category list items. In fact, this is easily done using the "Sortable.create" method. The key task in this case lies in how to invoke page MoveSection.aspx after the dragging action so as to execute the backend related database operations. Examining further, you will find this is accomplished with the help of the callback function of the "Sortable.create" method.

Listing 5

var sort = Sortable.create("section_list", {
            //ghosting: true,
            constraint: false,
            starteffect: function(element) {
                  // mark the initial order before dragging
                  start_order = Element.FindIndexOf("section_list", element);
                  start_order = parseInt(start_order) + 1;
            },
            endeffect: function(element) {
                  // mark the result order after dragging
                  end_order = Element.FindIndexOf("section_list", element);
                  end_order = parseInt(end_order) + 1;
  
                  // invoke the page MoveSection.aspx in the Ajax mode 
                  // to move the tag section
                  var pars = "oid=" + start_order + "&noid=" + end_order;
                  new Ajax.Request("MoveSection.aspx", 
                    {mothed: "GET", parameters: pars});
}

As you have found out, it is in the options parameter of the "Sortable.create" method that we defined the callback function endeffect, where we used the Ajax.Request class to asynchronously call page MoveSection.aspx.

Another question is how to obtain the two arguments oid and noid that page MoveSection.aspx needs. Since the parameters passed to the two callback functions starteffect and endeffect are both the dragged page elements, we need to retrieve the position of the element inside the div object that represents the tag category list.

In general JavaScript programming, to retrieve a sub element within a parent use the simple looping mode. Now with the help of the extending method FindIndexOf of the Element object, you can more elegantly do this, as is shown above.

Figure 2 - Moving the tag categories related snapshot

Displaying the Web Tag List

When you click the tag category name on the left part, the tag's info belonging to the related category will be displayed on the right side. The right part is the rather complex part in the tag system, where we cannot use the simple connecting string to meet the requirement of rendering the page. In this case, we will fall back upon the XSLT technique to transform the XML structured data into the HTML code form.

This above task is performed with page ListNotes.aspx, where the SQL Server's special FOR XML clause is used to help finish the database query. As you maybe have already known, a SQL query with a FOR XML sub clause will return the XML formatted data, which in combination with the XmlReader class in .NET platform will easily achieve the aim of outputting data in the XML format. Listing 6 indicates the behind-code of page ListNotes.aspx.

Listing 6

protected void Page_Load(object sender, EventArgs e)
{
      if (Request.Params["sid"] != null)
      {
            // Get the tag category id
            int iSectionId = Convert.ToInt32(Request.Params["sid"]);
 
            //create the database access object
            SqlDatabase db = DatabaseFactory.CreateDatabase
               ("DatabaseConnectionString"as SqlDatabase;
 
            // SQL clause: note the use of the FOR XML sub clause
            string sqlCommand = 
                  "SELECT id, title, link, description, html, [order] " +
                  "FROM note WHERE section_id = " + iSectionId.ToString() +
                  " ORDER BY [order] FOR XML AUTO, ELEMENTS";
 
            //create the SQL Command object according to the above sql clause
            DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);
 
            XmlReader reader = null;
            StringBuilder sb = new StringBuilder();
 
            try
            {
                  //obtain the XML styled data reader
                  reader = db.ExecuteXmlReader(dbCommand);
            }
            finally
            {
                  if (dbCommand.Connection != null)
                  {
                        dbCommand.Connection.Close();
                  }
            }
            
            // xslt transformation
            XslCompiledTransform xslt = new XslCompiledTransform();
            xslt.Load(Server.MapPath("~/xsl/notes.xsl"));
 
            // render the result via xslt transformation
            XmlWriter writer = new XmlTextWriter(Response.Output);
            xslt.Transform(reader, writer);
      }
}

Note that accessing page ListNotes.aspx requires an input parameter sid, which just corresponds to the tag category id. Another point you should take notice of is that file notes.xsl here is the XSLT transformation style file, which plays the role of transforming the XML data returned from the database query into the HTML code and render it onto the page. However, for brevity, we will not list the long content of file notes.xsl.

Next, in the client side JavaScript code two tasks need to be finished: one is add the onclick event handler for the items inside the tag category list, the other is put the output HTML code from page ListNotes.aspx inside the corresponding <div/> element on the main page.

To achieve the target of adding the onclick event handler for the items inside the tag category list, we can recur to the "Event.observe" method provided by Prototype. This is done using the code in Listing 7.

Listing 7

function InitSection(xmlhttp) {
  // Show tag category list
  $("sections").innerHTML = xmlhttp.responseText;
  
  // mark the start and  end orders during the course of the dragging respectively
  var start_order, end_order;
  
    var sort = Sortable.create("section_list", 
 {
              //ghosting: true,
              constraint: false,
              starteffect: function(element) {
                    // mark the initial order before dragging
                    start_order = Element.FindIndexOf("section_list", element);
                    start_order = parseInt(start_order) + 1;
              },
              endeffect: function(element) {
                    // mark the result order after dragging
                    end_order = Element.FindIndexOf("section_list", element);
                    end_order = parseInt(end_order) + 1;
      
                    //invoke the page MoveSection.aspx in the Ajax 
                    //mode to move the tag section
                    var pars = "oid=" + start_order + "&noid=" + end_order;
                    new Ajax.Request("MoveSection.aspx", 
                      {mothed: "GET", parameters: pars});
    }
  });
  
  // add onclick response
            $A($("sections").childNodes).each(
                  function(element, index) {
                        Event.observe(element, "click", ListNotes, false);
                  }
            );
}
function ListNotes(event) {
            // remove  "li_" before each id,can convert it to section id
      var section_id = Event.element(event).id.getId();
      $("selSection").value = section_id;
      new Ajax.Request(
            "ListNotes.aspx", {
                  parameters: "sid=" + section_id,
                  onComplete: ShowNotes
            }
      );
}
 
function ShowNotes(xmlhttp) {
          $("rightArea").innerHTML = 
             xmlhttp.responseText;
…… (omitted)

In the above code, we again used the iterate-through function of the enumerable objects to loop through all the sub nodes within the <div/> element representing the tag category list to attach the onclick event handler to them.

By examining further, you may find that the onclick event handler function is specified as ListNotes. Inside the function ListNotes, we use the "Ajax.Request" class to send asynchronous request to page ListNotes.aspx.

However, before sending out the request to page ListNotes.aspx, one question should be tackled out: how to grab the id of the current tag category? In essence, during the previous course of displaying the tag category and tag info, we have already made preparation for this. Acute readers may have found out that in the tag category and tag lists related HTML code, the naming of the element ids are in well regularity: they are all ended with the symbol underscore plus the id number. Therefore, if we obtain the id of the onclick event source, we can easily get the id's of the tag categories and tags. For this, we should fall back on the extension function getid of the String object, which can acquire the sub string after the last symbol underscore. Here is the related code.

Listing 8

String.prototype.getId=function(){
      Return this.substr( this.lastIndexOf("_")+1);
}

Up to now, we have nearly finished the task of displaying the tag info. The last small function that requires adding to this part is the unfold/collapse support to each tag info block. You may have already noticed that at the upper left corner of each tag rectangle there are small triangle icons through which we wish to add the tag info unfold/collapse function. Please look at the following script code.

Listing 9

function ShowNotes(xmlhttp) {
  …… (omitted)
            $$(".showHide").each(
                  function(item) {
                        Event.observe(item, "click",
                              function(event) {
                                    var target = 
                                     event.target ? event.target : event.srcElement;
                                    var id = target.id.getId();
                                    Effect.toggle("content_" + id, "appear", 
 {
                                          transition: Effect.Transitions.full,
                                          duration: 0.2,
                                          afterFinish: function (effect) {
                                                $("img_" + id).src = 
                                                      effect.element.visible() ?
                                                      "images/hideMod.gif" : 
                                                      "images/showMod.gif";
                                          }
                                    });
                              }, false
                        );
                  }
            );
…… (omitted)
}

Here, we again used the Event.observe method to attach the onclick event handler to the <img> elements. Morever, we rested on the special effect (in this case the Effect.toggle method) provided by the script.aculo.us framework to achieve the aim of displaying and hiding the tag info.

The last detail you need to notice is that we used the CSS selector support of Prototype to grab all the sets with the CSS class named "showHide," and then attached the corresponding onclick event handlers to each of the items. The following two figures show the unfolding and collapsing effect of the tag info blocks, respectively.

Figure 3 - Hiding the tag info block

Figure 4 - Displaying the tag info block

Moving a Web Tag

As with the tag category, the orders of the tags within a special category are also in some sequence. In this case, we display all the tags according to the order field defined in table note. In this section, we are to add the mouse drag & drop functionality to the tag list, so that users can use a simpler and more intuitive mode to adjust the order of the tag info.

In this sample, we use page MoteNote.aspx to achieve the moving tag function on the server side.

Listing 10

protected void Page_Load(object sender, 
 EventArgs e)
{
      if ((Request.Params["id"] != null) &&
            (Request.Params["noid"] != null))
      {
            // tag id
            int iNoteId = Convert.ToInt32(Request.Params["id"]);
 
            //tag order
            int iNewOrderId = Convert.ToInt32(Request.Params["noid"]);
 
            // set up the database access object
            Database db = DatabaseFactory.CreateDatabase
              ("DatabaseConnectionString");
 
            //the stored procedure MoveNote
            string sqlCommand = "MoveNote";
            DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
 
            // provide the input parameters for the SP
            db.AddInParameter(dbCommand, "id", DbType.Int32, iNoteId);
            db.AddInParameter(dbCommand, "new_order", DbType.Int32, iNewOrderId);
 
            // execute the stored procedure
            db.ExecuteNonQuery(dbCommand);
      }
}

There are two input arguments required by page MoveNote.aspx, id and order, which represent the id and order properties of the to-be-moved tag respectively.

In this case, we used the "Sortable.create" method to achieve the drag & drop functionality. However, the idea here is a bit different from that in moving the tag category. Because the parameter id passed to page MoveNote.aspx can be obtained by using the id property of the dragged object, herein we do not need the starteffect callback function any more. While in another callback function - endeffect send out the asychronous request to page MoveNote.aspx to finish the backend database related operations. The relevant script code is as follows.

Listing 11

function ShowNotes(xmlhttp) {
            
      //make the automatically added tag own automatic completing functionality
      EnableAutoCompleter();
            
      //mark the start and  end order during
       the course of the dragging
      var end_order;
  
      Sortable.create("notes", {
                  //ghosting: true,
                  constraint: false,
                  endeffect: function(element) {
            // mark the result order after dragging
            end_order = Element.FindIndexOf("notes", element);
                        end_order = parseInt(end_order) + 1;
      
            // invoke the page MoveNote.aspx in 
            // the Ajax mode to move the tag section
            var pars = "id=" + element.id.getId() + "&noid=" + end_order;
            new Ajax.Request("MoveNote.aspx", {mothed: "GET", parameters: pars});
    }
  });

With enough comments between the lines, we do not dwell upon the explanation. Next, let us take a glimpse at one of the running-time snapshots, as shown in Figure 5 below.

Figure 5 - Dragging any tag info area to adjust the tag sequence

On the right part of the figure, you can drag any rectangle tag info area to adjust the tag sequence at discretion.

Removing a Web Tag

Compared with other functionalities, removing a web tag is easy, which is performed using the following steps. First, write the behind-code page to invoke the stored procedure DeleteNote. Next, use page DeleteNote.aspx to implement the tag removing function. Listing 12 gives the related behind code.

Listing 12

protected void Page_Load(object sender, 
 EventArgs e)
{
      if (Request.Params["id"] != null)
      {
            // tag id
            int iNoteId = Convert.ToInt32(Request.Params["id"]);
            // set up the database access object
            Database db = DatabaseFactory.CreateDatabase
              ("DatabaseConnectionString");
            // the SP DeleteNote to delete tags
            string sqlCommand = "DeleteNote";
            DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
            // provide the input parameters for the SP
            db.AddInParameter(dbCommand, "id", DbType.Int32, iNoteId);
            // execute the stored procedure
            db.ExecuteNonQuery(dbCommand);
      }
}

Since there are already enough comments herein, you can easily seize the main idea of it. One note is the passed argument of page DeleteNote.aspx, i.e. the tag id.

As regards the "Delete" tag button, it has already been implemented when we discuss displaying the tag category list. And also, we have already provided the corresponding onclick event response function, DeleteNote(), is as follows.

Listing 13

// Delete Tag
function DeleteNote(id) {
    if (confirm("Are you sure to delete current tag? Not you cannot undo it!")) {
            new Ajax.Request("DeleteNote.aspx", {
                mothed: "GET",
                parameters: "id=" + id,
            });
        }
}
// Delete tag list
function RefreshNoteList() {
    var section_id = $("selSection").value;
    new Ajax.Request(
        "ListNotes.aspx", {
            parameters: "sid=" + section_id,
            onComplete: ShowNotes
        }
    );
}
Adding a New Web Tag Category

The basic routine for adding a new web tag category is: first, select the "adding a new web tag category" command, a dialog box then pops up to prompt you to enter the new name for the category, and after clicking "OK," the new tag category will be added to the system behind the scene and the page will be updated consequently.

In detail, adding a new web tag category is also divided into two parts. First, the server-side page (AddSection.aspx) invokes the stored procedure AddSection according to the passed argument (the tag category name) to implement the adding tag category operation.

Next, the client side JavaScript code use ProtoType's "Ajax.Request" object to send out a request to page AddSection.aspx; and if the request succeeds, the new category list will be refreshed consequently. Listing 14 gives the related script code.

Listing 14

function AddSection() {
    var sectionName = window.prompt("Please enter a new tag category name");
    if (sectionName) {
        var paras = "name=" + escape(sectionName);
        new Ajax.Request("AddSection.aspx", {
            mothed: "GET",
            parameters: paras,
            onComplete: function(xmlhttp) {
                new Ajax.Request("ListSection.aspx", {onComplete: InitSection});
        });
    }
}

The following figure illustrates one of the running-time snapshots for adding a new tag category operation. When we first click the "Add a new tag category" menu item, a related dialog box pops up that requires you to enter the new name and when you press "OK," the newly-populated tag category name will be added into the tag category list.

Figure 6

Next, let us continue to see how to delete a specified tag category.

Removing a Web Tag Category

When you click the "Delete current tag category" menu item, a simple alert dialog box will pop up asking you whether you are sure to make the deletion. After you press "Yes" and delete the current tag category, the tag category list will be automatically updated.

The behind code relating to page DeleteSeciton.aspx is shown below.

Listing 15

protected void Page_Load(object sender, EventArgs e)
{
      if (Request.Params["id"] != null)
      {
            // the tag category id to be deleted
            int iNoteId = Convert.ToInt32(Request.Params["id"]);
 
            // set up the database access object
            Database db = DatabaseFactory.CreateDatabase
              ("DatabaseConnectionString");
 
            // define the SP DeleteSection related object
            string sqlCommand = "DeleteSection";
            DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
 
            // provide the input parameters for the SP
            db.AddInParameter(dbCommand, "id", DbType.Int32, iNoteId);
 
            // execute the stored procedure
            db.ExecuteNonQuery(dbCommand);
      }
}

Herein, the argument id passed to page DeleteSection.aspx represents the id attribute of the tag category to be deleted.

On the client side, the similar means is taken to invoke the page DeleteSection.aspx in the asynchronous way, which is indicated in the following scripts.

Listing 16

function DeleteSection(id) {
        if (window.confirm("Are you sure to delete current tag category? All the 
tag info with it will be removed and cannot be restored!")) {
                  var paras = "id=" + id;
            new Ajax.Request("DeleteSection.aspx", {
                  mothed: "GET",
                  parameters: paras,
                  onComplete: function(xmlhttp) 
 {
                        new Ajax.Request("ListSection.aspx", 
                        {onComplete: InitSection});
                  }
            });
            }
}

Next, let us shift our attention to the web tag category modification operation.

Modifying a Web Tag Category

This rough idea of the modifying operation here is quite similar to that in adding and deleting a tag category. First, the server side page is RenameSection.aspx, whose behind code is listed below.

Listing 17

protected void Page_Load(object sender, EventArgs e)
{
      if ((Request.Params["id"] != null) &&
              (Request.Params["name"] != null))
      {
            // the tag category id to be modified
            int iSectionId = Convert.ToInt32(Request.Params["id"]);
 
            // the new web tag name
            string strSectionName = Request.Params["name"];
 
            // set up the database access object
            Database db = DatabaseFactory.CreateDatabase
             ("DatabaseConnectionString");
 
            // define the SP RenameSection related object
            string sqlCommand = "RenameSection";
            DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
 
            // provide the input parameters for the SP
            db.AddInParameter(dbCommand, "id", DbType.Int32, iSectionId);
            db.AddInParameter(dbCommand, "name", DbType.String, strSectionName);
 
            // execute the stored procedure
            db.ExecuteNonQuery(dbCommand);
      }
}

Here, the stored procedure RenameSection is invoked. And also, we have to pass in the two related arguments id and name which represent the id and the name property of the modifying tag category respectively.

In contrast to the above, on the client side, we still leverage "Ajax.Request" class to send out requests to page RenameSection.aspx, whose script code is as follows.

Listing 18

function RenameSection(id) {
      var sectionName = window.prompt("Please enter a new tag category name");
      if (sectionName) {
            var paras = "id=" + id + "&name=" + escape(sectionName);
            new Ajax.Request("RenameSection.aspx", {
                  mothed: "GET",
                  parameters: paras,
                  onComplete: function(xmlhttp) 
 {
                        new Ajax.Request("ListSection.aspx", 
                        {onComplete: InitSection});
                  }
            });
      }
}

Here, we first use the JavaScript window.prompt dialog to let the user enter a new tag category name. Then, construct the parameter passed to page RenameSection.aspx. And finally, asynchronously call page RenameSection.aspx to accomplish the task of modifying the category name behind the scene.

Adding a New Web Tag

The adding a new web tag in this section and the followed modifying a web tag are a bit complex because they are all connected with a special area for handling the tag. In this case and under normal conditions, the tag handling area is hidden. It is not until you select the menu item "Adding a new web tag" that thr mark area for the tag can be seen.

It is in page AddNote.aspx that the stored procedure AddNote is invoked to add a new tag. The following lists the total code for AddNote.aspx.cs.

Listing 19

public partial class AddNote : System.Web.UI.Page
{
      protected void Page_Load(object sender, EventArgs e)
      {
            if ((Request.Params["sid"] != null) &&
                        (Request.Params["title"] != null) &&
                        (Request.Params["link"] != null) &&
                        (Request.Params["desc"] != null) &&
                        (Request.Params["html"] != null) &&
                        (Request.Params["order"] != null))
            {
                  // tag category id
                  int iSectionId = Convert.ToInt32(Request.Params["sid"]);
 
                  // tag title
                  string strTitle = Request.Params["title"];
 
            // tag link URL
                  string strLink = Request.Params["link"];
 
                  //tag description
                  string strDesc = Request.Params["desc"];
 
                  // the tag HTML code
                  string strHtml = Request.Params["html"];
 
                  // tag order
                  int iOrder = Convert.ToInt32(Request.Params["order"]);
 
                  // set up the database access object
                  Database db = DatabaseFactory.CreateDatabase
                    ("DatabaseConnectionString");
 
                  // define the SP AddNote related object
                  string sqlCommand = "AddNote";
                  DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
 
            // provide the input parameters for the SP
            db.AddInParameter(dbCommand, "title", DbType.String, strTitle);
            db.AddInParameter(dbCommand, "link", DbType.String, strLink);
            db.AddInParameter(dbCommand, "description", DbType.String, strDesc);
            db.AddInParameter(dbCommand, "html", DbType.String, strHtml);
            db.AddInParameter(dbCommand, "section_id", DbType.Int32, iSectionId);
            db.AddInParameter(dbCommand, "order", DbType.Int32, iOrder);
 
                  // execute the stored procedure
                  db.ExecuteNonQuery(dbCommand);
            }
      }
}

Here, let us give more explanations concerning the six arguments passed to page AddNote.aspx.

·         Sid - the id property of the to-be-added tag

·         Title - the title property of the to-be-added tag

·         Link - the link property of the to-be-added tag

·         Desc - the desc property of the to-be-added tag

·         Html - the html property of the to-be-added tag

·         Order - the order property of the to-be-added tag

In the client-side JavaScript script, we, as usual, use the "Ajax.Request" class to asynchronously send requests to page AddNote.aspx to add a new web tag. And also, if the request succeeds the tag list will be updated, and after that, the corresponding <div/> mark area will be hidden. Here lists the relevant JavaScript script.

Listing 20

function AddNote(id) {
            //prepare the arguments
            var paras = "order=1&sid=" + $F("selSection") +
                  "&title=" + escape($("addTitle").value) +
                  "&link=" + escape($("addLink").value) +
                  "&desc=" + escape($("addDesc").value) +
                  "&html=" + escape($("addHtml").value);
            //make request and achieve the adding function behind
            new Ajax.Request("AddNote.aspx", {
                  mothed: "GET",
                  parameters: paras,
                  onComplete: function (xmlhttp) 
 {
                  //the id of the current tag category
                  var section_id = $("selSection").value;
                  //update the tag list
                  new Ajax.Request(
                        "ListNotes.aspx", {
                              parameters: "sid=" + section_id,
                              onComplete: function (xmlhttp) {
            //hide the adding mark area
                                    Element.hide("addArea");
            //update the tag info related to current tag category
                                    ShowNotes(xmlhttp);
                              }
                        }
                  );
                  }
            });
}

To gain a more convenient mode for the user to enter the title and the hyperlink of the tags, we have provided the automatic completion support when adding a new tag, so that when the user is entering the title and URL info, the page will give related prompt based upon the info in the title and URL set, which is carried out using the "Autocompleter.Local" class provided by the script.aculo.us framework. Listing 21 gives the automatic completion related programming.

Listing 21

function EnableAutoCompleter() {
        // title
        var titles = [];
        $$(".module .moduleFrame .moduleHeader .title").each( function (element) {
            titles.push(element.innerHTML);
        });             
        new Autocompleter.Local("addTitle", "titleList", titles);
        // website's url
        var links = [];
        $$(".moduleContent div span a").each( function (element) {
            links.push(element.href);
        new Autocompleter.Local("addLink", "linkList", links, {fullSearch: true});
}

The basic idea here is when displaying all the tag info belonging to a special category, we have used  two Array objects, titles and links, to persist all the title and URL info of this category, and then by using the "Autocompleter.Local" class to append the automatic completion function. By the way, we have used the CSS selector function $$ to grab all the tag and URL info, and then save it into the related Array objects. Figure 7 illustrates the automatic hint support when entering the tag title.

Figure 7—the automatic completing support in the running time

In the last section, we will turn to delve into how to edit the special tag info.

Modifying a Web Tag

The modifying function resembles the adding operation. In this case, we have also provided a special <tag/> area to edit the tag info. When clicking the "edit" button at the upper right part of the tag info block the special area becomes visible inside which the modification operation will be performed. The related server page is EditNotes.aspx, whose behind code is listed below.

Listing 22

protected void Page_Load(object sender, 
 EventArgs e)
{
      if ((Request.Params["id"] != null) &&
                  (Request.Params["title"] != null) &&
                  (Request.Params["link"] != null) &&
                  (Request.Params["desc"] != null) &&
                  (Request.Params["html"] != null))
      {
            // tag id
            int iNoteId = Convert.ToInt32(Request.Params["id"]);
 
            // tag title
            string strTitle = Request.Params["title"];
 
            // tag URL
            string strLink = Request.Params["link"];
 
            // the description of the tag
            string strDesc = Request.Params["desc"];
 
            // the HTML code of the tag
            string strHtml = Request.Params["html"];
 
            // set up the database access object
            Database db = DatabaseFactory.CreateDatabase
             ("DatabaseConnectionString");
 
            // the object to manipulate the SP EditNote
            string sqlCommand = "EditNote";
            DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
 
            // provide the input parameters for the SP
            db.AddInParameter(dbCommand, "id", DbType.Int32, iNoteId);
            db.AddInParameter(dbCommand, "title", DbType.String, strTitle);
            db.AddInParameter(dbCommand, "link", DbType.String, strLink);
            db.AddInParameter(dbCommand, "description", DbType.String, strDesc);
            db.AddInParameter(dbCommand, "html", DbType.String, strHtml);
 
            // execute the stored procedure
            db.ExecuteNonQuery(dbCommand);
      }
}

The meanings of the five passed arguments are below.

·         Id - the id property of the to-be-modified tag

·         Title - the title property of the to-be-modified tag

·         Link - the link property of the to-be-modified tag

·         Desc - the desc property of the to-be-modified tag

·         Html - the html property of the to-be-modified tag

·         Order - the order property of the to-be-modified tag

In the client-side JavaScript script, we have also used the "Ajax.Request" class to asynchronously send requests to page EditNote.aspx to edit a specified web tag. And also, if the request succeeds, the tag list will be updated, and after that, the corresponding <div/> mark area will again become hidden. Here is the relevant JavaScript script.

Listing 23

function UpdateNote() {
            var paras = "id=" + $("editNoteId").value +
                  "&title=" + escape($("editTitle").value) +
                  "&link=" + escape($("editLink").value) +
                  "&desc=" + escape($("editDesc").value) +
                  "&html=" + escape($("editHtml").value);
                  
            new Ajax.Request("EditNote.aspx", {
                  mothed: "GET",
                  parameters: paras,
                  onComplete: function (xmlhttp) 
 {
                  var section_id = $("selSection").value;
                  new Ajax.Request(
                        "ListNotes.aspx", {
                              parameters: "sid=" + section_id,
                              onComplete: function (xmlhttp) {
                                    Element.hide("editArea");
                                    ShowNotes(xmlhttp);                                   
                              }
                        }
                  );
                  }
            });
}

Finally, let us look at one of the running-time snapshots of the tag editing scene.

Figure 8—the running-time snapshots of the tag editing scene

Note for a poor CSS+DIV layout foundation, I have not elegantly controlled the position of the tag editing area. So, you can recreate it yourself.

Downloads

Conclusion

In this article, we have built a simple web tag application with the help of the two client-side Ajax frameworks - script.aculo.us and Prototype. We have provided the basic support for adding, editing, removing, and moving functionalities of the web tag and related categories.

In terms of the system design, we use the server side to undertake the database related business manipulations, while the client side takes the responsibility of launching the Ajax requests to associated pages in order to achieve the corresponding function, which, in fact, is the simplest mode of Ajax calling.

As you have seen, many of the server-side .aspx pages have no page-related contents to output, which seems to be of some redundancy. So, as a relaxing homework, I recommend you integrate these behind codes into the .aspx.cs file of the main page or one independent class, and then use the client side JavaScript code to invoke them, which will result in a clearer and more efficient system design. To achieve this aim, one of the feasible solutions is to resort to the server side related Ajax frameworks, such as ASP.NET AJAX, AjaxPro.NET, through which to invoke the methods of the newly-defined class. So, why not make an attempt with this new idea?



User Comments

Title: Thanks   
Name: Cong Doan
Date: 2009-04-13 11:17:25 AM
Comment:
Thanks for your Article! It's wonderful!






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-23 10:26:56 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search