Web Application Generator

Labels
AJAX(112) App Studio(7) Apple(1) Application Builder(245) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcode(2) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(12) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) Device(1) DotNetNuke(12) EASE(20) Email(6) Features(101) Firebird(1) Form Builder(14) Globalization and Localization(6) How To(1) Hypermedia(2) Inline Editing(1) Installation(5) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(18) OAuth(9) OAuth Scopes(1) OAuth2(13) Offline(20) Offline Apps(4) Offline Sync(5) Oracle(11) PKCE(2) Postgre SQL(1) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(183) Reports(48) REST(29) RESTful(29) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(81) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) SSO(1) Stored Procedure(4) Teamwork(15) Tips and Tricks(87) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(338) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Archive
Blog
Web Application Generator
Tuesday, September 25, 2012PrintSubscribe
jQuery Cross-Domain Dynamic Client of a Web App

A fictitious company Northwind Traders had a fair amount of success with the statically exposed product catalog that allows third parties to display the catalog on their own web sites. An exceptionally small amount of code is required to create a jQuery cross-domain static client of the back office web app created with Code On Time.

Northwind Traders have decided to offer search capabilities of the back office web app to their premium integration partners.

A possible implementation of a search client is shown next.

If a user clicks Find without entering a search sample,  then the first one hundred products are retrieved in alphabetical order.

The search result displayed in jQuery cross-domain dynamic client of the demo web app when a search criteria is not specified

This is the result that matches “40 biscuit” search criteria.

The search result displayed in jQuery cross-domain dynamic client of the demo web app with '40 biscuit' search sample

The back office web app at http://demo.codeontime.com/northwind/pages/products.aspx displays the same exact result as follows.

The 'Quick Find' result for '40 biscuit' search sample in the demo web app created with Code On Time

The HTML page implementing a sample search client works across domains in any web browser.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>jQuery Cross-Domain Client</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#ProductListPanel').hide();
            $('#Query').focus();
            $('#FindButton').click(function (e) {
                e.preventDefault();
                var query = '?_sortExpression=ProductName&_q=' +
                    encodeURIComponent($('#Query').val());
                $.ajax({
                    url: 'http://demo.codeontime.com/northwind/appservices/Products' + query,
                    cache: false,
                    dataType: 'jsonp',
                    success: function (data) {
                        $('#ProductList option').remove();
                        $.each(data.Products, function (index, product) {
                            $('<option>')
                                .text(
                                    product.ProductName + ' / ' +
                                    product.CategoryCategoryName + ' / ' +
                                    product.SupplierCompanyName + ' / ' +
                                    product.UnitPrice)
                                .attr('value', product.ProductID)
                                .appendTo($('#ProductList'));
                        });
                        $('#ProductListPanel').show();
                    }
                });
            });
        });
    </script>
</head>
<body>
    <input id="Query" type="text" />
    <button id="FindButton">
        Find</button>
    <div id="ProductListPanel">
        <select id="ProductList" size="10">
        </select>
    </div>
</body>
</html>

The page statically links jQuery library from CDN provided by Google.

The search starts when a user clicks on the Find button.

The “click” handler declares a query variable that contains “_sortExpression” and “_q” parameters. The first parameter specifies the sort order of returned products. The search parameter “_q” is the sample for the Quick Find feature of the web app.

Next, the “click” handler invokes ajax method to retrieve data from the web app. The key parameters of the method are url and dataType. The first parameter defines the REST URI of Products data controller. The second parameter indicates that a cross-domain web request must be executed by jQuery library.

If the request is successful, then a list of products populates the list box.

Monday, September 24, 2012PrintSubscribe
Your Own Personal Application Server

Code On Time release 7.0.2.0 introduces a built-in application sever in web apps created with Unlimited edition. Developers are creating modern user interface forms based on the data controllers using drag & drop and cut/copy/paste. Customized data controllers provide powerful REST APIs that allow extending web apps created with Code On Time to any platform supporting REST, JSON, JSONP, and XML.

See an example of HTML form that allows submitting data to the web app database without a single line of code. Learn how to create a native Windows Client for your web app. More examples covering development of cross-domain and embedded jQuery scripts are coming soon. It is now possible to create custom user controls that take a full advantage of data controllers with the help of jQuery.

The following features, enhancements, and bug fixes are included in this release:

  • REST APIs allow extending web apps with no-code html forms, native clients, and jQuery scripts.
     
  • Parameters can be referenced in the SQL Formula definition of a field.
     
  • Web Site Factory projects include the app generator version number in JavaScript and CSS references.
     
  • Many-to-many business rules work correctly when removing data rows from tables with surrogate primary keys.
     
  • Method BusinessRules.Result.RefreshChildren will correctly refresh the child views.
     
  • The category of annotations remains invisible until activatied by the end user.
     
  • Data sheet view will correctly size the columns in "new" mode when annotations are enabled.
     
  • Adaptive filter dialog window will correctly handle Enter key to prevent re-submission of the page.
     
  • The selected row is correctly "forgotten" by a data view when it is not in the filtered set of data rows.
     
  • Inline lookup record creation will correctly reference the Data Value Field and Data Text Field of the lookup field when figuring the value and text that must be selected in the lookup.
     
  • The controller configuration caching is now performed to improve performance. Only once instance of a data controller configuration is customized when processing  a server request.
     
  • Designer maintains "collapsed" state of nodes in Project Explorer during drag & drop operations.
     
  • Designer correctly saves changed to the "Group" property of views.
     
  • DataViewExtender class is now declared as a partial class derived from DataViewExtenderBase, which makes it possible to override CSS and JavaScript registration.
     
  • Many-to-many field values (without aliases are displayed on reports. We are still working on making possible display of of alias values.
     
  • Blob handler sets HTTP status code to 404 if the blob stream length is zero.
Friday, September 21, 2012PrintSubscribe
Windows Client of a Web App

A web app created with Code On Time may function as an application server for a client on any platform.

Let’s create a native Windows Forms application that will allow browsing and searching products available at http://demo.codeontime.com/Northwind/Pages/Products.aspx.

This is how a Quick Find search is performed by the web app. The native Windows client will provide a similar presentation and search facility.

The 'Quick Find' feature in action in a web app created with Code On Time

Click on the following link and you will see a response in XML format from the REST service of the web application:
http://demo.codeontime.com/northwind/appservices/Products?_q=40%20biscuit

The response will look similar to this sample.

<?xml version="1.0" encoding="utf-8"?>
<Products totalRowCount="2" pageSize="100" pageIndex="0" rowCount="2">
  <items>
    <item ProductName="Sir Rodney's Marmalade" SupplierID="8" CategoryID="3" 
          QuantityPerUnit="30 gift boxes" UnitPrice="$81.00" UnitsInStock="40" 
          UnitsOnOrder="0" ReorderLevel="0" Discontinued="False" ProductID="20" 
          SupplierCompanyName="Specialty Biscuits, Ltd." 
          CategoryCategoryName="Confections" />
    <item ProductName="Sir Rodney's Scones" SupplierID="8" CategoryID="3" 
          QuantityPerUnit="24 pkgs. x 4 pieces" UnitPrice="$10.00" UnitsInStock="3" 
          UnitsOnOrder="40" ReorderLevel="5" Discontinued="False" ProductID="21" 
          SupplierCompanyName="Specialty Biscuits, Ltd." 
          CategoryCategoryName="Confections" />
  </items>
</Products>

The “_q” parameter represents the Quick Find argument of the web resource. If the parameter is not specified, then the first 100 items are returned. Other parameters for sorting, paging, and filtering are also supported.

The native Windows client of the Northwind application server will construct a similar URL to retrieve data for presentation.

Start Visual Studio and select File | New Project option. Choose Windows Forms Application under Visual C# or Visual Basic template group, enter “ProductBrowser” in the name, and click OK to create project files.

The empty 'Northwind Product Browser' project contains a single Windows Form

Drop TextBox, Button, and ListView components from toolbox on the design surface of Form1 and have them arranged as shown next.

Form 'Form1' enhanced with a TextBox, Button, and ListView components

Use Properties Window to modify the Columns collection of listView1. Create five columns Product Name, Supplier Company Name, Category Name, Quantity per Unit, and Unit Price to capture a few properties of products.

Five columns in the list view 'listView1' represent properties of products stored in the Northwind database

Also set the following properties of listView1 component:

Property Value
FullRowSelect True
GridLines True
View Details
VirtualMode True

The list view is configured to behave as a virtual view.

If the property VirtualListSize is set to a value other than zero then the virtual list view will request items from the application as needed.

The list view will continuously request items representing a visible subset of data rows as a user scrolls the list.

Right-click Form1 node in the Solution Explorer and select View Code option in the context menu.

Add the highlighted namespaces to the top of code file:

C#:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Xml.XPath;
using System.IO;

namespace ProductBrowser
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

Visual Basic:

Imports System.Net
Imports System.Xml.XPath
Imports System.IO

Public Class Form1

End Class

The namespaces will link required .NET library components used by Windows native client to communicate with the web app.

Add fields _dataPage, _query, _cache, and method GetDataPage to the definition of class Form1.

C#:

protected XPathNavigator _dataPage;
protected string _query;

private SortedDictionary<int, XPathNavigator> _cache = new SortedDictionary<int, XPathNavigator>();

protected XPathNavigator GetDataPage(int pageIndex)
{
    XPathNavigator result = null;
    if (!_cache.TryGetValue(pageIndex, out result))
    {
        Cursor = Cursors.WaitCursor;
        try
        {
            WebRequest request = WebRequest.Create(String.Format(
                "http://demo.codeontime.com/northwind" +
                "/appservices/Products?_pageIndex={0}&_pageSize=10&_q={1}",
                pageIndex, _query));
            request.Method = "GET";
            using (WebResponse response = request.GetResponse())
            {
                using (Stream stream = response.GetResponseStream())
                    result = new XPathDocument(stream)
                        .CreateNavigator().SelectSingleNode("/Products");
            }
            _cache.Add(pageIndex, result);
        }
        finally
        {
            Cursor = Cursors.Default;
        }
    }
    return result;
}

Visual Basic:

Protected _dataPage As XPathNavigator
Protected _query As String

Private _cache As SortedDictionary(Of Integer, XPathNavigator) =
    New SortedDictionary(Of Integer, XPathNavigator)

Protected Function GetDataPage(pageIndex As Integer) As XPathNavigator
    Dim result As XPathNavigator = Nothing
    If Not (_cache.TryGetValue(pageIndex, result)) Then
        Cursor = Cursors.WaitCursor
        Try
            Dim request As WebRequest = WebRequest.Create(String.Format(
                "http://demo.codeontime.com/northwind" +
                "/appservices/Products?_pageIndex={0}&_pageSize=10&_q={1}",
                pageIndex, _query))
            request.Method = "GET"
            Using response As WebResponse = request.GetResponse()
                Using stream As Stream = response.GetResponseStream()
                    result = New XPathDocument(stream).
                        CreateNavigator().SelectSingleNode("/Products")
                    _cache.Add(pageIndex, result)
                End Using
            End Using
        Finally
            Cursor = Cursors.Default
        End Try
    End If
    Return result
End Function

The implementation of method GetDataPage creates a web request and retrieves the page of data from the web app if the page has not been found in the dictionary of cached data pages. The method parses the XML response received from the web app and stores an instance of XPathNavigator class initialized with a page data in the _cache field. The web request URI incorporates the requested page index and search criteria in _pageIndex and _q parameters accordingly.

Select listView1 in form designer and activate Properties Window, choose Events button, and double click RetrieveVirtualItem event.

Creating 'RetrieveVirtualItem' event handler for listView1 list view

Enter the following definition of the method listView1_RetrieveVirtualItem as shown next.

C#:

private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    // analyze the current page item range
int pageIndex = Convert.ToInt32(_dataPage.GetAttribute("pageIndex", String.Empty)); int pageSize = Convert.ToInt32(_dataPage.GetAttribute("pageSize", String.Empty)); int rowCount = Convert.ToInt32(_dataPage.GetAttribute("rowCount", String.Empty)); int firstAvailableRowIndex = pageIndex * pageSize; int lastAvailableRowIndex = firstAvailableRowIndex + rowCount - 1; // if the current page does not contain the item then retrieve the page from the app if (!(firstAvailableRowIndex <= e.ItemIndex && e.ItemIndex <= lastAvailableRowIndex)) { pageIndex = e.ItemIndex / pageSize; firstAvailableRowIndex = pageIndex * pageSize; _dataPage = GetDataPage(pageIndex); } // create a virtual list item XPathNavigator dataRow = _dataPage.SelectSingleNode( String.Format("items/item[{0}]", e.ItemIndex - firstAvailableRowIndex + 1)); e.Item = new ListViewItem(dataRow.GetAttribute("ProductName", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("SupplierCompanyName", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("CategoryCategoryName", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("QuantityPerUnit", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("UnitPrice", String.Empty)); }

Visual Basic:

Private Sub listView1_RetrieveVirtualItem(sender As System.Object,
        e As System.Windows.Forms.RetrieveVirtualItemEventArgs) Handles listView1.RetrieveVirtualItem
    ' analyze the current page item range
    Dim pageIndex As Integer = Convert.ToInt32(_dataPage.GetAttribute("pageIndex", String.Empty))
    Dim pageSize As Integer = Convert.ToInt32(_dataPage.GetAttribute("pageSize", String.Empty))
    Dim rowCount As Integer = Convert.ToInt32(_dataPage.GetAttribute("rowCount", String.Empty))
    Dim firstAvailableRowIndex As Integer = pageIndex * pageSize
    Dim lastAvailableRowIndex As Integer = firstAvailableRowIndex + rowCount - 1
    ' if the current page does not contain the item then retrieve the page from the app
    If Not (firstAvailableRowIndex <= e.ItemIndex And e.ItemIndex <= lastAvailableRowIndex) Then
        pageIndex = e.ItemIndex \ pageSize
        firstAvailableRowIndex = pageIndex * pageSize
       _dataPage = GetDataPage(pageIndex)
    End If
    ' create a virtual list item
    Dim dataRow As XPathNavigator = _dataPage.SelectSingleNode(
        String.Format("items/item[{0}]", e.ItemIndex - firstAvailableRowIndex + 1))
    e.Item = New ListViewItem(dataRow.GetAttribute("ProductName", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("SupplierCompanyName", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("CategoryCategoryName", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("QuantityPerUnit", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("UnitPrice", String.Empty))
End Sub

Consult the sample of XML response at the top of article to understand the method implementation.

The implementation makes an assumption that a page of XML data is stored in the _dataPage instance of XPathNavigator. The property e.ItemIndex specifies the index of the item that the virtual list view needs. The code tries to determine if the current data page contains the item. If the item is not in current page _dataPage, then the application will retrieve a page of data from the web app by invoking GetDataPage method. The method will either find the page in the cache or reach out to the web app with a web request for data.

Next, the event handler will create an instance of a ListViewItem. Its sub-items represent the values displayed in the columns of the list view. The instance of the ListViewItem is assigned to e.Item property.

At this point the entire mechanism of populating the list view with data has been implemented.

The only remaining step is to collect user input for the search criteria and to assign a value to the VirtualListSize property of listView1.

Activate the design surface of Form1 and double-click the Find button. This will create an event handler that shall be defines as explained below.

C#:

private void button1_Click(object sender, EventArgs e)
{
    // assign the search criteria
    _query = textBox1.Text;
    // remove any previously cached data pages
    _cache.Clear();
    // get the first page of data with index "zero"
    _dataPage = GetDataPage(0);
    // figure the total number of rows in the virtual listview
    int totalRowCount = Convert.ToInt32(_dataPage.GetAttribute("totalRowCount", String.Empty));
    listView1.VirtualListSize = totalRowCount;
}

Visual Basic:

Private Sub button1_Click(sender As System.Object, e As System.EventArgs) Handles button1.Click
    ' assign the search criteria
    _query = textBox1.Text
    ' remove any previously cached data pages
    _cache.Clear()
    ' get the first page of data with index "zero"
    _dataPage = GetDataPage(0)
    ' figure the total number of rows in the virtual listview
    Dim totalRowCount As Integer = Convert.ToInt32(_dataPage.GetAttribute("totalRowCount", String.Empty))
    listView1.VirtualListSize = totalRowCount
End Sub

The implementation of button1_Click method copies the search criteria from the text box in the field _query.  Then it clears the previously cached data pages and obtains the first page of data. Last, the method will figure the size of the virtual list.

In less than a hundred lines of code a remarkable functionality has been brought to life.

Press F5 to start the Northwind Product Browser for Windows. Click the Find button.

Product Browser retreives pages of data from the web app as user scrolls the list view

Try scrolling the list of products. The Windows client will make at the most 8 requests to retrieve the 77 products from the Northwind database sample. The page size in this implementation is deliberately set to 10 items to ensure that a client-server interaction does occur upon scrolling.  If the page size is not specified then the default page size of 100 will be used.

Enter “40 biscuit” in the text box textBox1 and hit the button one more time. The two products matching the search criteria will be retrieved. Compare the result to the web app screenshot at the top.

Product Browser perform 'Quick Find' function with the help of the application server emdeded in the web app created with Code On Time

The same technique of data paging can be used in any application that supports XML or JSON data formats. That includes Java applications and mobile native Android and iPhone/iPad apps.

Continue to Duplicate Action