Ext


Go Back   Ext JS Forums > Ext JS Community Forums (2.0) > Ext 2.x: Help

Reply
 
Thread Tools
  #1  
Old 11-16-2007, 10:06 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
Default EditorGrid - working example (php/mysql backend)

Mar 22 2008:
I've attached an updated php file. Demonstrates how you might do filtering, sorting, etc. server side. The filtering isn't tested too much, so please relay any bug fixes.

Original:
I thought I'd share an EditorGrid example that I've been learning with. The code provided works with a php/mysql backend with Ext2.0rc1.

I'll just include the code for the files, the commenting within the code is pretty excessive so I don't know that adding any additional commentary is needed. The .zip is attached. The following posts for each file are shown for an advance view and commenting (but do not reflect the current attached file any longer).

In order for the relative paths and css to work out of the box you should extract the attachment to the examples/ directory of your default download package.

L ext
    L adapter
    L build
    L docs
    L examples
        L grid-php <--Here
There is a companion tutorial for this thread, but currently it just points back to this thread.

The provided code is far from perfect (use at your own risk, etc.), but it does showcase some of the things you can do with the grids. When this code was done there were several things I had not quite figured out yet, but I figured sharing something less than perfect was better than sharing nothing at all.

I would not use this code as is in a production environment. Instead I would suggest just reading and learning from this code.

Constructive criticism is appreciated......

Features
  • filtering - filter what is shown in the grid (local or remote filtering)
  • configurable paging
  • context menu - right click in the grid to see options (see Bugs)
  • dropdowns - editable dropdowns (client and server side sources - see Bugs)
  • check box - column with checkable field
  • date - date updates on server (see Issues)
  • code cleanup (looks much longer because I've tried to keep each line to 80 characters)

Bugs / Known Issues
  • dropdowns
    • dropdown when using server side store is finicky (additional comments in file)
  • date - there's probably a better way to deal with the date object?
  • selectFirstRow - this should be done from grid 'render' listener

Future Plans
  • printing - implement TCPDF/FPDF (another suggestion here; see Grid FAQ for other extensions)
  • improve organization, speed?

I've posted a grid FAQ that might be of some help as well.

Download Problems: If you have any problems downloading try firefox instead of internet explorer (IE has problems sometimes).
Attached Images
File Type: jpg grid.jpg (46.3 KB, 13308 views)
Attached Files
File Type: zip grid-php.zip (52.9 KB, 15050 views)
File Type: zip grid-editor-mysql-php php file only.zip (4.5 KB, 3061 views)

Last edited by mjlecomte; 10-19-2008 at 09:47 AM.. Reason: minor edits
Reply With Quote
  #2  
Old 11-16-2007, 10:14 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
Default sql file

create database if not exists `test`;

USE `test`;

/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

/*Table structure for table `industry` */

DROP TABLE IF EXISTS `industry`;

CREATE TABLE `industry` (
  `industryID` int(10) unsigned NOT NULL auto_increment,
  `industryName` varchar(40) NOT NULL default '',
  PRIMARY KEY  (`industryID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;

/*Data for the table `industry` */

insert  into `industry`(`industryID`,`industryName`) values (1,'automotive'),(2,'computer'),(3,'finance'),(4,'food'),(5,'manufacturing'),(6,'medical'),(7,'retail'),(8,'services');

/*Table structure for table `stock` */

DROP TABLE IF EXISTS `stock`;

CREATE TABLE `stock` (
  `companyID` int(10) unsigned NOT NULL auto_increment,
  `company` varchar(40) default '',
  `price` float default NULL,
  `change` float default NULL,
  `pctChange` float default NULL,
  `lastChange` datetime default NULL,
  `industryID` int(10) default NULL,
  `risk` enum('low','medium','high') default NULL,
  `stars` enum('1','2','3','4','5') default NULL,
  `check` tinyint(1) default NULL,
  PRIMARY KEY  (`companyID`)
) ENGINE=InnoDB AUTO_INCREMENT=2036 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;

/*Data for the table `stock` */

insert  into `stock`(`companyID`,`company`,`price`,`change`,`pctChange`,`lastChange`,`industryID`,`risk`,`stars`,`check`) values (1,'Alcoa',23.33,0.42,1.47,'2007-10-02 00:00:00',5,'low','5',0),(2,'General Electric Company',22,-0.08,-0.23,'2007-10-02 00:00:00',5,'high','3',1),(144,'Altria Group Inc',10,0.28,0.34,'2007-02-02 00:00:00',5,'low','4',1),(145,'American Express Company',51,0.01,0.02,'2007-10-26 00:00:00',4,'low','2',1),(146,'AT&T',31.63,-0.48,-1.54,'2007-12-25 00:00:00',8,'medium','3',1),(148,'Caterpillar Inc.',67.27,0.92,1.39,'2007-10-02 00:00:00',5,'low','3',1),(149,'E.I. du Pont de Nemours and Company',10,0.51,1.28,'2007-10-02 00:00:00',5,'low','2',0),(150,'Exxon Mobil Corp',68.1,-0.43,-0.64,'2007-10-02 00:00:00',5,'medium','2',0),(152,'General Motors Corporation',30.27,1.09,3.74,'2007-10-02 00:00:00',1,'high','4',1),(154,'Honeywell Intl Inc',38.77,0.05,0.13,'2007-10-02 00:00:00',5,'high','5',0),(155,'Intel Corporation',19.88,0.31,1.58,'2007-10-02 00:00:00',2,'medium','2',0),(156,'International Business Machines',81.41,0.44,0.54,'2007-10-02 00:00:00',2,'medium','1',0),(157,'Johnson & Johnson',64.72,0.06,0.09,'2007-10-02 00:00:00',6,'high','2',0),(158,'JP Morgan & Chase & Co',45.73,0.07,0.15,'2007-10-02 00:00:00',3,'low','3',0),(162,'The Coca-Cola Company',45.07,0.26,0.58,'2007-10-02 00:00:00',4,'medium','2',0),(163,'The Procter & Gamble Company',61.91,0.01,0.02,'2007-10-02 00:00:00',5,'low','4',0),(164,'United Technologies Corporation',63.26,0.55,0.88,'2007-10-02 00:00:00',2,'high','5',1),(165,'Verizon Communications',35.57,0.39,1.11,'2007-10-02 00:00:00',8,'medium','4',0),(166,'3m Company',44,0.02,0.03,'2007-08-01 00:00:00',5,'low','1',1),(2009,'Boeing Co.',75.43,0.53,0.71,'2007-08-01 00:00:00',5,'low','3',1),(2015,'Hewlett-Packard Co.',36.54,-0.03,-0.08,'2007-08-01 00:00:00',2,'low','1',1),(2021,'McDonald\'s Corporation',36.76,0.86,2.4,'2007-08-01 00:00:00',4,'high','5',0),(2022,'Microsoft Corporation',25.84,0.14,0.54,'2007-08-01 00:00:00',2,'high','3',1),(2023,'Pfizer Inc',27.96,0.4,1.45,'2007-08-01 00:00:00',6,'high','5',0),(2030,'Citigroup',49.37,0.02,0.04,'2007-10-05 00:00:00',3,'high','3',0),(2031,'Merck & Co., Inc.',40.96,0.41,1.01,'2007-10-09 00:00:00',6,'medium','2',0),(2032,'Walt Disney Company (The) (Holding Compa',29.89,0.24,0.81,'2007-10-05 00:00:00',8,'low','2',1),(2033,'Wal-Mart Stores, Inc.',45.45,0.73,1.63,'2007-05-09 00:00:00',7,'medium','2',1),(2034,'American International Group, Inc.',10,0.31,0.49,'2007-06-09 00:00:00',2,'high','2',1),(2035,'The Home Depot',34.64,0.35,1.02,'2007-08-05 00:00:00',7,'medium','4',0);

Last edited by mjlecomte; 11-24-2007 at 01:32 AM.. Reason: added table, added column(s)
Reply With Quote
  #3  
Old 11-16-2007, 10:17 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
Default html

Note has some inline css for some of the rendering.


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Grid Example (MySQL/php)</title>

    <link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />

    <!-- GC -->
     <!-- LIBS -->
     <script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
     <!-- ENDLIBS -->

    <script type="text/javascript" src="../../ext-all-debug.js"></script>


    <script type="text/javascript" src="RowExpander.js"></script>
    <script type="text/javascript" src="grid-editor-mysql-php.js"></script>

    <link rel="stylesheet" type="text/css" href="grid-examples.css" />

    <!-- Common Styles for the examples -->

    <link rel="stylesheet" type="text/css" href="../examples.css" />

    <style type="text/css">
        body .x-panel {
            margin-bottom:20px;
        }
        .icon-grid {
            background-image:url(../../examples/shared/icons/fam/grid.png) !important;
        }
        #button-grid .x-panel-body {
            border:1px solid #99bbe8;
            border-top:0 none;
        }
        .add {
            background-image:url(../../examples/shared/icons/fam/add.gif) !important;
        }
        .option {
            background-image:url(../../examples/shared/icons/fam/plugin.gif) !important;
        }
        .remove {
            background-image:url(../../examples/shared/icons/fam/delete.gif) !important;
        }
        .refresh {
            background-image:url(../../examples/shared/icons/fam/table_refresh.png) !important;
        }
        .save {
            background-image:url(../../examples/shared/icons/save.gif) !important;
        }

        .red { color: red;}
    	.redcell { background-color:#FFE5E5 !important;}

		.greenrow { background-color:#C3FF8F !important;}
		.yellowrow { background-color:#FFFF66 !important;}
		.pinkrow { background-color:#FFE6CC !important;}
    	.x-grid3-col-classCompanyID { background-color:#F2F2F2 !important;}
 /*  	.x-grid3-col-classCompany { background-color:#FEFFE5 !important;} this shades the column but covers the red triangles*/

    	.stars1 { 
           background-image:url(../../examples/shared/icons/fam/user_suit.png) !important;
		   background-repeat: no-repeat;
		   background-position: center;
 		}
    	.stars2 { 
           background-image:url(../../examples/shared/icons/fam/user_red.png) !important;
		   background-repeat: no-repeat;
		   background-position: center;
 		}
    	.stars3 { 
           background-image:url(../../examples/shared/icons/fam/user_orange.png) !important;
		   background-repeat: no-repeat;
		   background-position: center;
 		}
    	.stars4 { 
           background-image:url(../../examples/shared/icons/fam/user_green.png) !important;
		   background-repeat: no-repeat;
		   background-position: center;
 		}
    	.stars5 { 
           background-image:url(../../examples/shared/icons/fam/user_gray.png) !important;
		   background-repeat: no-repeat;
		   background-position: center;
 		}
    </style>
</head>
<body>
<script type="text/javascript" src="../../examples/examples.js"></script><!-- EXAMPLES -->
<h1>Grid Example using MySQL and php</h1>
<p>This example shows how to create a grid from MySQL data with php backend.</p>
<p>Note that the js is not minified so it is readable. See <a href="grid-mysql-php.js" target="_blank">grid-mysql-php.js</a> and the <a href="../../docs/" target="_blank">API Docs</a>.</p>


<!-- you must define the select box here, as the custom editor for the 'Light' column will require it -->
<select name="riskName" id="riskID" style="display: none;">
	<option value="low">Low</option>
	<option value="medium">Medium</option>
	<option value="high">High</option>
</select>
   
<div id="grid-example"></div>
 <!---->
</body>
</html>
Reply With Quote
  #4  
Old 11-16-2007, 10:23 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
Default php file

Just enough to make it work basically. Uses post requests (mostly), no validation etc. is done.

You'll notice the tax function is very trivial. I basically just wanted to test out running to the server to update the grid, similar to using a php library or something.

Note if you're working with less than php5.2 the json.php library is required, but is included in the zip package.



<?php   

//database parameters
$user='test';   //user
$pw='test';     //user password
$db='test';     //name of database
$table='stock'//name of table data stored in

$taxRate 0.06;
    
//make database connection
$connection mysql_connect("localhost"$user$pw) or
   die(
"Could not connect: " mysql_error());
mysql_select_db($db) or die("Could not select database");

$task = ($_POST['task']) ? ($_POST['task']) : null;

//switchboard for the CRUD task requested
switch($task){
    case 
"create":
        
addData();
        break;
    case 
"readStock":
        
showData('stock');
        break;
    case 
"readIndustry":
        
getData('industry');
        break;
    case 
"update":
        
saveData();
        break;
    case 
"delete":
        
removeData();
        break;
    case 
"calcTax":
        
getTax();
        break;
    default:
        echo 
"{failure:true}";
        break;
}
//end switch

    
function showData($table
{
    global 
$taxRate;
    
     
/* By specifying the start/limit params in ds.load 
      * the values are passed here
      * if using ScriptTagProxy the values will be in $_GET
      * if using HttpProxy      the values will be in $_POST (or $_REQUEST)
      * the following two lines check either location, but might be more
      * secure to use the appropriate one according to the Proxy being used
      */
    
$start = (integer) (isset($_POST['start']) ? $_POST['start'] : $_GET['start']);
    
$end = (integer) (isset($_POST['limit']) ? $_POST['limit'] : $_GET['limit']);  
    
    
$sql_count 'SELECT * FROM ' $table;
    
$sql $sql_count ' LIMIT ' $start ', '$end;
    
    
$result_count mysql_query($sql_count);
    
$rows mysql_num_rows($result_count);
    
    
$result mysql_query($sql);
    
    while(
$rec mysql_fetch_array($resultMYSQL_ASSOC)){
        
//these lines are to populate the tax column for the initial display
        //of the grid, any updates to the price are handled by another function below
        
$price $rec['price'];
        
$rec['tax'] = round($price * ($taxRate),2);
        
        
$arr[] = $rec;
    };

    if (
version_compare(PHP_VERSION,"5.2","<"))
    {    
        require_once(
"./JSON.php"); //if php<5.2 need JSON class
        
$json = new Services_JSON();//instantiate new json object
        
$data=$json->encode($arr);  //encode the data in json format
    
} else
    {
        
$data json_encode($arr);  //encode the data in json format
    
}

    
/* If using ScriptTagProxy:  In order for the browser to process the returned
       data, the server must wrap te data object with a call to a callback function,
       the name of which is passed as a parameter by the ScriptTagProxy. (default = "stcCallback1001")
       If using HttpProxy no callback reference is to be specified*/
    
$cb = isset($_GET['callback']) ? $_GET['callback'] : '';
       
     echo 
$cb '({"total":"' $rows '","results":' $data '})';

}
//end showData



function getData($table
{

    
$sql 'SELECT * FROM ' $table;
    
$result mysql_query($sql);

    while(
$rec mysql_fetch_array($resultMYSQL_ASSOC)){
        
$arr[] = $rec;
    };

    if (
version_compare(PHP_VERSION,"5.2","<"))
    {    
        require_once(
"./JSON.php"); //if php<5.2 need JSON class
        
$json = new Services_JSON();//instantiate new json object
        
$data=$json->encode($arr);  //encode the data in json format
    
} else
    {
        
$data json_encode($arr);  //encode the data in json format
    
}

    
/* If using ScriptTagProxy:  In order for the browser to process the returned
       data, the server must wrap te data object with a call to a callback function,
       the name of which is passed as a parameter by the ScriptTagProxy. (default = "stcCallback1001")
       If using HttpProxy no callback reference is to be specified*/
    
$cb = isset($_GET['callback']) ? $_GET['callback'] : '';
       
     echo 
$cb '({"results":' $data '})';

}
//end getData

                
function saveData()
{
    
/*
     * $key:   db primary key label
     * $id:    db primary key value
     * $field: column or field name that is being updated (see data.Record mapping)
     * $value: the new value of $field
     */ 

    
global $table;
    
$key $_POST['key'];
    
$id    = (integer) mysql_real_escape_string($_POST['keyID']);
    
$field $_POST['field'];
    
$value $_POST['value'];
    
$newRecord $id == 'yes' 'no';                   
    
    
//should validate and clean data prior to posting to the database

    
if ($newRecord == 'yes'){
        
//INSERT INTO `stock` (`company`) VALUES ('a new company');
        
$query 'INSERT INTO `'.$table.'` (`'.$field.'`) VALUES (\''.$value.'\')';
    } else {
        
$query 'UPDATE `'.$table.'` SET `'.$field.'` = \''.$value.'\' WHERE `'.$key.'` = '.$id;
    }

    
//save data to database                                                    
    
$result mysql_query($query);
    
$rows mysql_affected_rows();
    
    if (
$rows 0) {
        if(
$newRecord == 'yes'){
            
$newID mysql_insert_id();
            echo 
"{success:true, newID:$newID}";
        } else {
            echo 
"{success:true}";
        }
    } else {
        echo 
"{success:false}"//if we want to trigger the false block we should redirect somewhere to get a 404 page
    
}
}
//end saveData


function removeData()
{
    
/*
     * $key:   db primary key label
     * $id:    db primary key value
     */ 

    
global $table;
    
$key $_POST['key'];
    
$arr    $_POST['companyID'];
    
$count 0;


    if (
version_compare(PHP_VERSION,"5.2","<"))
    {    
        require_once(
"./JSON.php"); //if php<5.2 need JSON class
        
$json = new Services_JSON();//instantiate new json object
        
$selectedRows $json->decode(stripslashes($arr));//decode the data from json format
    
} else
    {
        
$selectedRows json_decode(stripslashes($arr));//decode the data from json format
    
}

    
//should validate and clean data prior to posting to the database
    
foreach($selectedRows as $row_id)
    {
        
$id = (integer) $row_id;
        
$query 'DELETE FROM `'.$table.'` WHERE `'.$key.'` = '.$id;
        
$result mysql_query($query); //returns number of rows deleted
        
if ($result$count++;
    }
    
    if (
$count) { //only checks if the last record was deleted, others may have failed

        /* If using ScriptTagProxy:  In order for the browser to process the returned
           data, the server must wrap te data object with a call to a callback function,
           the name of which is passed as a parameter by the ScriptTagProxy. (default = "stcCallback1001")
           If using HttpProxy no callback reference is to be specified*/
        
$cb = isset($_GET['callback']) ? $_GET['callback'] : '';
           
        
$response = array('success'=>$count'del_count'=>$count);


        if (
version_compare(PHP_VERSION,"5.2","<"))
        {    
            
$json_response $json->encode($response);
        } else
        {
            
$json_response json_encode($response);
        }

        echo 
$cb $json_response;
//        echo '{success: true, del_count: '.$count.'}';
    
} else {
        echo 
'{failure: true}';
    }
}
//end saveData

/**
 * Get Tax
 * Determine tax based on price
 */
function getTax()
{                              
    
$price $_POST['price'];

    if (
$price >= 0) {
        global 
$taxRate;

        
$tax round($price * ($taxRate),2);

        
$cb = isset($_GET['callback']) ? $_GET['callback'] : '';

        
$response = array('success'=>'true''tax'=>$tax);

        if (
version_compare(PHP_VERSION,"5.2","<"))
        {    
            require_once(
"./JSON.php"); //if php<5.2 need JSON class
            
$json = new Services_JSON();//instantiate new json object
            
$json_response $json->encode($response);
        } else
        {
            
$json_response json_encode($response);
        }

        echo 
$cb $json_response;
    } else {
        echo 
'{failure: true}';
    }
}
//end getTotal
?>

Last edited by mjlecomte; 11-24-2007 at 01:35 AM.. Reason: updated
Reply With Quote
  #5  
Old 11-16-2007, 10:29 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
Default js code

Last but not least is the js code. As mentioned, this is probably overly commented. It's basically a compilation of what I've picked up from the various tutorials, screencasts, manual, api, forums, etc.
I've tested on FF2.0.0.8 and IE7 and it appears to work ok.



/**
 * Editor Grid
 * Interacts with server side php/MySQL
 * November 18, 2007
 * Michael LeComte
 */

/**
 * Ext JS Library 2.0 RC 1
 * Copyright(c) 2006-2007, Ext JS, LLC.
 * licensing@extjs.com
 * http://extjs.com/license
 */

   /**
    * Three main things to do:
    * 1.0 Setup the Data Source (setupDataSource)
    * 2.0 Create the Column Model (getColumnModel)
    * 3.0 Build the Grid (buildGrid)
    */    

// Reference local blank image to prevent link back to extjs.com
Ext.BLANK_IMAGE_URL '../../resources/images/default/s.gif';
//-> this = window

// Create a namespace Object
/* By specifying our own namespace we encapsulate all variables and methods in one 
   global object in order to avoid any conflicts or changes when working with other
   javascript files. This pattern scales well as the project becomes more complex 
   and as its API grows. It stays out of the global namespace, provides publicly 
   addressable API methods, and supports protected or “private” data and methods 
   along the way.*/
Ext.namespace('myNameSpace'); //define namespace with some 'name'
/* This assigns an empty object myNameSpace as a member of the Ext object (but 
   doesn’t overwrite myNameSpace if it already exists).*/

   ////////////////////////////////////////////////////////////////////////////////////////
   
// Now we can begin adding members to the Ext.myNameSpace application using the Module Pattern
myNameSpace.myModule = function(){//creates a property 'myModule' of the namespace object

//-> this = window
    
    /******************/
    /*--Private Area--*/
    //  can only access this area via the Public Area
    
    /*--Private Variables--*/
    //  Not accessible directly from outside of the module 
    //  These lines executed before document fully loaded, so don't access DOM 
    //  from here (elements do not exist yet)
    
var myPrivateVar "I can be accessed only from within Ext.myNameSpace.myModule.";
    var 
ds;
    var 
dsIndustry;
    var 
grid//component
    
var colModel// definition of the columns
    
var gridForm;
    var 
myRecordObj;
    var 
myReader;
    var 
primaryKey='companyID';
    
    
    
/*--Private Functions--*/  
    //  Not accessible directly from outside of the module 
    
var myPrivateMethod = function () {
        
Ext.log("I can be accessed only from within Ext.myNameSpace.myModule");
    }
    

   
////////////////////////////////////////////////////////////////////////////////////////

   /**
    * 1.0 Setup the Data Source (setupDataSource)
    * 1.1 Create Data Record
    * 1.2 Define Reader
    * 1.3 Create Data Store(s)
    * 1.4 Load Data Store(s)
    */
    
function setupDataSource() {


        
/*1.1 Create data Record
          This creates a constructor for a specific record layout defining the fields
          that make up an individual row of data.  The Reader is what links the Data Object
          (server side source or other static variable) with the DataStore.  The data
          Record tells the Reader how to associate or map the data from the Data Object
          with the Data Store.
          You can create the data record inline during creation of the reader, but creating
          the object separately here offers us the ability to add records dynamically, as
          an example see the addRecord() function below.
          To create a data record, we pass in an array of field definition objects specifying
          how to reference the data in your Data Object (the source of your data, ie. a
          database or static variable 'myData') */
        
myRecordObj Ext.data.Record.create([
            {
name'company'mapping'company'sortDir'ASC'sortType'asUCString'},
                
/* name:    'name' by which the field is referenced within the Record.
                 *          It will match the columnModel "dataIndex" property
                 * mapping: required only if the 'reference' != mapping
                 *          where reference is the key in the source data file
                 *          eg. db field name, xml tag name, etc.
                 * sortDir: initial sort direction
                 * sortType: defines explicitly how to perform sort, see Ext.data.SortTypes
                 */
            
{name'price'type'float'},  //type = how the data should be displayed
            
{name'tax'type'float'},  //type = how the data should be displayed
            
{name'change'type'float'}, //will use mapping = 'change'
            
{name'pctChange'type'float'},
            
//in the following line dateFormat must match that from the data source (see 'Class Date' in API)
            
{name'lastChange'type'date'dateFormat'Y-m-d H:i:s'},
            {
name'industryID'},
            {
name'risk'},
            {
name'stars'},
            {
name'check'},
            {
nameprimaryKey}//Note the order of fields defined here does not matter, it doesn't relate
                              //to the order of the fields in your source, nor the order displayed in the grid
                              //You also do not have to include every field in your data source here
                              //So if your database table has 10 columns, you can specify 2 here if you want
        
]);

     
        
/*1.2. Define Reader
          The reader extracts the field's value from the data object creating an Array
          of Ext.data.Record objects.
          We need to specify where the reader should look in the response for the data,
          aka the 'root'.  We can also optionally tell the reader where to look for the
          total number of records the Data Object has in case we don't pass all of the
          data in one go (pagination, etc.).
          The Data Object can be in several different base formats, so we need to use
          the proper reader that knows how to deal with the data format, so we specify
          the reader based on the format of the data returned (Xml, Json, Array)
          */
        
myReader = new Ext.data.JsonReader({ //creates array from JSON response
        /* 
        var myReader = new Ext.data.ArrayReader({//creates array from static array
        var myReader = new Ext.data.XmlReader({  //creates array from XML response
        */
            //1st parameter for reader constructor is to specify config options for reader:
            
root'results'// name of the property that is container for an Array of row objects
            
totalProperty'total'/*name of the property from which to retrieve the
                                      total number of records in the dataset.  This is 
                                      only needed if the whole dataset is not passed in
                                      one go, but is being paged from the remote server.*/
            /* The response should come back like this (using Firebug, click on 'Net' tab, click line
               corresponding to serverside script, then click "Response" to view the response; can
               also get same information using the "Console" tab):
            ({"total":"29",  <----the 'totalProperty'
              "results":[    <----the 'root'
                {"0":"Alcoa Inc","company":"Alcoa Inc",
                 "1":"29.01","price":"29.01",
                 "2":"0.42","change":"0.42",
                 "3":"1.47","pctChange":"1.47",
                 "4":"2007-10-02 00:00:00","lastChange":"2007-10-02 00:00:00",
                 "5":"143","id":"143"},
                {next record},
                {next record}]})
            */
            //record: 'item' //the XML delimiter tag for each record (row of data)
            
idprimaryKey //the property within each row object that provides an ID for the record (optional)
        
},  //2nd parameter for reader constructor is record constructor object
            //that specifies the record definition (the recordType object containing the field mapping)                                                       
            
myRecordObj //instead of defining inline just pass a reference to the object 
        
);

        
/**
         * 1.3. Create Data Store(s)
         * Set up the data Store object
         * A 'Store' is a client side cache of Ext.data.Record objects which
         * provide input data for widgets.
         * Basically you create this representation of your server side data
         * by defining the objects which specify:
         * 1. proxy - 
         *             how to the read the raw data (which proxy type)
         *          where to read data (the url to the data source)
         *          method to read data (GET or POST request) 
         * 2. reader - takes data and breaks into columns
         */ 

        // Data Store #1
        
ds = new Ext.data.GroupingStore({ //if grouping
      //ds = new Ext.data.Store({ //if not grouping
            /*1. specify how and where to access data.
              If data is specified within this file this argument is null
              Otherwise there are a few options for pulling the data you'd use:
              a. HttpProxy      reads data from the same domain/server
              b. ScriptTagProxy reads data object from different domain/server
              c. MemoryProxy    passes data specified in constructor
              */
            //set the proxy (method to get the raw data) - required for ScriptTagProxy   
            //note if using HttpProxy you can just specify the url property (HttpProxy is created):
            
proxy: new Ext.data.HttpProxy({
                
//where to retrieve data
                
url'grid-editor-mysql-php.php'//url to data object (server side script)
                
method'POST'
            
}),   
            
baseParams:{task"readStock"},//this parameter is passed for any HTTP request
            /*2. specify the reader
              The Store object doesn't know what the data looks like or or what
              format it is in, so a 'reader' is used to read the data into Records
              The reader object defined here will process the data object and return
              an array of Ext.data.Record objects which are cached and keyed per 
              their id property mapping the data we need*/
            
readermyReader,
            
sortInfo:{field'company'direction"ASC"}
            
//remoteSort: true,//true if sort from server (false = sort from cache only)
            //groupField:'industry', //added for GroupingStore, specifies initial group sort
        
});

        
// Data Store #2
        // This store will hold the data for the dropdown options
        
dsIndustry = new Ext.data.Store({
            
proxy: new Ext.data.HttpProxy({
                
//where to retrieve data
                
url'grid-editor-mysql-php.php'//url to data object (server side script)
                
method'POST'
            
}),   
            
baseParams:{task"readIndustry"},//this parameter is passed for any HTTP request
            /*2. specify the reader*/
            
reader:  new Ext.data.JsonReader(
                {
                    
root'results',//name of the property that is container for an Array of row objects
                    
id'industryID'//the property within each row object that provides an ID for the record (optional)
                
},
                [
                    {
name'industryID'},//name of the field in the stock table (not the industry table)
                    
{name'industryName'}
                ]
            ),
            
sortInfo:{field'industryName'direction"ASC"}
        }
        );
//end dsIndustry        


        /*1.4 Load Data Store(s)
          Use ds.loadData to load data directly from static data block array 'myData'
             ds.loadData(myData); 
          Use ds.load to load data from dynamic data source*/
        
dsIndustry.load(); //load data store holding our data for the industry column dropdown options
                           //note originally I had this store load second.  But when I did that
                           //the grid was apparently getting rendered the first time before the dsIndustry
                           //store was loaded so the rendered wasn't working (because the 'poop' portion
                           //of the if statement below was invoked since the store didn't exist yet
                           //After playing around I've noticed that the store must get returned before
                           //the execution gets to the grid render() line, otherwise it will still render
                           //the grid but the store will be empty and thus display an empty grid.  If you
                           //use the paging toolbar refresh that will probably show all the data because
                           //it just refreshes the page from the cached data store        
        
ds.load({params: { //parameters for the FIRST page load, use baseParams above for ALL pages.
            
start0//pass start/limit parameters for paging
            
limitmyNameSpace.myModule.perPage//
        
}}); //it is at this point that we'll request the data from the server.
             //note that this file keeps going independent of the server, thus
             //making this an asynchronous process, hopefully the server will respond
             //prior to calling render() on the grid, otherwise we'll have a blank grid.
             //If you're stepping through firebug, it's at this point you'll see the
             //XHR get sent out.

    
// end setupDataSource
    
   ////////////////////////////////////////////////////////////////////////////////////////

   /**
    * 2.0 Get the Column Model (getColumnModel)
    *     We have all of this data that came from the source (possibly server side) and then
    *     we read that data into a client side cache (store).  Now we have to decide what
    *     parts of that data we want to display and how we want to display it.  We may have
    *     some data we don't want displayed, or want some of it shown in a particular way. 
    * 2.1 Create Custom Renderers
    * 2.2 Create the Column Model
    */
    
function getColumnModel() {
        if(!
colModel) { //only need to create columnModel if it doesn't already exist

            /*2.1. Create Custom Renderers*/

              /** 
               * Italic Custom renderer function
               * val rendered in italics
               * @param {Object} val
               */
            
function italic(val){
                return 
'<i>' val '</i>';
            };

            
/** 
             * Red/Green Custom renderer function
             * renders red if <0 otherwise renders green 
             * @param {Object} val
             */
            
function renderPosNeg(val){
                if(
val >= 0){
                
//-> this = obj (row from grid, properties of id, name='change', style)
                    
return '<span style="color:green;">' val '</span>';
                }else if(
val 0){
                    return 
'<span style="color:red;">' val '</span>';
                }
                return 
val;
            };

            
/** 
             * Percent Custom renderer function
             * Renders red or green with %
             * @param {Object} val
             */
            
function renderPctChange(val){
                if(
val >= 0){
                
//-> this = obj (row from grid, properties of id, name='pctChange', style)
                    
return '<span style="color:green;">' val '%</span>';
                }else if(
val 0){
                    return 
'<span style="color:red;">' val '%</span>';
                }
                return 
val;
            };

            
/** 
             * Risk Custom renderer function
             * Renders according to risk level
             * @param {Object} val
             */
            
function renderRisk(datacellrecordrowIndexcolumnIndexstore){
                switch(
data) {
                    case 
"high":
                        
cell.css "redcell";
                        return 
"high";
                    case 
"medium":
                        return 
"medium";
                    case 
"low":
                        return 
"low";
                }
            };

            
/** 
             * Star Custom renderer function
             * Renders a picture according to value
             * @param {Object} val
             */
            
function renderStars(datacellrecordrowIndexcolumnIndexstore){
                switch(
data) {
                    case 
"1":    cell.css "stars1";   return 1;//returns text over the background image
                    
case "2":    cell.css "stars2";   return;//just shows the background image
                    
case "3":    cell.css "stars3";   return;
                    case 
"4":    cell.css "stars4";   return;
                    case 
"5":    cell.css "stars5";   return;
                }
            };


            
/** 
             * Date renderer function
             * Renders a date
             * @param {Object} val
             */
            
function renderDate(value){
                
//Ext.util.Format.dateRenderer('m/d/Y')
                
return value value.dateFormat('M d, Y') : '';
            };


            
// custom column plugin example
            //var checkColumn = new Ext.grid.CheckColumn({
            
this.checkColumn = new Ext.grid.CheckColumn({
                
header"Check",
                
dataIndex'check'
                
width9
                
sortabletrue
            
});
    
            
/**
             * Check Column event listener
             * @param {Object} element
             * @param {Object} e
             * @param {Object} record
             */
            
this.checkColumn.on('click', function(elementerecord) {
                  
//alert(record.get('check'));
                
var myField this.dataIndex;//the field name
                
var check record.data[this.dataIndex];//same as record.data.check (but more abstract)
                
var checkStatus check 'checked' 'unchecked';
                var 
checkItem record.data.company;
                var 
checkID record.data.companyID;
                
Ext.example.msg('Item Check''You {0} the "{1}" check box, ID = {2}.'checkStatuscheckItemcheckID);
                var 
myMsg 'You <b>'checkStatus '</b> the "<i>' checkItem '</i>" check box, ID = ' '<span style="color:blue;">' checkID '</span>.';
                
Ext.MessageBox.alert('Item Check'myMsg);
                var 
checkBoolean check 0;

                
//update the database
                
Ext.Ajax.request(
                    { 
//ajax request configuration  
                        
waitMsg'Saving changes...',
                        
url'grid-editor-mysql-php.php'//url to server side script
                        
params: { //these will be available via $_POST or $_REQUEST:
                            
task"update"//pass task to do to the server script
                            
keyprimaryKey,//pass to server same 'id' that the reader used
                            
keyIDcheckID,//for existing records this is the unique id (we need this one to relate to the db)
                            //newRecord: isNewRecord,//pass the new Record status indicator to server for special handling
                            
fieldmyField,//the column name
                            
valuecheckBoolean,//the updated value
                            
originalValue: !checkBoolean//the original value (oGrid_Event.orginalValue does not work for some reason)
                        
},//end params
                        
failure:function(response,options){
                            
Ext.MessageBox.alert('Warning','Oops...');
                        },
//end failure block                                      
                        
success:function(response,options){
                            
//Ext.MessageBox.alert('Success','Yeah...');
                            
if(checkID == 0){
                                var 
responseData Ext.util.JSON.decode(response.responseText);//passed back from server
                                
var newID responseData.newID;//extract the ID provided by the server
                                
record.set('newRecord','no');//reset the indicator since update succeeded
                                
record.set('companyID',newID);//assign the id to the record
                                
ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                            
} else {
                                
ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                            
}
                        }
//end success block                                      
                     
}//end ajax request config
                
); //end ajax request  
            
});


            
/** 
             * 2.2. Create the Column Model
             * Set up the ColumnModel object to define the initial layout/display of the grid.
             * The order specified here defines the order of initial column display.
             * We also define how each column in the grid correlates (maps) to our 
             * DataStore with dataIndex. 
             *   "mapping"   specifies how the data object relates/maps to the DataStore (client side cache of data).
             *   "dataIndex" specifies how the DataStore   relates/maps to the ColumnModel (actual display).
             * It can be extended to provide custom or reusable ColumnModels 
             */
            
colModel = new Ext.grid.ColumnModel([ //instantiate ColumnModel
                   //Here we give comma separated definitions of the fields we want
                   //displayable (some may be initially hidden) in the grid.
                   //Note you need not display every column in your data store here;
                   //you can include fields here and have them be hidden or
                   //you can just not include some fields in your grid whatsoever (maybe
                   //you just retrieved them to do other behind the scenes processing
                   //client side instead of server side)
                
{  
                    
id:    'classCompanyID',//by placing an id on this column we can later reference the column specifically
                                     //For instance we could set a css style to highlight the column (.x-grid3-col-classCompanyID)
                                     //This doesn't work well with an editor grid though, as the red triangle gets covered up.
                                     //Perhaps something with the z-index could be changed so the red triangle remained on top?
                                     //Another use might be to select an entire column and do something with it
                                     //Example anyone?
                    
header:"ID",//header = text that appears at top of column
                    
width9,      //column width
                    
sortabletrue,//false (default) to disable sorting by this column
                    
lockedfalse,
                    
align'right',//default is to align to the left
                    //hidden: true, //true to initially hide the column
                    
dataIndex'companyID'//the DataStore field "name" this column draws its data from
                                        //dataIndex = rt name
                 
},{                         
                    
id:    'classCompany',//by placing an id on this column we can later reference the column specifically
                                     //currently the html page sets a css style to highlight the column (.x-grid3-col-classCompany)
                                     //we may be able to select an entire column and do something with it
                                     //example anyone?
                    
header:"Company",//header = text that appears at top of column
                    
width40,      //column width
                    
sortabletrue,//false (default) to disable sorting by this column
                    
lockedfalse,
                    
//resizable: false, //disable column resizing (can also used fixed = true)
                    
dataIndex'company',//the DataStore field "name" this column draws its data from
                                        //dataIndex = rt name
                    
editor: new Ext.form.TextField({ //TextField editor - for an editable field add an editor
                        //specify options
                        
allowBlankfalse //default is true (nothing entered)
                    
})                           
                },{                         
                    
header"Price"
                    
width12
                    
sortabletrue,
                    
//hidden: true,//true to initially hide the column 
                                   //(NOTE: as of Ext2.0-rc1 the GroupingStore has problems sizing the grid when columns are hidden)  
                    
rendererExt.util.Format.usMoney,//optional rendering function to provide customized data formatting 
                    
dataIndex'price',
                    
align'right',//default is to align to the left
                    
editor: new Ext.form.NumberField({
                        
//specify options
                        
allowBlankfalse,  //default is true (nothing entered)
                        
allowNegativefalse//could also use minValue
                        
maxValue100
                    
})
                },{                         
                    
header"Tax"
                    
width12
                    
sortabletrue,
                    
rendererExt.util.Format.usMoney,//optional rendering function to provide customized data formatting 
                    
dataIndex'tax',
                    
align'right'//default is to align to the left
                
},{
                    
header"Change"
                    
width12
                    
sortabletrue
                    
rendererrenderPosNeg
                    
dataIndex'change',
                    
align'center'
                
},
                {
header"% Change"width15sortabletruerendererrenderPctChangedataIndex'pctChange'},
                {
                    
header"Last Updated"
                    
width20
                    
sortabletrue
                    
rendererrenderDate
                    
dataIndex'lastChange',
                    
editor: new Ext.form.DateField({ //DateField editor
                        //specify options
                        
allowBlankfalse,  //default is true (nothing entered)
                        //format: 'd/m/y', //defaults to 'm/d/y', if there is a renderer 
                                           //specified it will render whatever this form
                                           //returns according to the renderer
                        
minValue'10/15/07'//anything prior to is greyed out/unclicklable
                                             //validator prevents typing a new date violating criteria 
                        
disabledDays: [036],
                        
disabledDaysText'Closed on this day'
                    
})
                },{
                    
header"Industry",
                    
width23
                    
sortabletrue
                    
dataIndex'industryID',//this is what is specified in the reader
                    
editor: new Ext.form.ComboBox({ //dropdown based on server side data (from db)
                        
typeAheadfalse//will be querying database so may not want typeahead consuming resources
                        
triggerAction'all',
                        
lazyRendertrue,//prevents combo box from rendering until requested, should always be true for editor
                        
storeds,//Industry,//where to get the data for our combobox
                        
displayField'industryName',//the underlying data  field name to bind to this ComboBox
                                                     //(defaults to undefined if mode = 'remote' or 'text' if transforming a select)
                        
valueField'industryID'     //the underlying value field name to bind to this ComboBox
                    
}),
                    
renderer:
                            function(
data) {
                                
record dsIndustry.getById(data);//same as accessing this.data.key(id)
                                
if(record) {
                                    return 
record.data.industryName;
                                } else {
                                    
//return data;
                                    
return 'poop';
                                }
                            }
                },{
                    
header"Risk",
                    
width11
                    
sortabletrue
                    
rendererrenderRisk
                    
dataIndex'risk',
                    
editor: new Ext.form.ComboBox({ //dropdown based on client side data (from html)
                        
typeAheadtrue,
                        
triggerAction'all',
                        
transform:'riskID',//look for this id to transform the html option values to a dropdown
                        
lazyRender:true,//prevents combo box from rendering until requested, should always be true for editor
                        
listClass'x-combo-list-small' //css class to apply to the dropdown list element
                    
})
                },{
                    
header"Stars",
                    
width8
                    
sortabletrue
                    
rendererrenderStars
                    
dataIndex'stars',
                    
align'center'
                
},
                
checkColumn //defined above
            
]);//end colModel
            
            //instead of specifying sorting permission by individual columns can also specify for entire grid
            //colModel.defaultSortable = false;

        
}//end if colModel
        
return colModel;
    }
//getColumnModel

   ////////////////////////////////////////////////////////////////////////////////////////

   /**
    * 3.0 Build the Grid (buildGrid)
    * 3.1 Create Handlers 
    * 3.2 Create (instantiate) the Grid 
    * 3.3 Render the Grid (make it lazy if you want) 
    * 3.4 Add listeners to the Grid 
    */
    
function buildGrid() {    
/*
        gridForm = new Ext.BasicForm(
            Ext.get("updategrid"),
            {
                
            }
        ); //end gridForm
*/            

        /**
         * 3.1. Create Handlers
         * Create functions to handle various events
         */

        /**
         * Function for Refreshing Grid
         */ 
        
function refreshGrid() {
            
ds.reload();//
        
}; // end refresh 

        /**
         * Handler for Adding a Record
         */
        
function addRecord() {
            var 
= new myRecordObj({
                
//specify default values
                
companyID0,//use this to trigger special handling when updating 
                
company''//you can't comment out this line if you want the editor
                             //to start there, as it will show the html tags
                
price0.00,
                
tax0.00,
                
change0.00,
                
pctChange0.00,
                
lastChange: (new Date()).clearTime(),
                
industry'',
                
risk'',
                
stars'0',
                
//newRecord:'yes',//use this to trigger special handling when updating
                //id: 0//this is not helpful, 
            
});
            
grid.stopEditing();//stops any acitve editing
            
ds.insert(0r); //1st arg is index,
                             //2nd arg is Ext.data.Record[] records
            //very similar to ds.add, with ds.insert we can specify the insertion point
            
grid.startEditing(01);//starts editing the specified rowIndex, colIndex
                                    //make sure you pick an editable location in the line above
                                    //otherwise it won't initiate the editor
        
}; // end addRecord 

        
        //add an event to handle any updates to grid
        
        
        /**
         * Handler to control grid editing
         * @param {Object} oGrid_Event
         */
        
function handleEdit(editEvent) {
            var 
gridField editEvent.field;//determine what column is being edited
            
updateDB(editEvent);//start the process to update the db with cell contents
            
            //I don't want to wait for server update to update the Total Column
            
if (gridField == 'price'){
                
getTax(editEvent);//start the process to update the Tax Field
            
}
        }
        
        
/**
         * Function for updating database
         * @param {Object} oGrid_Event
         */
        
function updateDB(oGrid_Event) {
            
            
/*Do we need to disable a new record from further editing while the first request
              is being made since the record may not have the new companyID in time
              to use to properly handle other updates of the same record? 
              
              Dates come through as an object instead of a string or numerical
              value, so do a check to prep the new value for transfer to the
              server side script*/
            
if (oGrid_Event.value instanceof Date)
            {   
//format the value for easy insertion into MySQL
                
var fieldValue oGrid_Event.value.format('Y-m-d H:i:s');
            } else
            {
                var 
fieldValue oGrid_Event.value;
            }    
                    
            
//submit to server
            
Ext.Ajax.request//alternative to Ext.form.FormPanel? or Ext.BasicForm
                
{   //specify options (note success/failure below that receives these same options)
                    
waitMsg'Saving changes...',
                    
//url where to send request
                    
url'grid-editor-mysql-php.php'//url to server side script
                    //method: 'POST', //if specify params default is 'POST' instead of 'GET'
                    
params: { //these will be available via $_POST or $_REQUEST:
                        
task"update"//pass task to do to the server script
                        
keyprimaryKey,//pass to server same 'id' that the reader used
                        
keyIDoGrid_Event.record.data.companyID,//for existing records this is the unique id (we need this one to relate to the db)
                                                                 //we'll check this server side to see if it is a new record                    
                     //   bogusID: oGrid_Event.record.id,//for new records Ext creates a number here unrelated to the database
                     //   newRecord: isNewRecord,//pass the new Record status indicator to server for special handling
                        
fieldoGrid_Event.field,//the column name
                        
valuefieldValue,//the updated value
                        
originalValueoGrid_Event.record.modified//the original value (oGrid_Event.orginalValue does not work for some reason)
                                                                  //this might(?) be a way to 'undo' changes other than by cookie?
                                                                  //when the response comes back from the server can we make an undo array?                         
                    
},//end params
                    //the function to be called upon failure of the request (404 error etc, NOT success=false)
                    
failure:function(response,options){
                        
Ext.MessageBox.alert('Warning','Oops...');
                        
//ds.rejectChanges();//undo any changes
                    
},//end failure block                                      
                    
success:function(response,options){
                        
//Ext.MessageBox.alert('Success','Yeah...');
                        
if(oGrid_Event.record.data.companyID == 0){
                            var 
responseData Ext.util.JSON.decode(response.responseText);//passed back from server
                            
var newID responseData.newID;//extract the ID provided by the server
                            //oGrid_Event.record.id = newID;
                            
oGrid_Event.record.set('newRecord','no');//reset the indicator since update succeeded
                            
oGrid_Event.record.set('companyID',newID);//assign the id to the record
                            //note the set() calls do not trigger everything since you may need to update multiple fields for example
                            //so you still need to call commitChanges() to start the event flow to fire things like refreshRow()
                            
ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                            //var whatIsTheID = oGrid_Event.record.modified;
                        
} else {
                            
ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                        
}
                    }
//end success block                                      
                 
}//end request config
            
); //end request  
        
}; //end updateDB 


        /**
         * Function for updating Tax shown in grid
         * @param {Object} oGrid_Event
         */
        
function getTax(oGrid_Event) {
            
            
//submit to server
            
Ext.Ajax.request//alternative to Ext.form.FormPanel? or Ext.BasicForm
                
{   //specify options (note success/failure below that receives these same options)
                    //waitMsg: 'Saving changes...',
                    //url where to send request
                    
url'grid-editor-mysql-php.php'//url to server side script
                    //method: 'POST', //if specify params default is 'POST' instead of 'GET'
                    
params: { //these will be available via $_POST or $_REQUEST:
                        
task"calcTax"//pass task to do to the server script
                        
priceoGrid_Event.value//the updated value
                    
},//end params
                    //the function to be called upon failure of the request
                    
failure:function(response,options){
                        
Ext.MessageBox.alert('Warning','Oops...');
                        
//ds.rejectChanges();//undo any changes
                    
},//end failure block                                      
                    
success:function(response,options){
                        
//Ext.MessageBox.alert('Success','Yeah...');
                        
var responseData Ext.util.JSON.decode(response.responseText);//passed back from server
                        
var myTax responseData.tax;//extract the value provided by the server
                        //oGrid_Event.record.data.tax = myTax;//assign the tax to the record
                        //oGrid_Event.record.tax= myTax;//assign the id to the record
                        
oGrid_Event.record.set('tax',myTax);
                        
ds.commitChanges();//commit changes (removes the red triangle which indicates a 'dirty' field)
                    
}//end success block                                      
                 
}//end request config
            
); //end request  
        
}; //end getTax 

        
        /**
         * Handler for Deleting record(s)
         */ 
        
function handleDelete() {
            var 
selectedKeys grid.selModel.selections.keys//returns array of selected rows ids only
            
if(selectedKeys.length 0)
            {
                
Ext.MessageBox.confirm('Message','Do you really want to delete selection?'deleteRecord);
            }
            else
            {
                
Ext.MessageBox.alert('Message','Please select at least one item to delete');
            }
//end if/else block
        
}; // end handleDelete 

        /**
         * Function for Deleting record(s)
         * @param {Object} btn
         */ 
        
function deleteRecord(btn) {
            if(
btn=='yes')
            {
                
/* block if just want to remove 1 row
                var selectedRow = grid.getSelectionModel().getSelected();//returns record object for the most recently selected
                                                                     //row that is in data store for grid
                if(selectedRow){
                    ds.remove(selectedRow);
                } //end of block to remove 1 row
                */
                
var selectedRows grid.selModel.selections.items;//returns record objects for selected rows (all info for row)
                
var selectedKeys grid.selModel.selections.keys//returns array of selected rows ids only

                //note we already did an if(selectedKeys) to get here

                
var encoded_keys Ext.encode(selectedKeys);//encode array into json
                //submit to server
                
Ext.Ajax.request//alternative to Ext.form.FormPanel? or Ext.BasicForm.submit
                    
{   //specify options (note success/failure below that receives these same options)
                        
waitMsg'Saving changes...',
                        
//url where to send request
                        
url'grid-editor-mysql-php.php'//url to server side script
                        
params: { //these will be available via $_POST or $_REQUEST:
                            
task"delete"//pass task to do to the server script
                            
companyIDencoded_keys,//the unique id(s)
                            
keyprimaryKey//pass to server same 'id' that the reader used
                        
},
                        
/* you can also specify a callback (instead of or in addition to 
                        success/failure) for custom handling.  If you have success/failure
                        defined, those will fire before 'callback'.  This callback will fire
                        regardless of success or failure.*/
                        
callback: function (optionssuccessresponse) {
                            if (
success) { //success will be true if the request succeeded
                                
Ext.MessageBox.alert('OK',response.responseText);//you won't see this alert if the next one pops up fast
                                
var json Ext.util.JSON.decode(response.responseText);
                                
Ext.MessageBox.alert('OK',json.del_count ' record(s) deleted.');//need to move this to an after
                                //event because it will fire before the grid is re-rendered (while the deleted row(s) are still there
                                //You could update an element on your page with the result 
                                //from the server (e.g.<div id='total'></div>)
                                //var total = Ext.get('total');
                                //total.update(json.sum);
                            
} else {
                                
Ext.MessageBox.alert('Sorry, please try again. [Q304]',response.responseText);
                            }
                        },
                        
/* */
                        //the function to be called upon failure of the request (server script, 404, or 403 errors)
                        
failure:function(response,options){
                            
Ext.MessageBox.alert('Warning','Oops...');
                            
//ds.rejectChanges();//undo any changes
                        
},                                      
                        
success:function(response,options){
                            
//Ext.MessageBox.alert('Success','Yeah...');
                            
ds.reload();//commit changes and remove the red triangle which indicates a 'dirty' field
                        
}                                      
                     } 
//end Ajax request config
                
);// end Ajax request initialization
            
};//end if click 'yes' on button
        
}; // end deleteRecord 


        /**
         * 3.2. Create (instantiate) the Grid
         * This creates the actual GUI for the Grid.
         * We specify here where, how, and when to render the Grid.
         */
      //grid = new Ext.grid.GridPanel({ //to instantiate normal grid
        
grid = new Ext.grid.EditorGridPanel({ //to instantiate editor grid
            //el:'grid-example', //html element (id of the div) where the grid will be rendered
            //'renderTo' does the same as 'el', except eliminated the need to explicitly call render() 
            //renderTo: 'grid-example',//could also render it directly to document.body 
             
iconCls'icon-grid',//we create our own css with a class called 'icon-grid'
            
storeds,       //the DataStore object to use (ds: is shorthand)
            
colModelgetColumnModel(), //gets the ColumnModel object to use (cm: is shorthand)
            
autoExpandColumn'company'//which column to stretch in width to fill up the grid width and not leave blank space
          //autoSizeColumns: true,//deprecated as of Ext2.0
            //Enable a Selection Model.  The Selection Model defines the selection behavior,
            //(single vs. multiple select, row or cell selection, etc.)
            
selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),//true to limit row selection to 1 row})
           //footer: true,
            
height:350,//you must specify height or autoHeight
            //autoHeight:true,//autoHeight resizes the height to show all records
            
width:740,
            
title:'This is the Grid Title',
            
clicksToEdit:2,//number of clicks to activate cell editor, default = 2        
            
plugins:this.checkColumn,
            
//frame:true,//add a frame around the grid; defaults to no frame 
            
cellclick: function()
            {
                var 
record grid.getStore().getAt(rowIndex); //get the record
                
var fieldName grid.getColumnModel().getDataIndex(columnIndex);//get field name
                
var data record.get(fieldName);
                
Ext.MessageBox.alert('title','inside function');
                   
//title: 'My Title Here',
                   //msg: 'outside the function...'
                   //fn: myCallBackFunction,//the callback function after the msg box is closed
                   //scope:this//scope of callback function   
            
},
            
stripeRowstrue,//applies css classname to alternate rows, defaults to false
            //trackMouseOver: true,//highligts rows on mousever
            //Add a bottom bar      
            
bbar: new Ext.PagingToolbar({
                
pageSizemyNameSpace.myModule.perPage,//default is 20
                
storeds,
                
displayInfotrue,//default is false (to not show displayMsg)
                
displayMsg'Displaying topics {0} - {1} of {2}',
                
emptyMsg"No data to display",//display message when no records found
                
items:[
                    
'-', {
                    
pressedtrue,
                    
enableToggle:true,
                    
text'Show Preview',
                    
cls'x-btn-text-icon details'
                    
//toggleHandler: toggleDetails  
                
}]
            }),
            
//Add a top bar      
            
tbar: [
                {
                    
text'Add Record',
                    
tooltip'Click to Add a row',
                    
iconCls:'add'//we create our own css with a class called 'add'
                                   //custom class not included in ext-all.css by default
                    
handleraddRecord //what happens when user clicks on it
                
}, '-'//add a separator
                
{
                    
text'Delete Selected',
                    
tooltip'Click to Delete selected row(s)',
                    
handlerhandleDelete//what happens when user clicks on it
                    
iconCls:'remove' //we create our own css with a class called 'add'
                
}, '-'//add a separator
                
{
                    
text'Refresh',
                    
tooltip'Click to Refresh the table',
                    
handlerrefreshGrid//what happens when user clicks on it
                    
iconCls:'refresh' //we create our own css with a class called 'add'
                
}
            ],
            
//this is the key to showing the GroupingStore
            
view: new Ext.grid.GroupingView({
                
forceFit:true,
                
//custom grouping text template to display the number of items per group
                
groupTextTpl'{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
            
}) /**/
        
});//end grid
     
        // ## THIS DOES NOT WORK ## //
        /*  
        var rz = new Ext.Resizable("grid-example",{
            wrap:true,
            minHeight:100,
            pinned: true,
            handles:'all'
        });
        rz.on("resize", grid.autosize, grid);
        */ 

        /**
         * 3.3 Render the Grid (make it lazy if you want)
         * Explicitly rendering the grid is only required if "renderTo" is not specified
         * in the configuration of the grid object above.
         * In Ext2.0, every component automatically supports "lazy" (on demand) rendering.
         * The rendering pipeline is managed automatically if you use "renderTo" in the
         * grid constructor.  Instead of using "renderTo" you can explicitly render the grid
         * when you want using render(). This gives you the flexibility or power to control
         * the rendering process.  In addition to render() you can also use the beforerender()
         * event (see Ext.Component).
         * 3.4 Add listeners to the Grid
         */
        
grid.render('grid-example');//1st argument is the container, 2nd argument is the position within
                                    //the div (defaults to end of the container)
        
        /**
         * 3.4 Add listeners to the Grid
         */

        /**
         * Add right click event
         * rowcontextmenu fires when a row is right clicked
         */ 
        
grid.addListener('rowcontextmenu'onMessageContextMenu);

        
//callback function for the right click event 
        
function onMessageContextMenu(gridrowIndexe) {
            
e.stopEvent();
            var 
coords e.getXY();
            var 
record grid.getStore().getAt(rowIndex);//OK, we have our record, now how do we pass
                                                         //it to the referenced handler?

            
var messageContextMenu = new Ext.menu.Menu({
                
id'messageContextMenu',
                
items: [
                {
                    
text'Properties',
                    
handleronMessageContextItemClick
                    
//handler: showRecord(record)
                
},
                {
                    
text'I like Ext',
                    
checkedtrue,       // when checked has a boolean value, it is assumed to be a CheckItem
                    
checkHandleronItemCheck
                
}
                ]
            });
            
            
//predefine a menu item
            
var menuItem = new Ext.menu.Item({text'<i>New Item</i>'});

             
//shows how to add items dynamically
            
var item messageContextMenu.add(
                
'-',
                
menuItem//add item by reference
                
{    
                    
text'<u>View in new tab</u>',
                    
//handler: onMessageContextItemClick(this,['open']),
                    
handler: function(){
                        
this.viewer.openTab(this.ctxRecord);
                    },
                    
iconCls:'add'
                
},
                    {
text'<b>Print</b>'menu: new Ext.menu.Menu({// <-- submenu by nested config object
                        
items: [
                            {
text'PDF',  handler:function(){callPrintPreview("PDF");} },
                            {
text'EXCEL',handler:function(){callPrintPreview("EXCEL ");} },
                            {
text'HTML'handler:function(){callPrintPreview("HTML") ;} },
                            {
text'WORD'handler:function(){callPrintPreview("WORD") ;} }
                        ]
                    })},
                    {
text'<b>Save Preferences</b>',handler: function(){saveUserPref(Ext.encode(colModel.config));}}
            );

            
messageContextMenu.showAt([coords[0], coords[1]]);
            
e.preventDefault();//to disable the standard browser context menu
        
}


        
/**
         * Handlers for right clicks
         */ 
        
function onMessageContextItemClick(item) {
            
//Ext.MessageBox.alert('Request','You selected the {0} menu item',item.text);
            
Ext.MessageBox.alert('Request','You selected '+this.text);
        }; 
// end right click handler 

        
function onItemCheck(itemchecked){
            
Ext.example.msg('Item Check''You {1} the "{0}" menu item.'item.textchecked 'checked' 'unchecked');
        }

        function 
SaveToExcel(item) {
            
Ext.MessageBox.alert('Request','You selected '+this.text);
        }; 
        function 
callDelete(item) {
            
Ext.MessageBox.alert('Request','You selected '+this.text);
        }; 
        function 
callTrade(item) {
            
Ext.MessageBox.alert('Request','You selected '+this.text);
        }; 
        function 
callPrintPreview(item) {
            
Ext.MessageBox.alert('Request','You selected '+this.text);
        }; 


        
/**
         * Add an event to handle any updates to grid
         */ 
        
grid.addListener('afteredit'handleEdit);//give event name, handler (can use 'on' shorthand for addListener) 
        
        
        //instead of adding listeners individually could have also loaded together like so:   
        /*
        grid.addListener({  //same as saying grid.on
            'rowcontextmenu': onMessageContextMenu,
            'afteredit': handleEdit
            //note other listeners are same just without the 'on' (mousever, mouseout, click, etc.)
        });
        */


            
        /**
         * Grid rendering effects
         * if we want to render rows depending on values in row
         */ 
        
grid.getView().getRowClass = function(recordindex) {
            switch (
record.data.stars) {
                case 
'0'
                
//right now just keying off of stars = '0' to signify the row has
                //not been saved yet, might be better to key from when the 'id' is no longer zero
                //but for now I just chose the last column thinking that would be the last to get updated
                    
return "yellowrow"
                    
break
                case 
'5':
                    return 
"greenrow"
                    
break
                case 
'4':
                    return 
"pinkrow"
                    
break
                default:
                    
//something else?
            
}
        };
//end row rendering


        // This line to highlight the first row of the grid is quite finicky.  There's probably
        // a better way to do this that is more reliable.  It seems like this next line may get
        // executed before the grid is rendered and may not fire depending on the timing.
        
grid.getSelectionModel().selectFirstRow();
    
        
    }
//end function buildGrid

    
    /*--Private Area--*/
    /******************/
 
    /*****************/
    /*--Public Area--*/
    
return {//returns an object Ext.myNameSpace.module1 with the following methods:
        /*--Public Properties--*/
        // it's good practice to put the following in the public area of the module:
        //   text used by module, default dmensions, styles, customizable options, etc.
        
myPublicProperty"I'm accessible as myNameSpace.myModule.myPublicProperty.",
    
        
perPage50//page limit

        /*--Public Methods--*/
        //  Public methods can be called from outside
        //  Public methods can access Private Area
        
myPublicMethod: function(){//accessible as myNameSpace.myModule.myPublicMethod
            
var myOtherProperty this.myPublicProperty //use 'this' to refer to Public Property
            
return myPrivateVar//note reference to Private variable does NOT use 'this'
        
},
        
init : function(){ //this method is called by the last line below that looks like this:
                           //Ext.onReady(myNameSpace.myModule.init, myNameSpace.myModule, true);
                           //So once the document is fully loaded that line gets executed and we
                           //end up here.  As a result, this is a good place to put DOM dependent tasks 

            /* Put initialization code here */

            /**
             * Set up plugin for a check column
             * @param {Object} config
             */
            
Ext.grid.CheckColumn = function(config){
                
this.addEvents({
                    
clicktrue
                
});
                
Ext.grid.CheckColumn.superclass.constructor.call(this);
                
                
Ext.apply(thisconfig, {
                    
init : function(grid){
                        
this.grid grid;
                        
this.grid.on('render', function(){
                            var 
view this.grid.getView();
                            
view.mainBody.on('mousedown'this.onMouseDownthis);
                        }, 
this);
                    },
                
                    
onMouseDown : function(et){
                        if(
t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
                            
e.stopEvent();
                            var 
index this.grid.getView().findRowIndex(t);
                            var 
record this.grid.store.getAt(index);
                            
record.set(this.dataIndex, !record.data[this.dataIndex]);
                            
this.fireEvent('click'thiserecord);
                        }
                    },

                    
renderer : function(vprecord){
                        var 
checkState = (+v) ? '-on' '';//the +v type converts to a number (json returns a string which always evaluates true)
                        
p.css += ' x-grid3-check-col-td'
                      
//return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'"> </div>';
                        
return '<div class="x-grid3-check-col'checkState +' x-grid3-cc-'+this.id+'"> </div>';
                    }
                });
                
              if(!
this.id){
                  
this.id Ext.id();
              }
              
this.renderer this.renderer.createDelegate(this);
            };
            
            
Ext.extend(Ext.grid.CheckColumnExt.util.Observable);// extend Ext.util.Observable

            //done with plugin setup        
            /////////////////////////////////////////////////////////////////
    
    
             // get our Grid!
            
this.getMyGrid();// this = refers to properties and methods inside the public area
    
            // Works without this, used for state awareness...
            //Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
        
},//end of init
       
        /**
         * getMyGrid
         * Call after initialization to get our Grid
         */
        
getMyGrid: function() {  
            
Ext.QuickTips.init();// Enable Quicktips
            
setupDataSource();
            
buildGrid();
        },
        
//a method we can call from Firebug console to check what is in our Data Store
        
getDataSource: function() {  
            return 
ds;
        }
    }
    
/*--Public Area--*/
    /*****************/
}(); /* End of application. Note the parentheses () — this notation causes the anonymous
        function to execute immediately, returning the object containing myPublicProperty 
        and myPublicMethod. As soon as the anonymous function returns, that returned object
        is addressable as myNameSpace.myModule.   */


// Since the above code has already executed, we can access the init method immediately:
Ext.onReady(myNameSpace.myModule.initmyNameSpace.myModuletrue);
/* This line executes the myModule.init method after the document has been completely
   loaded. This line also sets the myModule.init method scope to myModule, which means
   you can call Public attributes (methods and properties) with a preceding 'this'.*/ 

Last edited by mjlecomte; 11-24-2007 at 01:36 AM.. Reason: various edits and updates
Reply With Quote
  #6  
Old 11-17-2007, 09:50 AM
anbutu's Avatar
anbutu anbutu is offline
Ext User
 
Join Date: Sep 2007
Posts: 7
anbutu is on a distinguished road
Send a message via MSN to anbutu
Default

great
Reply With Quote
  #7  
Old 11-17-2007, 10:17 AM
banesto banesto is offline
Ext User
 
Join Date: Nov 2007
Posts: 17
banesto is on a distinguished road
Question no response from proxy

Hi! in your comments it is said, that using HttpProxy you can see response in firebug NET view. Well your example works, but i can't seem to understand, why does my php file doesn't even appear on Net list? Any thoughts?
Reply With Quote
  #8  
Old 11-17-2007, 10:35 AM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
Default try the XHR filter

Quote:
Originally Posted by banesto View Post
Hi! in your comments it is said, that using HttpProxy you can see response in firebug NET view. Well your example works, but i can't seem to understand, why does my php file doesn't even appear on Net list? Any thoughts?
Just above where it says "NET", there is another set of buttons you can select from that essentially act as a filter (see attached firebug image). Check which one you have selected. If you just select XHR it will only show the XHR (XMLHttpRequest).

I found looking at all of the other buttons and "NET" in general interesting because it shows links in red that were invalid, so this pointed me towards other things that might be wrong (like missing images to render the css, etc.).
Attached Images
File Type: png firebug.PNG (7.4 KB, 2030 views)
Reply With Quote
  #9  
Old 11-17-2007, 01:35 PM
banesto banesto is offline
Ext User
 
Join Date: Nov 2007
Posts: 17
banesto is on a distinguished road
Default

reposted in http://extjs.com/forum/showthread.php?p=88150

Last edited by banesto; 11-17-2007 at 06:50 PM.. Reason: misuse
Reply With Quote
  #10  
Old 11-17-2007, 02:52 PM
mjlecomte mjlecomte is offline
Ext JS - Quality Assurance Team
 
Join Date: Jul 2007
Location: Florida
Posts: 10,008
mjlecomte is on a distinguished road
Default

I think you're hijacking my thread!? It's fine for you to inquire here, but you should probably just post your question in it's own thread and ask people monitoring this thread to go to your thread?

My intent for this thread was to show a working example (I should probably not have posted this in the 'help' section) and get critiques, even supporting people having questions with the files provided.

The above aside, if your html page doesn't get a response (which is I think what you're saying...that you have no response)....then the grid certainly won't display the data. You might try simplifying what you're doing. Have your php file just send back {success: true}. Then have your js display a message box in your success: block.

If I change my php to have the last (or only) line as


echo "{success: true}"
I'll get a blank grid as well. But my php file still shows up on the Console Tab and I can see the Response. Double check you have a file called "data.php" that is in the SAME directory as your js file. Also, check the CONSOLE tab, if I intentionally relocate file or rename it, the console tab still shows the request looking for that file, but it shows up in red because it can't find it (see my earlier post about this being a nice check to see your page is getting all the content you expected). [Edit:...and by the way, with the wrong filename the file shows up in red on the Console tab and not at all on the Net tab.]

Your js file is quite different from the example I have provided here. So I don't know what else you have that is different.
Reply With Quote
Reply

Thread Tools

Posting Rules

Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

All times are GMT -5. The time now is 09:37 AM.

© 2006-2009 Ext, LLC
Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.