Pages

Saturday 28 January 2012

Grid editing using wcf

ajax.svc

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Web;

namespace gridediting
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Ajax
    {
            [WebGet(BodyStyle = WebMessageBodyStyle.Wrapped,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/GetRelatives")]
        [OperationContract]
        public PageData GetRelatives()
        {
            //        [0]: "_dc"
            //[1]: "page"
            //[2]: "start"
            //[3]: "limit"
            //int dc = int.Parse(string.IsNullOrEmpty(HttpContext.Current.Request["_dc"]) ? "0" : System.Web.HttpContext.Current.Request["_dc"].ToString());
            int start = int.Parse(string.IsNullOrEmpty(HttpContext.Current.Request["start"]) ? "0" : System.Web.HttpContext.Current.Request["start"].ToString());
            int end = int.Parse(string.IsNullOrEmpty(HttpContext.Current.Request["limit"]) ? "0" : System.Web.HttpContext.Current.Request["limit"].ToString());
            int page = int.Parse(string.IsNullOrEmpty(HttpContext.Current.Request["page"]) ? "0" : System.Web.HttpContext.Current.Request["page"].ToString());
            System.Collections.Generic.List<Person> people = new System.Collections.Generic.List<Person>();
            string s = string.Format("SELECT  pid,FirstName, LastName, Age,startdate FROM (SELECT  ROW_NUMBER() OVER (ORDER BY FirstName ASC) AS Row, pid,FirstName, LastName, Age,startdate FROM person2) AS LogWithRowNumbers WHERE  Row >{0} AND Row <= {1}", start, (start + end));
            SqlDataAdapter da = new SqlDataAdapter(s, con);
            SqlCommandBuilder cb = new SqlCommandBuilder(da);
            //DataSet ds = new DataSet();
            DataTable dt = new DataTable();
            da.Fill(dt);
            foreach (DataRow dr in dt.Rows)
            {
                people.Add(new Person(dr.ItemArray[1].ToString(), dr.ItemArray[2].ToString(), int.Parse(dr.ItemArray[3].ToString()), int.Parse(dr.ItemArray[0].ToString()), dr.ItemArray[4].ToString()));
            }
            SqlCommand cmd = new SqlCommand("select count(*) from person2", con);
            con.Open();
            int row_count = int.Parse(cmd.ExecuteScalar().ToString());
            con.Close();
            PageData pg = new PageData(row_count);
            pg.Data = people;
            return pg;
            //return people;
        }

        //}
        [WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/Save")]
        [OperationContract]
        public string Save(String first, String last, Int32 age, String startdate)
        {
            string s = "insert into person2 values('" + first + "','" + last + "'," + age + ",'" + startdate + "')";
            SqlDataAdapter da = new SqlDataAdapter(s, con);
            DataSet ds = new DataSet();
            da.Fill(ds);
            return ("u r record has saved successfully");
        }

        [WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/update")]
        [OperationContract]
        public string update(String first, String last, Int32 age, Int32 pid, String startdate)
        {
            string s;
            SqlCommand cmd = new SqlCommand("select Max(pid)+1 from person2", con);
            con.Open();
            int max = int.Parse(cmd.ExecuteScalar().ToString());
            con.Close();
            if (pid==0)
            {
                pid = max;
                s = "insert into person2 values('" + first + "','" + last + "'," + age + ",'" + startdate + "')";
            }
            else
            {
                s = "update person2 set firstname='" + first + "',lastname='" + last + "',age=" + age + ",startdate='" + startdate + "'where pid=" + pid + "";

            }
            SqlDataAdapter da = new SqlDataAdapter(s, con);
            DataSet ds = new DataSet();
            da.Fill(ds);
            return ("u r record has saved successfully");
        }
        [WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/delete")]
        [OperationContract]
        public string delete(String first, String last, Int32 age,Int32 pid)
        {
            string s = " delete person2 where pid=" + pid + "";
            SqlDataAdapter da = new SqlDataAdapter(s, con);
            DataSet ds = new DataSet();
            da.Fill(ds);
            return ("u r record has Deleted successfully");
        }
    }
    [System.Runtime.Serialization.DataContract]
    public class PageData
    {
        public PageData(Int32 TotalCount)
        {
            totalCount = TotalCount;
        }
        [System.Runtime.Serialization.DataMember]
        public Int32 totalCount
        {
            get;
            set;
        }


        [System.Runtime.Serialization.DataMember]
        public List<Person> Data
        {
            get;
            set;
        }

    }

    [System.Runtime.Serialization.DataContract]
    public class Person
    {
        public Person(String first, String last, Int32 age, Int32 pid, String startdate)
        {
            FirstName = first;
            LastName = last;
            Age = age;
            Pid = pid;
            Startdate = startdate;
        }

        //public Person() { }
        [System.Runtime.Serialization.DataMember]
        public String FirstName
        {
            get;
            set;
        }
        [System.Runtime.Serialization.DataMember]
        public String LastName
        {
            get;
            set;
        }
        [System.Runtime.Serialization.DataMember]
        public Int32 Age
        {
            get;
            set;
        }
        [System.Runtime.Serialization.DataMember]
        public Int32 Pid
        {
            get;
            set;
        }
        [System.Runtime.Serialization.DataMember]
        public String Startdate
        {
            get;
            set;
        }
    }
}

webform.aspx



<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="gridediting.WebForm2" %>


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


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
     <link rel="stylesheet" type="text/css" href="ExtJS/resources/css/ext-all.css" />
    <script type="text/javascript" src="ExtJS/ext-all.js"></script>
    <script type="text/javascript">
        Ext.onReady(function () {
            Ext.QuickTips.init();
            function change(val) {
                if (val >= 21) {
                    return '<span style="color:green;">' + val + '</span>';
                } else if (val < 21) {
                    return '<span style="color:red;">' + val + '</span>';
                }
                return val;
            }
            Ext.define('User', {
                extend: 'Ext.data.Model',
                fields: [


       { name: 'FirstName', type: 'string' },
       { name: 'LastName', type: 'string' },
       { name: 'Age', type: 'int' },
       { name: 'Pid', type: 'int' }
      , { name: 'Startdate', type: 'date' }
                //, { name: 'indoor', type: 'bool' }
        ]
            });
          
           var myStore = Ext.create('Ext.data.Store', {
                pageSize: 5,
                autoLoad: true,
                autoSync: true,
                model: 'User',
                groupField: 'age',
                paramNames: {
                    start: "start",
                    limit: "end"
                },
                proxy: {
                    type: 'rest',
                    url: 'Ajax.svc/GetRelatives',
                    reader: {
                        type: 'json',
                        root: 'GetRelativesResult.Data',
                        totalProperty: 'GetRelativesResult.totalCount'
                    }
                }
            });


            var cellEditing = Ext.create('Ext.grid.plugin.RowEditing', {
                clicksToEdit: 2,
                listeners: {
                    'beforeedit': function (e) {
                        var me = this;
                        var allowed = !!me.isEditAllowed;
                        if (!me.isEditAllowed)
                            Ext.Msg.confirm('confirm', 'Are you sure you want edit?', function (btn) {
                                if (btn !== 'yes')
                                    return;
                                me.isEditAllowed = true;
                                me.startEdit(0, 0);
                            });
                        return allowed;
                    },
                    afteredit: function (e) {
                        this.isEditAllowed = false;
                        var p = grid.getSelectionModel().lastFocused.data;
                        Ext.Ajax.request({
                            url: 'Ajax.svc/update',
                            headers: { 'Content-Type': 'application/json' },
                            method: 'POST',
                            jsonData: { first: p.FirstName, last: p.LastName, age: p.Age, pid: p.Pid, startdate: p.Startdate },
                            success: function (f, a) {
                                var s = Ext.decode(f.responseText);
                                Ext.Msg.alert('Success', '' + f.responseText + '');
                            },
                            failure: function (response, options) {
                                Ext.MessageBox.alert('Failed', '' + response.responseText + '');
                            }
                        });
                        e.record.commit();
                    }
                }
            });
            var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
                groupHeaderTpl: 'Group: {name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
            });
          
           var sm = Ext.create('Ext.selection.CheckboxModel', {
                checkOnly: true,
                listeners: {
                    // prevent selection of records with invalid descriptions selectedRows[0].data selectedRows.length
                    beforeselect: function (selModel, record, index) {
                        if ((Ext.String.trim(record.get('FirstName')) == '')) {
                            var srows = selModel.getSelection(sm);
                            Ext.Msg.alert('Please complete the record! ', 'You cannot check these rows until you complete x field.' + srows.length + srows);
                            return false;
                        }
                    },
                    select: function (selModel, record, index) {
                        var selectedRows = selModel.getSelection(sm);
                        if (selectedRows.length > 0) {
                            for (var i = 0; i < selectedRows.length; i++) {
                                Ext.Msg.alert('msg', 'you have selected ' + selectedRows.length + ' row');
                            }
                        }
                    }
                }
            });
            var grid = Ext.create('Ext.grid.Panel', {
                store: myStore,
                frame: true,
                title: 'Users',
                features: [groupingFeature],
                columns: [{


                    xtype: 'rownumberer',
                    sortable: false
                },  { text: "Pid", id: 'Pid', header: 'Pid', dataIndex: 'Pid', sortable: true },
                { text: "FirstName", id: 'FirstName', header: 'Name'
            , dataIndex: 'FirstName', sortable: false, //editor: title_edit
                    field: { xtype: 'textfield', allowBlank: false },
                    renderer: function (value, metaData, record, row, col, store, gridView) {
                        metaData.tdAttr = 'data-qtip="' + record.get('Age') + ' is the age of ' + value + '"';
                        return value;
                    }
                    //            , xtype: 'templatecolumn'
                    //            , tpl: '<img src="group.gif" style="cursor:pointer;"> {FirstName}' //,fieldLabel: 'FirstName',name: 'first' }
                },
    { text: "LastName", id: 'LastName', header: 'LastName', dataIndex: 'LastName', sortable: false,
        editor: {
            xtype: 'textfield',
            allowBlank: false, fieldStyle: 'text-transform:uppercase'
        }
    },
    { text: "Age", id: 'Age', header: 'Age', dataIndex: 'Age', sortable: false, renderer: change,
        editor: {
            xtype: 'textfield',
            allowBlank: false
        }
    },
    {
        xtype: 'datecolumn',
        header: 'Start Date',
        dataIndex: 'Startdate',
        width: 90,
        editor: {
            xtype: 'datefield',
            allowBlank: false,
            format: 'm/d/Y'
                        ,
            minValue: '01/01/2006',
            minText: 'Cannot have a start date before the company existed!',
            maxValue: Ext.Date.format(new Date(), 'm/d/Y')
        }
    }, {
        header: 'Delete',
        xtype: 'actioncolumn'
, width: 40
, items: [{ // Delete button
   tooltip: 'Delete a Row',
   icon: 'delete.gif',
   handler: function (grid, rowIndex, colindex) {
       // Working with grid row data
       var record = grid.getStore().getAt(rowIndex);
       //Ext.Msg.alert('Delete', 'Delete user: ' + record.data.Pid);
       var p = record.data.Pid;
       Ext.Ajax.request({
           url: 'Ajax.svc/delete',
           headers: { 'Content-Type': 'application/json' },
           method: 'POST',
           jsonData: { pid: p },
           success: function (f, a) {
               var s = Ext.decode(f.responseText);
               Ext.Msg.alert('Success', '' + f.responseText + '');
           },
           failure: function (response, options) {
               Ext.MessageBox.alert('Failed', '' + response.responseText + '');
           }
       });


   } // eo handler
}]
    }
                //    , {
                //        
                //        header: 'Indoor?',
                //        dataIndex: 'indoor',
                //        width: 55
                //    }
                //    , { header: "DOJ", dataIndex: 'DOJ', renderer:
                //Ext.util.Format.dateRenderer('m/d/Y')
                //    }
        ]


 , fbar: ['->', {
     text: 'Clear Grouping',
     iconCls: 'icon-clear-group',
     handler: function () {
         groupingFeature.disable();
     }
 }, {
     text: 'Enable Grouping',
     iconCls: 'icon-clear-group',
     handler: function () {
         groupingFeature.enable();
     }
 }],
                //        tools: [{ // config 
                //        type: 'refresh' 
                //    }] ,
                //                selModel: {
                //                    selType: 'rowmodel'
                //                },
                selModel: sm,
                plugins: [
           cellEditing
        ],
                renderTo: 'example-grid',
                width: 600,
                height: 400,


                bbar: Ext.create('Ext.PagingToolbar', {
                    store: myStore,
                    displayInfo: true,
                    displayMsg: 'Displaying Records {0} - {1} of {2}',
                    emptyMsg: "No topics to display",
                    items: [
                '-', {
                    text: 'Show Preview',
                    enableToggle: true,
                    toggleHandler: function (btn, pressed) {
                        var preview = Ext.getCmp('gv').getPlugin('preview');
                    }
                }]
                }),


                tbar: [{
                    text: 'Add Record',
                    handler: function (btn) {


                        var form = Ext.create('Ext.form.Panel', {
                            renderTo: 'example-grid',
                            frame: true,
                            title: 'Person Details Form',
                            width: 300,
                            height: 200,
                            buttonAlign: 'center',
                            items: [{
                                xtype: 'textfield',
                                fieldLabel: 'FirstName',
                                //id: 'txtFirst',
                                name: 'first'//,
                                //allowBlank: false
                                //declare it after ending ext.create a = Ext.getCmp('email').focus();
                                ,listeners: {
      afterrender: function(field) {
        field.focus(false, 1000);
      }
    }
                            }, {
                                xtype: 'textfield',
                                fieldLabel: 'LastName',
                                //id: 'txtLast',
                                name: 'last'
                            }, {
                                xtype: 'textfield',
                                fieldLabel: 'Age',
                                //id: 'txtAge',
                                name: 'age'
                            }],
                            buttons: [{


                                text: 'Save',
                                icon: 'disk.png',
                                handler: function () {
                                    var formValues = form.getValues();
                                    Ext.Ajax.request({
                                        url: 'Ajax.svc/Save',
                                        headers: { 'Content-Type': 'application/json' },
                                        method: 'POST',
                                        jsonData: { first: formValues.first, last: formValues.last, age: formValues.age },
                                        success: function (f, a) {
                                            var s = Ext.decode(f.responseText);
                                            Ext.Msg.alert('Success', '' + f.responseText + '');
                                        },
                                        failure: function (response, options) {
                                            Ext.MessageBox.alert('Failed', '' + response.responseText + '');
                                        }
                                    });
                                }
                            }]
                        });
                        btn.disable();
                    }


                }, '-', {
                    text: 'Add Row',
                    tooltip: 'Add a new row',
                    //                    width: 64,
                    //                    height: 64,
                    icon: 'add.gif',
                    //iconCls: 'startbutton',
                    //                    style: 'background-color: #F1F1F1; margin: 30px auto;'
                    //               + 'position: relative;' // support the [+] button
                    //        ,
                    handler: function () {
                        // Create a record instance through the ModelManager
                        var r = Ext.ModelManager.create({
                            //FirstName: 'New Plant 1',
                            checkOnly: false,
                            FirstName: '',
                            LastName: '',
                            Age: '',
                            pid: '',
                            Startdate: new Date()
                        }, 'User');
                        //add new row at first
                        //                        myStore.insert(0, r);
                        //                        cellEditing.startEditByPosition({ row: 0, column: 0 });
                        //add new row at last
                        myStore.insert(grid.getStore().getCount(), r);
                        cellEditing.startEdit(grid.getStore().getCount() - 1, 0);
                    }
                }, '-', 
                {
                    text: 'Delete Row',
                    cls: 'x-btn-text-icon',
                    icon: 'delete.gif',
                    handler: function () {
                        if (grid.getSelectionModel().getCount() == 0) {
                            Ext.MessageBox.alert("No Records Selected", "You have not selected any records for removal. Please select one or more records and try again.");
                        } else {
                            myStore.remove(grid.getSelectionModel().getSelection());
                            //grid.reconfigure();
//                            var p = grid.getSelectionModel().lastFocused.data;
//                            Ext.Ajax.request({
//                                url: 'Ajax.svc/delete',
//                                headers: { 'Content-Type': 'application/json' },
//                                method: 'POST',
//                                jsonData: { first: p.FirstName, last: p.LastName, age: p.Age, pid: p.Pid, startdate: p.Startdate },
//                                success: function (f, a) {
//                                    var s = Ext.decode(f.responseText);
//                                    Ext.Msg.alert('Success', '' + f.responseText + '');
//                                },
//                                failure: function (response, options) {
//                                    Ext.MessageBox.alert('Failed', '' + response.responseText + '');
//                                }
//                            });
                        }
                    }
                }, '-', {
                    text: 'Save',
                    icon: 'disk.png',
                    handler: function () {
                        var p = grid.getSelectionModel().lastFocused.data;
                        Ext.Ajax.request({
                            url: 'Ajax.svc/update',
                            headers: { 'Content-Type': 'application/json' },
                            method: 'POST',
                            jsonData: { first: p.FirstName, last: p.LastName, age: p.Age, pid: p.Pid, startdate: p.Startdate },
                            success: function (f, a) {
                                var s = Ext.decode(f.responseText);
                                Ext.Msg.alert('Success', '' + f.responseText + '');
                            },
                            failure: function (response, options) {
                                Ext.MessageBox.alert('Failed', '' + response.responseText + '');
                            }
                        });
                    }
                }
                //                , {
                //                    xtype: 'textfield',
                //                    listeners: {
                //                        specialkey: Movies.doSearch
                //                    }
                //                }
                ]
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div id="example-grid">
    
    </div>
    </form>
</body>
</html>

web.config

<system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="WebScriptBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="WebScriptBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
     multipleSiteBindingsEnabled="true" />
    <services>
      <service name="gridediting.Ajax">
        <endpoint address="" behaviorConfiguration="WebScriptBehavior"
         binding="webHttpBinding" contract="gridediting.Ajax" />
      </service>
    </services>
  </system.serviceModel>

Wednesday 25 January 2012



This is a part of EXT JS Tutorial
In this article I will cover information about creating, submitting and validating a forms with Ext JS library.
Submitting form to the server will be based on ASP.NET MVC page, so create a new MVC project in Visual Studio and add a EXT JS library into it. How to do it I have written here. So let’s create our first form.

How to create a simple form – first example.
              var form = new Ext.form.FormPanel({ //(1)
                    renderTo: Ext.getBody(), //(2)
                    url: 'Home/SubmitForm',
                    frame: true,
                    title: 'Tell me sth about yourself',
                    width: 200,
                    items: [{ //(3)
                        xtype: 'textfield',
                        fieldLabel: 'Your name',
                        name: 'name'
                    }, {
                        xtype: 'numberfield',
                        fieldLabel: 'Age',
                        name: 'age'
              }]
                    });

Listing above shows:

            (1) FormPanel is used to group fields in a single panel. It corresponds to a <form> tag in XHTML. FormPanel takes one argument which is a config object.
            (2) In the config object you can specify the form properties, one by line in this example, but this is not required. You can write all in one line remembers only to separate them with a colon (,). Placing them one after another may improve readability.
            (3) All fields, like html textbox, combobox and other in FormPanel are definied as elements of the items collection. One record for one field. In EXT JS you can create these fields in two ways. Above is presented first. The second looks like:
           var nameTextField = new Ext.form.TextField({
                    fieldLabel: 'Your name',
                    name: 'name'
                });
                var ageNumberField = new Ext.form.NumberField({
                    fieldLabel: 'Age',
                    name: 'age'
                });

                var form = new Ext.form.FormPanel({ //(1)
                    renderTo: Ext.getBody(), //(2)
                    url: 'Home/SubmitForm',
                    frame: true,
                    title: 'Tell me sth about yourself',
                    width: 200,
                    items: [ //(3)
                nameTextField,
                ageNumberField
]
                });

In both situations the result looks the same:






Other fields

Except TextField and NumberField we can use:

-radio buttons

                    {
                        xtype: 'radio',
                        fieldLabel: 'Sex',
                        name: 'sex',
                        boxLabel: 'male'
                    }, {
                        xtype: 'radio',
                        name: 'sex',
                        hideLabel: false,
                        boxLabel: 'female'
                    }

Important is here to set the name to the same value. Thanks to it, it is possible to check the value in action method on the server.

-checkbox
 

                    {
                        xtype: 'checkbox',
                        name: 'siblings',
                        fieldLabel: 'Siblings'
                    }

-combobox

To combobox field are added pairs, with key and the value. The key can be read after submitting the form in the server side code, value this is what user can see in the browser when he selected one from the available options.
EXT provides special store objects, where data can be kept. This feature will be covered in one of the next parts.
At this point look only for below example, which is used to work with combobox field:
                var answers = new Ext.data.SimpleStore({
                    fields: ['id', 'answer'],
                    data: [['1', 'yes'], ['2', 'no']]
                });

and the combo:
                   {
                        xtype: 'combo',
                        store: answers,
                        mode: 'local',
                        fieldLabel: 'available answers',
                        name: 'answer',
                        anchor: '90%',
                        displayField: 'answer',
                        valueField: 'id'
                    }

As you can see, in the combo to the store config option is link the SimpleStore object with handle the data. To the displayField and valueField are assigned fields from used store.



-datefield

                    {
                        xtype: 'datefield',
                        name: 'date',
                        fieldLabel: 'Select date',
                        anchor: '90%',
                        disabledDays: [0,6]
                    }















-timefield
                    {
                        xtype: 'timefield',
                        name: 'time',
                        fieldLabel: 'Time',
                        anchor: '90%'
                    }






















-textarea
                    {
                        xtype: 'textarea',
                        name: 'area',
                        fieldLabel: 'Enter some text',
                        anchor: '90%',
                        multiline: true
                    }

Listeners

For each field in documentation you can find a lot of events. This is very easy to listen to them in EXT JS. Look at example of using a invalid event:
                var nameTextField = new Ext.form.TextField({
                    fieldLabel: 'Your name',
                    name: 'name',
                    allowBlank: false,
                    listeners: {
                        invalid: function(field, msg)
                        {
                            Ext.Msg.alert('', msg);
                        }
                    }
                });

In this code, when you leave blank the Name field, the error message you will see in the alert dialog instead of baloon.










Submitting form to the server

In previous paragraph I have showed how to create a form to take data from user. Now I would like to concentrate how to send and use these data in a server side code. To be able to send the data to the server, form must have a button to do that. FormPanel contain similar to the items collection, collection of buttons. Look at this code
               buttons: [{
                    text: 'Save',
                    handler: function()
                    {
                        form.getForm().submit({
                            success: function(a, b)
                            {
                                Ext.Msg.alert('Success', 'ok');
                            },
                            failure: function(a, b)
                            {
                                Ext.Msg.alert('Failure', b.result.error);
                            }
                        });
                    }
                }, {
                    text: 'Reset',
                    handler: function()
                    {
                        form.getForm().reset();
                    }
                 }]

In code below there are created two buttons, one for submit the form and one for reset it. Both have a handler methods. In handler method you can specify, what will be done when the button is pressed. In the Save button there is called the submit method and checked the result .
Before we can submit the form, we must create a action method in the controller class:
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SubmitForm(FormCollection collection)
        {
            string response = String.Empty;
            //validation here
            try
            {
                string name = collection.GetValue("name").AttemptedValue;
                int age = Convert.ToInt32(Request.Form["age"]);
                response = "{success: true}";
            }
            catch (Exception)
            {
                response = "{success: false, error: \”an error occurred\”}";
            }
            return Content(response);
        }

In this code, in action method the submitted data should be validated if it hasn’t been done in the client code. The next two paragraphs are devoted to client side validation.

Developer can determine in the submit method, if the result is successful or not. Both, success and failure takes two arguments, which determine: the first is the form that requested this action, the second: the response from the server.

Build-in validation

At this point when you click the Save button, everything seems to work fine. However in the fields for name and age you can almost insert whatever you want. That’s true, in the numberfield you can insert only numbers, but these numbers can be negative too. Negative age it isn’t something what we want.












As I mentioned earlier, you can validate these fields on the server, but better way would seem to be validate it from the client side. EXT JS provides the stuff to do it. Suppose that, we would like to have the possibility to insert into the Name field only a alphabetic characters and this field must have a value (can’t be empty). For validation we can use a build-in vtype types. We can distinguish the basics: url, email, alpha and alphanum. These names are so obvious that I don't need to describe them, I think . Ok, it’s time to show how to use them
                var nameTextField = new Ext.form.TextField({
                    fieldLabel: 'Your name',
                    name: 'name',
                    vtype: 'alpha',
                    allowBlank: false
                });

As you can see I added two new lines. Thanks to the first line you can not add anything that is not a sign from the alphabet now. Second defines that, the field can’t be empty. When you try to submit the form without the value in the Name field, you will see an error










The field in underlined and nothing else. You can customize it by adding a new line
            Ext.QuickTips.init();

just under the Ext.onReady function. Using it, when you mouse over the field, you will see a balloon with the message showing what went wrong












To validate an Age field you can use config options, like maxValue, allowNegative, allowDecimals, allowBlank and minValue.
               var ageNumberField = new Ext.form.NumberField({
                    fieldLabel: 'Age',
                    name: 'age',
                    maxValue: 100,
                    allowNegative: false,
                    allowDecimals: false,
                    allowBlank: false,
                    minValue: 10
               });

Custom validation

Using EXT JS you can create your own, custom validation. The build-in vtypes are very limited. For example in the field where user must write his name, there are available only characters from ASCII, or in other words only characters which appear in English alphabet. In this situation I’m not able to put there my name, which contains polish specified characters. Everyone with different locale that English will be have this problem.
To create a custom vtype we need to add it to the vtype definition. Lets see an example. This code allows to use a polish letters in the TextField, additionally the first letter for surname and first for firstname will be capitalized.
                Ext.form.VTypes['ValidNameVal'= //(1)
                        /^[A-ZŁŻ][A-ZŻŁŚŹa-ząłęóźżńćś\-]+ [A-ZŁŻ][A-ZŻŁŚŹa-ząłęóźżńćś\-]+$/;
                Ext.form.VTypes['ValidNameMask'= /[A-ZŻŁŚŹa-ząłęóźżńćś\- ]///(2)
                Ext.form.VTypes['ValidNameText'= 'Invalid name'//(3)
                Ext.form.VTypes['ValidName'= function(arg//(4)
                {
                    return Ext.form.VTypes['ValidNameVal'].test(arg);
                }

At first glance it may look horrible. Especially because of the used regular expression (regex) if you are not familiar with this syntax. Each vtype definition has a:

            (1) Value – here is the regex to match to the user input
            (2) Mask – here are specified characters, which user can input in the field,
            (3) Text – this is the message with the error description
            (4) The last require element – the function for testing

Below example shows how it look like in the web browser. To use this custom vtype, you must change the definition for TextField from
            var nameTextField = new Ext.form.TextField({
                fieldLabel: 'Your name',
                name: 'name',
                vtype: ‘alpha,
                allowBlank: false
            });

to
               var nameTextField = new Ext.form.TextField({
                    fieldLabel: 'Your name',
                    name: 'name',
                    vtype: 'ValidName',
                    allowBlank: false
                });

Result










As you can see, with polish letters I have no problem any more. If error occur (first letter for my surname is not capitalize) , validation works properly:










Summary

In this part I have covered how to work with forms using the EXT JS library and ASP.NET MVC. I’ve showed how to create, validate and submit them to the server. And at the end the possibility of creating own custom validation. That’s not all what is related to forms in this library. In next parts there will be explained how to create and use them with the layouts, further will be showed how to work with data stores and other.
The source code with above examples is available here (click the blue button called "Pobierz plik").