<!-- title: PHP Grid Framework Documentation -->
<!-- subtitle: Superchange your development speed -->

<a id="top"></a>
# PHP Grid Framework Documentation

## Introduction

### Overview

![Getting Started Overview](//www.phpgrid.org/wp-content/gallery/documentation/getting-started.png)

PHP Grid Framework is a RAD tool that enables development of PHP based project far more faster.
Grid component itself contain a CRUD (create,read,update,delete) function which reduce the repeated work load.
It support connection to all major database engines including SQL Server, Oracle, IBM DB2, MySQL, Postgres and others.
It has master-detail, subgrid, data grouping, file uploading, excel mode and many other features.

## Setup

### Requirements

On server side, we need:

1) A Webserver running PHP v5.4+ (v5.4 and onwards)

2) Database server (Mysql, Sql-Server, Oracle, SQLite or any other you use)

On client side, we have tested it on famous browsers of Windows, MacOS and Linux.

### Installing Demos using Web Installer

1) Extract the downloaded product archive in web root. e.g. www/phpgrid

2) Open it in browser to run installer. e.g. http://localhost/phpgrid and following the intallation steps.

### Installing Demos Manually

1) Execute "database.sql" on a Mysql Database. It will create 'griddemo' database.

2) Place all files in a directory on the web server. e.g. ".../www/phpgrid/"

3) Rename config.sample.php to config.php, and update database config. e.g.

	define("PHPGRID_DBTYPE","mysqli");
	define("PHPGRID_DBHOST","localhost");
	define("PHPGRID_DBUSER","root");
	define("PHPGRID_DBPASS","");
	define("PHPGRID_DBNAME","griddemo");

	// It will work in normal cases, unless you change lib folder location
	define("PHPGRID_LIBPATH",dirname(__FILE__).DIRECTORY_SEPARATOR."lib".DIRECTORY_SEPARATOR);

4) Run the product demos in browser. e.g. http://localhost/phpgrid/index.php

### Integration in your Project

To integration in your app, copy 'lib' folder to your project. You need to consider 3 things.

1) Set DB config

	$db_conf = array();
	$db_conf["type"] = "mysqli";
	$db_conf["server"] = PHPGRID_DBHOST; // or you mysql ip
	$db_conf["user"] = PHPGRID_DBUSER; // username
	$db_conf["password"] = PHPGRID_DBPASS; // password
	$db_conf["database"] = PHPGRID_DBNAME; // database

	// pass connection array to jqgrid()
	$g = new jqgrid($db_conf);

2) The folder `../../lib` will be replaced by path where you place `lib` folder (if changed)

	<link rel="stylesheet" type="text/css" media="screen" href="../../lib/js/themes/start/jquery-ui.custom.css"></link>
	<link rel="stylesheet" type="text/css" media="screen" href="../../lib/js/jqgrid/css/ui.jqgrid.css"></link>
	<script src="../../lib/js/jquery.min.js" type="text/javascript"></script>
	<script src="../../lib/js/jqgrid/js/i18n/grid.locale-en.js" type="text/javascript"></script>
	<script src="../../lib/js/jqgrid/js/jquery.jqGrid.min.js" type="text/javascript"></script>
	<script src="../../lib/js/themes/jquery-ui.custom.min.js" type="text/javascript"></script>

3) Update include path where you place `lib/inc/` folder (if changed)

	include("../../lib/inc/jqgrid_dist.php");
	$g = new jqgrid($db_conf);

### Upgrading from older version

Simply override `lib/inc` & `lib/js` from latest build to the phpgrid folder in previous implementations.
You may need to clear browser cache as well to remove the effect of old JS and CSS files.
Same applies to upgrade from free to full version.

[^ Top](#top)

## Creating First Grid

Step1: Add PHP Grid configuration code

	<?php
	include_once("../../config.php");

	// include and create object
	include(PHPGRID_LIBPATH."inc/jqgrid_dist.php");

	$db_conf = array(
						"type" 		=> PHPGRID_DBTYPE,
						"server" 	=> PHPGRID_DBHOST,
						"user" 		=> PHPGRID_DBUSER,
						"password" 	=> PHPGRID_DBPASS,
						"database" 	=> PHPGRID_DBNAME
					);

	$g = new jqgrid($db_conf);

	// set few params
	$opt["caption"] = "Sample Grid";
	$g->set_options($opt);

	// set database table for CRUD operations
	$g->table = "clients";

	// render grid and get html/js output
	$out = $g->render("list1");
	?>

Step2: Include JS and CSS files in your html page

	<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
	<html>
	<head>

		<!-- these css and js files are required by php grid -->
		<link rel="stylesheet" href="../../lib/js/themes/redmond/jquery-ui.custom.css"></link>
		<link rel="stylesheet" href="../../lib/js/jqgrid/css/ui.jqgrid.css"></link>
		<script src="../../lib/js/jquery.min.js" type="text/javascript"></script>
		<script src="../../lib/js/jqgrid/js/i18n/grid.locale-en.js" type="text/javascript"></script>
		<script src="../../lib/js/jqgrid/js/jquery.jqGrid.min.js" type="text/javascript"></script>
		<script src="../../lib/js/themes/jquery-ui.custom.min.js" type="text/javascript"></script>
		<!-- these css and js files are required by php grid -->

	</head>

Step3: Print the `$out` variable where you wish to display grid.

	<body>
		<div style="margin:10px">

		<!-- display grid here -->
		<?php echo $out?>
		<!-- display grid here -->

		</div>
	</body>
	</html>

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/editing/index.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/editing/index.php)
- You can check this demo in archive `demos/editing/index.php`

#### Explanation

- The PHP Part configured the grid and rendered the output to $out variable.
- In HTML Part, we displayed the generated grid code `$out` along with few external css/js files. It's upto you to place external css and js files at appropriate locations.
- `->set_options()` function is most of the customization, we'll be covering later.
- `->table` is required, to enable automatic select,add,update,delete operations on that table. By default all columns of the table are selected on grid. We'll review how to select particular columns.
- `->render()` will generate the final output, to be displayed in view. It takes **Grid ID** as input, which should be unique on a page.

## Selecting Columns

By default, when we define the `->table` property, it displays all the columns of table. We can pick certain columns to be displayed on grid by using `->set_columns($cols)` function.

	$col = array();
	$col["title"] = "Id"; // caption of column, can use HTML tags too
	$col["name"] = "client_id"; // grid column name, same as db field or alias from sql
	$col["width"] = "20"; // width on grid
	$col["editable"] = true;
	$cols[] = $col;

	$col = array();
	$col["title"] = "Name"; // caption of column, can use HTML tags too
	$col["name"] = "name"; // grid column name, same as db field or alias from sql
	$col["width"] = "40"; // width on grid
	$col["editable"] = true;
	$cols[] = $col;

	$col = array();
	$col["title"] = "Gender"; // caption of column, can use HTML tags too
	$col["name"] = "gender"; // grid column name, same as db field or alias from sql
	$col["width"] = "60"; // width on grid
	$col["editable"] = true;
	$cols[] = $col;

	// pass the cooked columns to grid
	$g->set_columns($cols);

If you want to customize any specific column properties, and let other columns be displayed from table definition, you can pass 2nd argument of `set_columns($cols,true)` to `true`.

	$col = array();
	$col["name"] = "company";
	$col["edittype"] = "textarea";
	$cols[] = $col;

	$g->set_columns($cols,true);

Only column with name 'company' will be changed to textarea and rest table column will be displayed as they were before.

**NOTE**: The first column must have unique data (usually PK) in order to work properly. It is required to identify and perform row wise operations. You can make it hidden in grid if you wish. See `hidden` property in later section for more.

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/appearance/image.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/appearance/image.php)
- You can check this demo in archive `demos/appearance/image.php`

[^ Top](#top)

## Column Options

We can also customize each column properties. Following are the parameters, that can be passed to customize column definition on grid.

#### Caption shown on grid

	$col["title"] = "Details";

#### DB table field name or alias

	$col["name"] = "view_more";

#### DB table.field name

	// in case of field name ambiguity b/w tables
	$col["dbname"] = "c.id";

#### Width of column

	$col["width"] = "20";

	// to set exact pixel width
	$col["fixed"] = true;
	$col["width"] = "20";

#### Editable (true,false)

	$col["editable"] = false;

#### Viewable (true,false)

When the option is set to false the column does not appear in view Form

	$col["viewable"] = false;

#### Frozen (true,false)

When the option is set to true the column will be freezed while scrolling.
Column must be first column of grid OR after another freezed column.

	$col["frozen"] = true;

The following limitations tell you when frozen columns can not be set-up:

	- When TreeGrid is enabled
	- When SubGrid is enabled
	- When cellEdit is enabled
	- When inline edit is used - the frozen columns can not be editable.
	- When sortable columns are enabled - grid parameter sortable is set to true or is function
	- When scroll is set to true or 1
	- When Data grouping is enabled
	- When footer row (footerrow paremeter) is enabled

#### Allow null (true,false)

If db fields allows null and we want to save (NULL) instead of "". Defaults to false

	$col["isnull"] = true;

#### Auto-increment ID (true,false)

First field in column definition array is by-default skipped from INSERT query (assuming to be primary key and auto increment).
If you wish to include it in INSERT sql (non auto increment) you can set:

	$col["autoid"] = false;

#### Resizable (true,false)

	$col["resizable"] = true;

#### Edit Type & Options

This option let us select the control we want to render when editing this field. All possible options are in following snippet. Defaults to `text`. In `editoptions` we can set all the possible attributes for this field's control.

Render as textarea on edit

	$col["edittype"] = "textarea";
	$col["editoptions"] = array("rows"=>2, "cols"=>20);

Render as checkbox, with these values "checked_value:unchecked_value"

	$col["edittype"] = "checkbox";
	$col["editoptions"] = array("value"=>"Yes:No");

To make checkbox already in checked state while adding record
	$col["editoptions"] = array("value"=>"Yes:No", defaultValue=> 'Yes');

Render as textbox with size 20, and initial value in textbox to 10

	$col["editoptions"] = array("size"=>20, "defaultValue"=>'10');

Render as password textbox, it should be used with `$col["formatter"] = "password";` to hide password in listing

	$col["edittype"] = "password";

Render as select (dropdown), with these values "key:value;key:value;key:value"

	$col["edittype"] = "select";
	$col["editoptions"] = array("value"=>'10:$10;20:$20;30:$30;40:$40;50:$50');

	// For multiselect, you probably need to write custom on_update handler
	$col["editoptions"] = array("value"=>'10:$10;20:$20;30:$30;40:$40;50:$50', "multiple" => true);

	// In case you want to use different delimiter (:) and separator (;), you can override
	$col["editoptions"]["delimiter"] = ":";
	$col["editoptions"]["separator"] = ";";

Render as button

	$col["edittype"] = "button";
	$col["editoptions"] = array("value"=>'Click Me');

Render Radio buttons as edittype

Radio buttons can be shown by custom method.

	$col = array();
	$col["title"] = "Closing Rate";
	$col["name"] = "closed";
	$col["width"] = "30";
	$col["editable"] = true;
	$col["align"] = "center";
	$col["editoptions"]["dataInit"] = "function(o){edit_as_radio(o);}";
	$cols[] = $col;

... and in html section, we can define custom edit-type display

	<script>
    function edit_as_radio(o)
    {
		setTimeout(function(){
			jQuery(o).hide();
			jQuery(o).parent().append('<input title="0" type="radio" name="rd_closed" value="0" onclick="jQuery(\'#total\').val(0);"/> 0 <input title="5" type="radio" name="rd_closed" value="5" onclick="jQuery(\'#total\').val(5);"/> 5 <input title="10" type="radio" name="rd_closed" value="10" onclick="jQuery(\'#total\').val(10);"/> 10');
		},100);
    }
    </script>

Multiple checkboxes as edittype

	$col = array();
	$col["title"] = "Closed";
	$col["name"] = "closed";
	$col["width"] = "50";
	$col["editable"] = true;
	$col["editoptions"]["dataInit"] = "function(o){edit_as_custom(o);}";
	$cols[] = $col;

and in html, add display function that will update the selection in main field (hidden)

	<script>
		function edit_as_custom(o)
		{
			setTimeout(function(){
				jQuery(o).parent().append('<input type="checkbox" name="rd_closed" value="1" onclick="set_checkbox_value();"/> Option 1 <input type="checkbox" name="rd_closed" value="2" onclick="set_checkbox_value();"/> Option 2 <input type="checkbox" name="rd_closed" value="3" onclick="set_checkbox_value();"/> Option 3');
				jQuery(o).css('display','none');

				// here you can also read #closed value (if set) and set in checkboxes using jquery for edit mode

			},100);
		}

		function set_checkbox_value()
		{
			jQuery('#closed').val( jQuery('input[name=rd_closed]:checked').map(function(){return this.value;}).get() );
		}
	</script>

#### Readonly Column

You can also set certain column as readonly on edit dialog, and editable on add dialog.

	$col["editrules"]["readonly"] = true;

To make column readonly in both add and edit dialog, use following:

	// shows defaultValue only on add dialog and readonly
	$col["editoptions"] = array("defaultValue"=>"Test Value","readonly"=>"readonly", "style"=>"border:0");

If you need to make a column non-editable when it contain some specific data, you can also put that condition using `readonly-when`. Refer column-access.php.

	$col = array();
	$col["title"] = "Gender";
	$col["name"] = "gender";
	$col["editable"] = true;
	$col["editrules"] = array("required"=>true, "readonly"=>true, "readonly-when"=>array("==","male"));
	$cols[] = $col;

For advance readonly logic, use callback function

	$col["editrules"] = array("required"=>true, "readonly"=>true, "readonly-when"=>"check_client");

	// html side .. JS callback function

	<script>
	// readonly gender conditional function - when return true, field will be readonly
	function check_client(formid)
	{
		client_id = jQuery("input[name=client_id]:last, select[name=client_id]:last",formid).val();
		client_id = parseInt(client_id);

		if (jQuery.inArray(client_id,[3,6,7,8,9]) != -1)
			return true;
	}
	</script>

#### Column Form Option

This option is valid only in form editing. The purpose of these options is to reorder the elements in the form and to add some information before and after the editing element.

`elmprefix` if set, a text or html content appears before the input element
`elmsuffix`	string	if set, a text or html content appears after the input element
`label`	string	if set, this replace the name from colNames array that appears as label in the form.
`rowpos` determines the row position of the element (again with the text-label) in the form; the count begins from 1
`colpos` determines the column position of the element (again with thelabel) in the form beginning from 1

If you plan to use this object in collModel with rowpos and colpos properties it is recommended that all editing fields use these properties.

	$col["formoptions"] = array("elmprefix"=>'(*)', "rowpos"=>"1", "colpos"=>"2");

To mark a field as required, you can use

	$col["formoptions"] = array("elmsuffix"=>'<font color=red> *</font>');

#### Column Formatter

This will format this column as date (and will show date picker control) on add or edit operations.

	$col["formatter"] = "date";
	$col["formatoptions"] = array("srcformat"=>'Y-m-d',"newformat"=>'d/m/Y');

This will format this column as date time (and will show date time picker control) on add or edit operations.

	$col["formatter"] = "datetime";
	$col["formatoptions"] = array("srcformat"=>'Y-m-d',"newformat"=>'d/m/Y');

Complete date formatting shortcode can be found on this link: http://www.php.net/manual/en/function.date.php

By default, datepicker does not perform 'contains' search. If you wish to enable, you need to set following with date column.
This will disable datepicker.

	// contains search
	$col["searchoptions"]["sopt"] = array("cn");

Format of contains search is yyyy-mm-dd, which can be changed using 'dbname' property and mysql format_date function.

	// search date in format Jan 23, 2008
	$col["dbname"] = "date_format(invdate,'%b %d, %Y')";

To show column as checkbox,

	$col["formatter"] = "checkbox";

To display select box (dropdown) label instead of value,

	$col["formatter"] = "select";

For password fields,

	$col["formatter"] = "password";

You can also set format options for numeric and currency data.

	$col["formatter"] = "number";
	$col["formatoptions"] = array("thousandsSeparator" => ",",
		                            "decimalSeparator" => ".",
		                            "decimalPlaces" => 2);

	$col["formatter"] = "currency";
	$col["formatoptions"] = array("prefix" => "$",
		                            "suffix" => '',
		                            "thousandsSeparator" => ",",
		                            "decimalSeparator" => ".",
		                            "decimalPlaces" => 2);

Render as image,

	$col["formatter"] = "image";
	$col["formatoptions"] = array("src"=>'http://test.com/image.jpg');

For custom formatter, e.g. image display

	$col["formatter"] = "function(cellval,options,rowdata){ return '<img src=\"'+cellval+'\" />'; }";
	$col["unformat"] = "function(cellval,options,cell){ return $('img', cell).attr('src'); }";

For custom formatter of percentage display

	$col["formatter"] = "function(cellval,options,rowdata){ return cellval*100+'%'; }";
	$col["unformat"] = "function(cellval,options,cell){ return cellval.replace('%','')/100; }";

For custom formatter of fix height row (having html <br> content)

	$col["formatter"] = "function(cellval,options,rowdata){ return '<div style=\"height:25px; overflow:hidden;\">'+cellval+'</div>'; }";
	$col["unformat"] = "function(cellval,options,cell){ return jQuery(cell).children('div').html(); }";

For raw link formatter

	$col["formatter"] = "function(cellval,options,rowdata){ return '<a target=\"_blank\" href=\"http://'+cellval+'\">'+cellval+'</a>'; }";
	$col["unformat"] = "function(cellval,options,cell){ return $('a', cell).attr('href').replace('http://',''); }";

In unformatter, if you want to use row data you can use getRowData, e.g:

	// here list1 is your grid id & total_weight is row column to use
	$col["unformat"] = "function(cellval, options, cell) {
							var rowdata = $('#list1').getRowData(options.rowId);
							return cellval.replace('%','')*rowdata['total_weight']/100;
						}";

#### Date Format

Governs format of editrules {date:true} fields. Determines the expected date format for that column. Uses a PHP-like date formatting. Currently "/", "-", and "." are supported as date separators. Valid formats are:
y,Y,yyyy for four digits year
YY, yy for two digits year
m,mm for months
d,dd for days

	$col["datefmt"] = "Y-m-d";

#### Text alignment	(left,right,center)

	$col["align"] = "center";

#### Is searching allowed on this field (true,false)

	$col["search"] = false;

#### Dropdown in auto filter search

We need to set `stype` and `searchoptions` to enable dropdown search in autofilter.

	// Fetch data from database, with alias k for key, v for value
	$str = $g->get_dropdown_values("select distinct client_id as k, name as v from clients");

	$col["stype"] = "select";
	$col["searchoptions"] = array("value" => $str, "separator" => ":", "delimiter" => ";");

#### Limit column search operators

Optionally set limited search operators (e.g. bw = begins with, 'eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc')

This will limit search operators for this columns to begins-with, equal, cotains

	$col["searchoptions"]["sopt"] = array("bw","eq","cn");

If you pass single operator, only that will be used in autofilter and override default contains search

	$col["searchoptions"]["sopt"] = array("eq");

#### Is sorting allowed on this field (true,false)

	$col["sortable"] = false;

#### Sort type (only work with load with array)

Defines the type of sort for column.

	/*
	Possible values:
	int/integer - for sorting integer
	float/number/currency - for sorting decimal numbers
	date - for sorting date
	text - for text sorting
	*/

	$col["sorttype"] = int;

#### Make the data in column as hyperlink
We can use exiting db-field value of that row in URL pattern. For e.g. if we have a grid column named 'id', we can insert it's value in URL using {id}. Here we set, http://domain.com?id={id} given that, there is a column with $col["name"] = "id" exist.

	$col["link"] = "http://localhost/?id={id}";

`linkoptions` option is used with `link` parameter to provide additional attributes.

	$col["linkoptions"] = "target='_blank'"; // extra params with <a> tag

There is a limitation thatyou cannot make first column as hyperlink, as it is usually PK and used in INSERT/UPDATE.
Alternate solution could be to select same field 2 times in SQL, and make first as hidden and second as hyperlink.

#### Static Content
If the column is static data (non database driven), we can set it with default param. We can set custom HTML too, for e.g. `<img>` or `<div>` etc.

	$col["default"] = "View More"; // default link text

#### Dynamic Content
We can also use `{field}` replacement in `default` parameter. Here is an example for custom column to show bar graph. Where `bar` is a column alias from SQL statement.

	$col = array();
	$col["title"] = "Performance";
	$col["name"] = "bar";
	$col["width"] = "40";
	$col["align"] = "left";
	$col["search"] = false;
	$col["sortable"] = false;
	$col["default"] = "<div style='width:{bar}px; background-color:navy; height:14px'></div>";
	$cols[] = $col;

In same way, we can embed dynamic images and other media (flv or swf) in grid.

#### Conditional Content
We can also provide certain condition, based on which either row data will be displayed.
NOTE: Use single quote for condition, and $row will have all columns data, to use in condition.

	$col["condition"] = array('$row["total"] < 100', $data1, $data2);

Now if the condition is met, `$data1` will be displayed otherwise `$data2`. You can also `{field}` replacement in `$data1` & `$data2`. Refer example below.

	# no new line in this html, only space. otherwise it may break ui of grid
	$buttons_buy = "<a target='_blank' href='http://www.amazon.com?id={id}'>Buy</a>";
	$buttons_try = "<a target='_blank' href='http://www.google.com?id={id}'>Try</a>";
	$col["condition"] = array('$row["total"] > 10', $buttons_buy, $buttons_try);

For extended conditional data, you can also have callback function, that will allow you to display based on row data. For e.g.

	$col["on_data_display"] = array("display_keyword","");

	function display_keyword($data)
	{
		$kw = $data["keyword_name"];
		$numKeywords = count(explode("\n",$pass));
		if ($numKeywords > 3)
			   return $numKeywords." Keywords";
		else
		{
			   $pass = str_replace("+"," ",$pass);
			   return $pass;
		}
	}

#### Hiding Column

At instance, we don't want to show column in grid (like primary key), and it is equally needed for background operations like update or delete. `hidden` property can work here.

	// don't show this column in list, but in edit/add mode
	$col["hidden"] = true;

If `hidedlg` set to true this column will not appear in the modal dialog (colchooser / showhidecolumn) where users can choose which columns to show or hide.

	$col["hidedlg"] = true;

Another scenario is we want to hide it on grid list, and display it on Add or Edit forms.

	$col["editrules"] = array("edithidden"=>true);

If you want to enable searching on this hidden column, set

	$col["searchoptions"] = array("searchhidden" => true);

You can also customize in one line, on which dialog/section this column will be displayed. Possible options are true or false. This may override the hidden and edithidden settings. See column-access.php

	$col["show"] = array("list"=>true, "add"=>true, "edit"=>true, "view"=>true, "bulkedit"=>true);

#### Row-wise Action Column

When we enable inline edit/delete option, An additional column `Action` is appended as last column of grid.
We can also specify, by defining a column with name `$col["name"] = "act";`. After that all changes will be applied on that column.

	# Customization of Action column width and other properties
	$col = array();
	$col["title"] = "Action";
	$col["name"] = "act";
	$col["width"] = "50";
	$cols[] = $col;

[^ Top](#top)

## Grid Options

### Custom SQL Query

By default, when we define the `->table` property, it fetches all the possible columns of table.
We can provide custom SQL query in `->select_command` property to pick columns available for grid.
We can use complex multi-join sub-queries in it.

	$g->select_command = "SELECT i.id, invdate , c.name,
							i.note, i.total, i.closed FROM invheader i
							INNER JOIN clients c ON c.client_id = i.client_id";

### Grid Settings

You can use following options for `->set_options($opt)` function.

#### Records per Page

Number of records to show on page

	$opt["rowNum"] = 10;

#### Options to show in paging records

	$opt["rowList"] = array(10,20,30);

	// you can also set 'All' for all records
	$opt["rowList"] = array(10,20,30,'All');

	// empty array will hide dropdown
	$opt["rowList"] = array();

#### Show Row numbers

To show row numbers before each records, and set that column's width

	$opt["rownumbers"] = true;
	$opt["rownumWidth"] = 30

#### Show Paging Buttons

To show/remove Paging navigation buttons

	$opt["pgbuttons"] = false;

#### Set Initial Page

To set initial page (e.g. as page 2) of grid

	$opt["page"] = 2;

	// to set last page, set some big number
	$opt["page"] = 9999;

#### Show Paging text

To show/remove Paging text e.g. Page 1 of 10

	$opt["pgtext"] = null;

Enable or Disable total records text on grid

	$opt["viewrecords"] = true;

#### Fit Columns

If set to true, and resizing the width of a column, the adjacent column (to the right) will resize so that the overall grid width is maintained (e.g., reducing the width of column 2 by 30px will increase the size of column 3 by 30px). In this case there is no horizontal scrolbar. Note: this option is not compatible with shrinkToFit option - i.e if shrinkToFit is set to false, forceFit is ignored.

	$opt["forceFit"] = true;

#### Extend Columns to Grid Width

This option describes the type of calculation of the initial width of each column against with the width of the grid. If the value is true and the value in width option is set then: Every column width is scaled according to the defined option width.

	$opt["shrinkToFit"] = true;

#### Autowidth

Expand grid to screen width

	$opt["autowidth"] = true;

#### Resizable Grid

Show corner (lower-right) resizable option on grid

	$opt["resizable"] = true; // defaults to false

#### Responsive Switch

Auto resize grid with browser resize

	$opt["autoresize"] = true; // defaults to false

#### Initially Hidden Grid

If set to true the grid initially is hidden. The data is not loaded (no request is sent) and only the caption layer is shown. When the show/hide button is clicked the first time to show grid, the request is sent to the server, the data is loaded, and grid is shown. From this point we have a regular grid. This option has effect only if the caption property is not empty and the hidegrid property (see below) is set to true.

	$opt["hiddengrid"] = true;

#### Show Hide Grid button

Enables or disables the show/hide grid button, which appears on the right side of the Caption layer. Takes effect only if the caption property is not an empty string.

	$opt["hidegrid"] = true;

#### Grid Height

The height of the grid. Can be set as percentage or any valid measured value

	// set in pixels
	$opt["height"] = "400";

	// to remove vertical scroll bar
	$opt["height"] = "100%";

#### Grid Width

If this option is not set, the width of the grid is a sum of the widths of the columns defined

	$opt["width"] = "600";

#### Loading Text

The text which appear when requesting and sorting data. Defaults to `Loading...`

	$opt["loadtext"] = "Loading...";

#### Toolbar Position

This option defines the toolbar of the grid. This is array with two values in which the first value enables the toolbar and the second defines the position relative to body Layer. Possible values "top" or "bottom" or "both"

	$opt["toolbar"] = "top";

#### Multiselect Records

Allow you to multi-select through checkboxes

	$opt["multiselect"] = true;

Allow you to multi-select through checkboxes and not whole row

	$opt["multiboxonly"] = true;

This parameter have sense only multiselect option is set to true. The possible values are: shiftKey, altKey, ctrlKey

	$opt["multikey"] = true;

#### Alternate Row Color

Set a zebra-striped grid, boolean

	$opt["altRows"] = true;

#### Initial Grid Sorting

Default sort grid by this field, Sort ASC or DESC

	$opt["sortname"] = 'id';
	$opt["sortorder"] = "desc";

To sort on multiple fields (at time of loading)

	// Date will be sorted desc, and ID asc.
	$opt["sortname"] = "date DESC,id";
	$opt["sortorder"] = "ASC";

To sort first click in DESC sequence, set:

	$opt["firstsortorder"] = "desc";

This will make SQL: ORDER BY date DESC,id ASC

#### Grid Multi-Column Sorting

In case of multi sort when first time clicked the sort is asc (or descending) the next click sort to
opposite direction the third click of the column remove the sorting from that column. Your first column must have
similar records to see the change of second level sorting and onwards.

	$opt["multiSort"] = true;

#### Grid Caption

This will set grid caption.

	$opt["caption"] = "Invoice Data";

In order to remove caption bar, set it to blank.

	$opt["caption"] = "";

#### Lazy Loading of Pages

Creates dynamic scrolling grids. When enabled, the pager elements are disabled and we can use the vertical scrollbar to load data. useful for big datasets

	$opt["scroll"] = true;

#### RTL or LTR

Makes grid right to left, for rtl languages e.g. arabic. Default is ltr

	$opt["direction"] = "rtl";

#### Tooltips

Enable tooltips for icons and long text: true/false

	$opt["tooltip"] = true;

#### Hotkeys

Enable or disable hotkeys for add, edit or delete operations: true/false
It only work for first grid on page.

	$opt["hotkeys"] = true;

#### Excel Mode Switch

Inline cell editing, like spreadsheet

	$opt["cellEdit"] = true;

#### Reload after Edit

To reload whole grid after editing

	$opt["reloadedit"] = true;

#### Display Pager on Top

Display Top Pager bar

	$opt["toppager"] = true;

#### URL for Ajax calls

URL for grid page (for ajax calls), defaults to REQUEST_URI. It works with http & https. Used when passing extra querystring data, e.g.

	$opt["url"] = "http://domain/page.php?test=1";

#### Grid Dialog Customizations

Set Add and Edit form & View dialog width. This can be used with combination of css customization of dialog forms.

	$opt["add_options"] = array('width'=>'420');
	$opt["edit_options"] = array('width'=>'420');
	$opt["view_options"] = array('width'=>'420');

Just like width in dialog options, you can also set other for e.g.

	$opt["add_options"] = array('width'=>'420',
								"closeAfterAdd"=>true, // close dialog after add/edit
								"clearAfterAdd"=>true, // clear fields after add/edit - default true
								"top"=>"200", // absolute top position of dialog
								"left"=>"200" // absolute left position of dialog
								);

	$opt["edit_options"] = array('width'=>'420',
								"closeAfterEdit"=>true, // close dialog after add/edit
								"top"=>"200", // absolute top position of dialog
								"left"=>"200" // absolute left position of dialog
								);

To specify exact top/left position (as above), you need to set:

	$opt["form"]["position"] = "";
	$opt["add_options"]["jqModal"] = true;

#### Dialog Success Message

You can also customize the success messages that appear after add/edit/del operations.

	$opt["add_options"]["success_msg"] = "Post added";
	$opt["edit_options"]["success_msg"] = "Post updated";
	$opt["delete_options"]["success_msg"] = "Post deleted";

	// for bulk editing
	$opt["edit_options"]["success_msg_bulk"] = "Post(s) updated";
	...
	$g->set_options($opt);

To remove these success messages, you can set:

	$opt["add_options"]["afterSubmit"] = 'function(response) { return [true,""]; }';
	$opt["edit_options"]["afterSubmit"] = 'function(response) { return [true,""]; }';
	$opt["delete_options"]["afterSubmit"] = 'function(response) { return [true,""]; }';

#### Dialog Submit Confirmation

This option work only in editing mode. If Set to true this option will work only when a submit button is clicked and
if any data is changed in the form. If the data is changed a dilog message appear where the user is asked
to confirm the changes or cancel it.

	$opt["edit_options"]["checkOnSubmit"] = true;

#### Dialog Display Position

To Set Form to position on center of screen

	$opt["form"]["position"] = "center";

#### Show Dialog Navigation buttons

Enable form Prev | Next record navigation

	$opt["form"]["nav"] = true;

Refer demos/appearance/dialog-layout.php for demo.

#### Row Action Icons or Text

You can enable / disable the row action icons, by setting it true or false. It is enabled by default in latest version.

	$opt["actionicon"] = false;
	...
	$g->set_options($opt);

#### Global Column Setting

If we want to set some column property across all columns of grid, without individually setting them with column definition,
We can use `cmTemplate` property.

	$opt["shrinkToFit"] = false;
	$opt["autowidth"] = true;
	$opt["cmTemplate"] = array("width"=>"400");
	...
	$g->set_options($opt);

Above will set each column width to 400.

### Grid Actions

We can also switch actions to enable or disable them on grid. It is controlled by `->set_actions()` function.

Possible values are `true` or `false`.

|Operations			|Description																			|
|-------------------|---------------------------------------------------------------------------------------|
|`add` 				|Enable / Disable add operation on grid. Defaults to `true`. 							|
|`edit` 			|Enable / Disable edit operation on grid. Defaults to `true`.							|
|`bulkedit` 		|Enable / Disable bulk edit operation on grid. Defaults to `false`.						|
|`delete` 			|Enable / Disable delete operation on grid. Defaults to `true`.  						|
|`view` 			|Enable / Disable view operation on grid. Defaults to `true`.  							|
|`clone` 			|Enable / Disable clone operation on grid. Defaults to `false`.  						|
|`rowactions` 		|Enable / Disable inline edit/del/save option. Defaults to `true`.  					|
|`export` 			|Enable / Disable export to excel option. Defaults to `false`.  						|
|`import` 			|Enable / Disable import data option. Defaults to `false`.  						|
|`autofilter` 		|Enable / Disable autofilter toolbar for search on top. Defaults to `true`.  			|
|`showhidecolumns` 	|Enable / Disable button to hide certain columns from client side. Defaults to `true`.	|
|`inlineadd` 		|Enable / Disable button to perform insertion inline. Defaults to `false`.				|
|`search` 			|Search property can have 3 values, `simple`, `advance` or `false` to hide.				|

Code:

	$g->set_actions(array(
							"add"=>true,
							"edit"=>true,
							"clone"=>true,
							"bulkedit"=>true,
							"delete"=>true,
							"view"=>true,
							"rowactions"=>true,
							"export"=>true,
							"import"=>true,
							"autofilter" => true,
							"search" => "simple",
							"inlineadd" => true,
							"showhidecolumns" => true
						)
					);

## Master Detail Grid

![Master Detail Grid](//www.phpgrid.org/wp-content/gallery/documentation/masterdetail.png)

Following params will enable detail grid, and by default 'id' (PK) of parent is passed to detail grid. (see master-detail.php)

	$opt["detail_grid_id"] = "list2";

In order to invoke multiple detail grid, you can pass grid identifier in this way.

	$opt["detail_grid_id"] = "list2,list3,list4";

To extra params passed to detail grid, column name comma separated

	$opt["subgridparams"] = "gender,company";
	$g->set_options($opt);

	...
	...

	# To read passed params in detail grid code
	$company = $_GET["company"];

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/master-detail/master-detail.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/master-detail/master-detail.php)
- You can check this demo in archive `demos/master-detail/master-detail.php`

[^ Top](#top)

## Subgrid

#### Single Subgrid

![Using Subgrid](//www.phpgrid.org/wp-content/gallery/documentation/subgrid.png)

Setting `subGrid` to `true` will enable subgrid. When clicking `+` icon on parent grid, it will try to load url defined in `subgridurl`. By default 'rowid' (PK) of parent is passed. `subgridparams` holds comma sep. fields that will be POSTed from parent grid to subgrid. They can be read using $_POST in subgrid.

	$opt["subGrid"] = true;
	$opt["subgridurl"] = "subgrid_detail.php";
	$opt["subgridparams"] = "name,gender,company"; // no spaces b/w column names

On subgrid, data can be fetched and passed in SQL

	$c_id = $_REQUEST["rowid"];
	$g->select_command = "SELECT concat(id,'-',num) as `key`, i.*
							FROM invlines i WHERE id = $c_id";

For extra params passed from parent other than rowid (e.g. company), we need some persistent storage in session for ajax calls

	if (!empty($_POST["company"]))
	 	$_SESSION["company"] = $_POST['company'];
	$company = $_SESSION['company'];

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/master-detail/subgrid.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/master-detail/subgrid.php)
- You can check this demo in archive `demos/master-detail/subgrid.php`

#### Multiple Subgrid at same level

![Using Subgrid](//www.phpgrid.org/wp-content/gallery/documentation/multi-subgrid.png)

To define multiple subgrid at same level, just render 2 grids in detail grid page. Rest process will be same as above subgrid.

	$g = new jqgrid();
	// ...
	$out1 = $g->render('list1');

	$g = new jqgrid();
	// ...
	$out2 = $g->render('list2');

	echo "<fieldset><legend>First Grid</legend>$out</fieldset>";
	echo "<fieldset><legend>Second Grid</legend>$out2</fieldset>";

#### Resources

- [Parent Grid Code](//www.phpgrid.org/demo/demos/master-detail/multi-subgrid.phps)
- [Detail Grid Code](//www.phpgrid.org/demo/demos/master-detail/multi-subgrid-detail.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/master-detail/multi-subgrid.php)
- You can check this demo in archive `demos/master-detail/multi-subgrid.php`

[^ Top](#top)

## Exporting Data

![Exporting Data](//www.phpgrid.org/wp-content/gallery/documentation/export.png)

`format` could be
	- `pdf`
	- `excel`
	- `csv`
	- `html`
`heading` is used as Heading of pdf file.
`orientation` is page orientation. Could be `landscape` or `portrait`.
`paper` values could be 4a0,2a0,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,b0,b1,
						b2,b3,b4,b5,b6,b7,b8,b9,b10,c0,c1,c2,c3,c4,c5,
						c6,c7,c8,c9,c10,ra0,ra1,ra2,ra3,ra4,sra0,sra1,
						sra2,sra3,sra4,letter,legal,ledger,tabloid,executive,
						folio,commercial #10 envelope,catalog #10 1/2 envelope,
						8.5x11,8.5x14,11x17

	$opt["export"] = array("format"=>"pdf", "filename"=>"my-file", "sheetname"=>"test");
	$opt["export"] = array("filename"=>"my-file", "heading"=>"Invoice Details", "orientation"=>"landscape", "paper"=>"a4");

Setting `paged` to `1` will only export current page.

	$opt["export"]["paged"] = "1";

Export all data which is fetched by SQL, or export after applying search filters (if any)
Possible values are `filtered` or `all`.

	$opt["export"]["range"] = "filtered";

When exporting PDF, if you define column width, you need to set width of all columns. Setting width for few and leaving few
will make export column width distorted. In order to make it independent of $col["width"] and adjust equally in pdf, you can set:

	$grid["export"]["colwidth"] = "equal";

You can also set certain column not to export by setting export option to false. e.g.

	$col["export"] = false;

You can also add export buttons on toolbar by:

	$g = new jqgrid($conf);
	// ...
	$g->set_actions(array(
							"add"=>true,
							"edit"=>true,
							// ...
							"export_pdf"=>true,
							"export_excel"=>true,
							"export_csv"=>true,
							"export_html"=>true
						)
					);

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/export/export-all.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/export/export-all.php)
- You can check this demo in archive `demos/export/export-all.php`

[^ Top](#top)

## Importing Data

Import data option can be enabled by setting `import` to `true` in set_actions, as mentioned below:

	$g->set_actions(array(
							"add"=>true,
							"edit"=>true,
							"delete"=>true,
							"import"=>true,
							"search" => "advance"
						)
					);

Step1: Select File / Copy-Paste data from Excel

![Select File](//www.phpgrid.org/wp-content/gallery/documentation/import-1.png)

Step2: Map imported data on Database fields

![Map fields](//www.phpgrid.org/wp-content/gallery/documentation/import-2.png)

Step3: Finished

![Import finished](//www.phpgrid.org/wp-content/gallery/documentation/import-3.png)

By default new rows are appended. If you want to show append or replace option on Step2, you can set:

	$opt["import"]["allowreplace"] = true;
	$g->set_options($opt);

If you wish to remove certain database fields in import mapping, e.g.

	$opt["import"]["hidefields"] = array("client_id");
	$g->set_options($opt);

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/export/import.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/export/import.php)
- You can check this demo in archive `demos/export/import.php`

[^ Top](#top)

## Conditional Formatting

![Conditional Formatting](//www.phpgrid.org/wp-content/gallery/documentation/conditional.png)

With conditional formatting, you can specify the CSS of rows or columns based on data in it. When specifying class name you must declare the css class in your document before usage. (refer example: conditional-format.php)

	// conditional css formatting of rows

	$f = array();
	$f["column"] = "name"; // exact column name, as defined above in set_columns or sql field name
	$f["op"] = "cn"; // cn - contains, eq - equals
	$f["value"] = "Ana";
	$f["class"] = "focus-row"; // css class name
	$f_conditions[] = $f;

	$f = array();
	$f["column"] = "invdate";
	$f["op"] = "eq";
	$f["value"] = "2007-10-04";
	$f["class"] = "focus-row-red";
	$f_conditions[] = $f;

	// apply style on target column, if defined cellclass OR cellcss
	$f = array();
	$f["column"] = "id";
	$f["op"] = "=";
	$f["value"] = "7";
	$f["cellclass"] = "focus-cell";
	$f["target"] = "name";
	$f_conditions[] = $f;

If nothing set in 'op' and 'value', it will set column formatting for all cell

	$f = array();
	$f["column"] = "invdate";
	$f["css"] = "'background-color':'#FBEC88', 'color':'black'";
	$f_conditions[] = $f;

Finally, you need to call `set_conditional_css` of grid object to enable formatting.

	$g->set_conditional_css($f_conditions);

Refer demos/appearance/conditional-format.php for reference.

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/appearance/conditional-format.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/appearance/conditional-format.php)
- You can check this demo in archive `demos/appearance/conditional-format.php`

[^ Top](#top)


## Grouping

![Grouping](//www.phpgrid.org/wp-content/gallery/documentation/grouping.png)

Following setting will enable grouping footer in grid. (see grouping.php)

	$opt["grouping"] = true;
	$opt["groupingView"] = array();

	// specify column name to group listing
	$opt["groupingView"]["groupField"] = array("gender");

	// either show grouped column in list or not (default: true)
	$opt["groupingView"]["groupColumnShow"] = array(false);

	// {0} is grouped value, {1} is count in group
	$opt["groupingView"]["groupText"] = array("<b>{0} - {1} Item(s)</b>");

	// show group in asc or desc order
	$opt["groupingView"]["groupOrder"] = array("asc");

	// show sorted data within group
	$opt["groupingView"]["groupDataSorted"] = array(true);

	// work with summaryType, summaryTpl, see column: $col["name"] = "total";
	$opt["groupingView"]["groupSummary"] = array(true);

	// Turn true to show group collapse (default: false)
	$opt["groupingView"]["groupCollapse"] = false;

	// show summary row even if group collapsed (hide)
	$opt["groupingView"]["showSummaryOnHide"] = true;

	// by default grouping titles are case sensitive. To combine multiple records in same group, set:
	$opt["groupingView"]["isInTheSameGroup"] = array(
			"function (x, y) { return String(x).toLowerCase() === String(y).toLowerCase(); }"
		);
	$opt["groupingView"]["formatDisplayField"] = array(
			"function (displayValue, cm, index, grp) { return displayValue[0].toUpperCase() + displayValue.substring(1).toLowerCase(); }"
		);

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/appearance/grouping.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/appearance/grouping.php)
- You can check this demo in archive `demos/appearance/grouping.php`

[^ Top](#top)

## Grouping Headers

![Grouping Headers](//www.phpgrid.org/wp-content/gallery/documentation/grouping.png)

Now you can have a grouped headers in phpgrid control.
It would help in categorizing your related columns. (demos/appearance/group-header.php)

	// group columns header
	$g->set_group_header( array(
							    "useColSpanStyle"=>true,
							    "groupHeaders"=>array(
							        array(
							            "startColumnName"=>'name', // group starts from this column
							            "numberOfColumns"=>2, // group span to next 2 columns
							            "titleText"=>'Personal Information' // caption of group header
							        ),
							        array(
							            "startColumnName"=>'company', // group starts from this column
							            "numberOfColumns"=>2, // group span to next 2 columns
							            "titleText"=>'Company Details' // caption of group header
							        )
							    )
							)
						);

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/appearance/group-headers.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/appearance/group-headers.php)
- You can check this demo in archive `demos/appearance/group-headers.php`

[^ Top](#top)

## Search

Grid allows variety of different options to make search feature more usable.

### Autofilter toolbar

You can enable it by setting:

	$g->set_actions(array(
							// ...
							"autofilter" => true
							// ...
						)
					);

By default it will be hidden and once you set `xs+`` autofilter will come back on extra small and onwards.

	$grid["search_options"]["autofilter"] = "xs+"; // xs+, sm+, md+
	$g->set_options($grid);

![Autofilter toolbar search](//www.phpgrid.org/wp-content/gallery/images-v2/autofilter-plus.png)

[^ Top](#top)

### Search Dialog

Basic search dialog can be enabled by `search` key in set_actions function.
Possible values are `simple`, `advance`

|Values			|Description										|
|---------------|---------------------------------------------------|
|`simple` 		|Single column search dialog 						|
|`advance`		|Multi column search with AND / OR option			|
|`group` 		|Multi column search with multiple AND / OR groups	|

	$g->set_actions(array(
							// ...
							"search" => "advance"
							// ...
						)
					);

![Group Search Dialog](//www.phpgrid.org/wp-content/gallery/images-v2/search-group.png)

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/search/search-group.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/search/search-group.php)
- You can check this demo in archive `demos/search/search-group.php`

[^ Top](#top)

### Search Templates

You can also set predefined search templates using grid options.

	// Define predefined search templates
	$opt["search_options"]["tmplNames"] = array("Template1", "Template2");
	$opt["search_options"]["tmplFilters"] = array(
		array(
			"groupOp" => "AND",
			"rules" => array (
							array("field"=>"name", "op"=>"cn", "data"=>"Maria"),
							array("field"=>"closed", "op"=>"cn", "data"=>"No"),
							)
		),
		array(
			"groupOp" => "AND",
			"rules" => array (
							array("field"=>"total", "op"=>"gt", "data"=>"50")
							)
		)
	);

	$g->set_options($opt);

![Search Templates](//www.phpgrid.org/wp-content/gallery/images-v2/search-template.png)

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/search/search-template.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/search/search-template.php)
- You can check this demo in archive `demos/search/search-template.php`

[^ Top](#top)

### Search External Form

For further customizations, you can create an custom HTML form and
connect it to datagrid search javascript api.

![External Search Form](//www.phpgrid.org/wp-content/gallery/images-v2/search-custom.png)

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/search/search-form.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/search/search-form.php)
- You can check this demo in archive `demos/search/search-form.php`

[^ Top](#top)

### Search on Load

Following config will enable search on load. Initialize search with `name` field equal to `eq` 'Client 1'

	$sarr = <<< SEARCH_JSON
	{
		"groupOp":"AND",
		"rules":[
		  {"field":"name","op":"eq","data":"Client 1"}
		 ]
	}
	SEARCH_JSON;

	$opt["search"] = true;
	$opt["postData"] = array("filters" => $sarr );

If you wish to persist search settings on page reload:

	$opt["persistsearch"] = true;

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/search/search-onload.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/search/search-onload.php)
- You can check this demo in archive `demos/search/search-onload.php`

[^ Top](#top)

### Search based on URL parameters

You can filter datagrid based on URL parameter as well. Url format is {gridid}_{colname}={value}
e.g. page.php?list1_closed=1 will filter grid with id `list1` on page.php with column name `closed` to `1`
You can add multiple filtering (AND) conditions as shown in image.

![URL Based Filtering](https://www.phpgrid.org/wp-content/uploads/v26-search_url.png)

To have a numeric range filter, (total > 10) you can set e.g. ?list1_total=>10

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/search/search-onload-url.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/search/search-onload-url.php)
- You can check this demo in archive `demos/search/search-onload-url.php`

[^ Top](#top)

### Show / Hide columns based on URL parameters

You can show or hide certain column based on URL parameter as well.
Url format is {gridid}_showcols={col1},{col2} or {gridid}_hidecols={col1},{col2}

e.g. `page.php?list1_showcols=id,invdate,note&list1_hidecols=total`

This will show columns with name `id`,`invdate`,`note` (if defined and hidden) and hide column name `total`
where `list1` is grid id on page.php.

[^ Top](#top)

## Grid Events

For advance solutions, We are not limited to single table operations. We often need to update several tables and execute extra business cases like sending an email or soft delete a record.

We can have our own code-behind implementation for ADD, UPDATE or DELETE operations.

The `on_insert` takes 3 params (function-name, class-object or null-if-global-func, continue-default-grid-operation)

If you pass last argument as true, functions will act as a filter and insert/update in `->table` will be performed by grid after your function.
If last argument is set to false, only your function handler will be executed and grid's internal implementation will be ignored.

	$e["on_insert"] = array("add_client", null, false);
	$e["on_update"] = array("update_client", null, false);
	$e["on_delete"] = array("delete_client", null, true);

	// return last inserted id for further working
	$e["on_after_insert"] = array("after_insert", null, true);
	$e["on_after_update"] = array("after_update", null, true);

	// invoked to filter data before displaying on grid
	$e["on_data_display"] = array("filter_display", null, true);

	// ...

	$g->set_events($e);

In each callbacks, `$data` is passed to function which contains all posted data. We can `print_r()` it for further help.

	function add_client($data)
	{
		global $grid;
		$grid->execute_query("INSERT INTO clients
						VALUES (null,'{$data["params"]["name"]}'
									,'{$data["params"]["gender"]}'
									,'{$data["params"]["company"]}')");
	}

If the 3rd argument is true, the function will behave as a data filter and the final update will be done by grid code. For e.g.

	$e["on_update"] = array("update_client", null, true);
	...
	function update_client(&$data)
	{
		// set current date time internally
		$data["params"]["reg_date"] = date("Y-m-d H:i:s");
	}

If the 3rd argument is false, the function will be executed and grid's implementation will be skipped.
In that case, the callback for on_insert and on_update should echo JSON, e.g.

	// if you make it 3rd param to false, then it should return json data
	// e.g. $e["on_insert"] = array("add_client", null, false);

	function add_client($data)
	{
		// ... custom code to make $sql

		global $grid; // where $grid = new jqgrid(...);

		$insert_id = $grid->execute_query($sql,false,"insert_id");

		if (intval($insert_id)>0)
			$res = array("id" => $insert_id, "success" => true);
		else
			$res = array("id" => 0, "success" => false);

		echo json_encode($res);
		die;
	}

Inside callback functions, you can check whether $data variables have all such keys.
Following will print $data in error msg. You can debug all data to see the issue.

You can also put phpgrid_error(mysql_error()); before die statement.

	function update_client($data)
	{
		ob_start();
		print_r($data);
		phpgrid_error(ob_get_clean());

		// ...
	}

You can also write you custom function for data export (see export-custom.php)
$e["on_export"] = array("do_export", null);

	// custom on_export callback function
	function custom_export($param)
	{
		$sql = $param["sql"]; // the SQL statement for export
		$grid = $param["grid"]; // the complete grid object reference

		if ($grid->options["export"]["format"] == "xls")
		{
			// excel generate code goes here
		}
		else if ($grid->options["export"]["format"] == "pdf")
		{
			// pdf generate code goes here
		}
	}

To use custom SQL for search operations on particular field, you can use on_select event.

	$e["on_select"] = array("custom_select","");
	$g->set_events($e);

	function custom_select($d)
	{
		// search params
		$search_str = $this->strip($d["param"]['filters']);
		$search_arr = json_decode($search_str,true);
		$gopr = $search_arr['groupOp'];
		$rule = $search_arr['rules'][0];

		// sort by params
		$sidx = $d["param"]['sidx']; // get index row - i.e. user click to sort
		$sord = $d["param"]['sord']; // get the direction

		if ($rule["field"] == "name")
		{
			$d["sql"] = "select * from clients WHERE name like '%{$rule["data"]}%' ORDER BY $sidx $sord";
			$d["sql_count"] = "select count(*) as c from clients";
		}
	}

You can also set Client side event handlers (e.g. on row select)

Step1: Set JS event handler

	// just set the JS function name (should exist)
	$e["js_on_select_row"] = "do_onselect";
	...
	$grid->set_events($e);

Step2: Define JS event handler (where 'list1' is grid id and 'company' is field name to load)

	<script>
	function do_onselect(id)
	{
		var rd = jQuery('#list1').jqGrid('getCell', id, 'company'); // where invdate is column name
		jQuery("#span_extra").html(rd);
	}
	</script>
	<br>
	Company: <span id="span_extra">Not Selected</span>

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/editing/custom-events.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/editing/custom-events.php)
- You can check this demo in archive `demos/editing/custom-events.php`

[^ Top](#top)

## Validation

#### JS Validation

You can specify the validation rules required on each column. Possible options are mentioned below

	$col["editrules"] = array("required"=>true);
	$col["editrules"] = array("number"=>true);
	$col["editrules"] = array("email"=>true);
	$col["editrules"] = array("date"=>true);
	$col["editrules"] = array("minValue"=>5, "maxValue"=>10);
	$col["editrules"] = array("url"=>true);

The `date` validation will check input against format specified in datefmt option, see `datefmt`.

#### Custom JS Validation

For custom validation function (be it ajax remote checking or complex regex), Follow following steps.
For e.g. to check certain column value must be greater than 100:

Step1: Define `custom_func` property for JS function

	$col = array();
	$col["title"] = "Date";
	$col["name"] = "invdate";
	$col["width"] = "50";
	$col["editable"] = true;
	$col["editrules"] = array("custom"=>true,"custom_func"=>"function(val,label){return my_validation(val,label);}");
	$cols[] = $col;

Step2: Define JS callback function

	<script>
    function my_validation(value,label)
    {
        if (value > 100)
            return [true,""];
        else
            return [false,label+": Should be greater than 100"];
    }
    </script>

To validate some field 'onblur' JS event, set it in 'editoptions' and define JS callback function like above.

	$col["editoptions"] = array("onblur"=>"validate_onblur(this)");

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/editing/js-validation.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/editing/js-validation.php)
- You can check this demo in archive `demos/editing/js-validation.php`

#### Server Validation

![Server Validation](//www.phpgrid.org/wp-content/gallery/documentation/server-validation.png)

If you want to validate that client does not already exist in database. Following code will prompt the ‘already exist’ message as data entry error.

Step1: Define on_insert event handler 'add_client' for server validation.

	$e["on_insert"] = array("add_client", null, true);
	$grid->set_events($e);

Step2: The helper function ‘phpgrid_error’ will display your server side validation message as error dialog.

	function add_client($data)
	{
		global $grid; // where $grid = new jqgrid(...);

		$check_sql = "SELECT count(*) as c from clients where LOWER(`name`) = '".strtolower($data["params"]["name"])."'";

		$rs = $grid->get_one($check_sql);

		if ($rs["c"] > 0)
			phpgrid_error("Client already exist in database");

		$grid->execute_query("INSERT INTO clients VALUES (null,'{$data["params"]["name"]}','{$data["params"]["gender"]}','{$data["params"]["company"]}')");
	}

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/editing/server-validation.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/editing/server-validation.php)
- You can check this demo in archive `demos/editing/server-validation.php`

[^ Top](#top)

## Upload Files

![Using File Upload](//www.phpgrid.org/wp-content/gallery/documentation/fileupload.png)

Step1: Define column with edittype 'file', and set uploading path in 'upload_dir' property.

	// file upload column
	$col = array();
	$col["title"] = "Note";
	$col["name"] = "note";
	$col["width"] = "50";
	$col["editable"] = true;

	$col["edittype"] = "file"; // render as file
	$col["upload_dir"] = "temp"; // upload here

	$col["show"] = array("list"=>false,"edit"=>true,"add"=>true); // only show in add/edit dialog
	$cols[] = $col;

Step2: To display uploaded file in grid, make a (non-db) virtual column.

	$col = array();
	$col["title"] = "Image";
	$col["name"] = "logo";
	$col["width"] = "200";
	$col["editable"] = true;
	$col["default"] = "<a href='http://jqgrid/dev/demos/dev/{note}' target='_blank'><img height=100 src='http://jqgrid/dev/demos/dev/{note}'></a>";
	$col["show"] = array("list"=>true,"edit"=>false,"add"=>false); // only show in listing
	$cols[] = $col;

You can also decide what to do when file already exist:

	// prompt error
	$col["editrules"] = array("ifexist"=>"error");

	// rename file e.g. file_1,file_2,file_3 etc (default)
	$col["editrules"] = array("ifexist"=>"rename");

	// override file
	$col["editrules"] = array("ifexist"=>"override");

To restrict uploaded files based on extension you can set:

	$col["editrules"]["allowedext"] = "jpeg,jpg,png,bmp,gif"; // comma separated list of extensions

To upload multiple files, you can set following. It uploads all selected files in specified folder and set comma separated file names
in posted array field to be saved in db. One can use on_insert, on_update to separate them and save in separate table if required.

	$col["editoptions"]["multiple"] = "multiple";

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/editing/file-upload.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/editing/file-upload.php)
- You can check this demo in archive `demos/editing/file-upload.php`

[^ Top](#top)

## Footer Summary

![Footer](//www.phpgrid.org/wp-content/gallery/documentation/footer.png)

Step1: Enable footer in grid options and connect grid load event.

	$opt["footerrow"] = true;
	$opt["loadComplete"] = "function(){ grid_onload(); }";
	$g->set_options($opt);

Step2: Write JS code to fill footer row.

	<script>
	// e.g. to show footer summary
	function grid_onload()
	{
		// where list1 is grid id
		var grid = $("#list1");

		// get sum of column `total`
		// can use other functions like 'sum, 'avg', 'count' (use count-1 as it count footer row).
		var sum = grid.jqGrid('getCol', 'total', false, 'sum');

		// set in footer under another column 'id'
		grid.jqGrid('footerData','set', {id: 'Total: ' + sum});
	};
	</script>

If using formatter in columns (like currency etc), you need to pass 4th param to false. e.g.

	grid.jqGrid('footerData','set', { id: 'Total: €' + sum.toFixed(2) }, false);

For more advanced example, refer sample code below.

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/appearance/footer-row.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/appearance/footer-row.php)
- You can check this demo in archive `demos/appearance/footer-row.php`

[^ Top](#top)

## Autocomplete

Steps shows how to integrate database driven type ahead and autocomplete by lookup query.

#### Basic Typeahead (single field)

Step1: Set formatter to autocomplete on desired column

	$col["formatter"] = "autocomplete"; // autocomplete

Step2: Set format options query. The field in sql aliased 'v' will be shown in list

	// Fill the name field with query values typeahead
	$col["formatoptions"] = array(	"sql"=>"SELECT name as v FROM clients",
									"update_field"=>"name");

#### Autofill other field.

The field 'company' will be filled w.r.t. selected name.

	$col["formatoptions"] = array(	"sql"=>"SELECT company as k, name as v FROM clients",
									"update_field"=>"company");

The field aliased 'k' will be set in the 'updated_field' column (e.g. company)

#### Callback function

Connect a callback function that will auto-fill multiple fields & search in both name + id,

	$col["formatoptions"] = array(	"sql"=>"SELECT *, name as v FROM clients",
									"search_on"=>"concat(name,'-',client_id)",
									"callback"=>"fill_form");

and in html part, define callback function.

	<script>
	function fill_form(data)
	{
		jQuery("input[name=gender].FormElement").val(data.gender);
		jQuery("textarea[name=company].FormElement").val(data.company);

		jQuery("input[name=gender].editable").val(data.gender);
		jQuery("textarea[name=company].editable").val(data.company);
	}
	</script>

#### Force Selection

You can also force to select from one of the options, set force_select => true

	// callback function
	$col["formatoptions"] = array(	"sql"=>"SELECT *, name as v FROM clients where gender='male' ORDER BY name desc",
									"search_on"=>"concat(name,'-',client_id)",
									"force_select"=>true);

By default, autocomplete uses 'contains' search. To switch to 'begins with' set:

	$col["formatoptions"]["op"] = "bw";

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/integrations/autocomplete.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/integrations/autocomplete.php)
- You can check this demo in archive `demos/integrations/autocomplete.php`

[^ Top](#top)

## Multiselect Filter

Step1: Include JS / CSS files required to have this feature. Make sure you include JS files after jQuery JS inclusion.

	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-ui-multiselect-widget/1.17/jquery.multiselect.css">
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-ui-multiselect-widget/1.17/jquery.multiselect.filter.css">
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ui-multiselect-widget/1.17/jquery.multiselect.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ui-multiselect-widget/1.17/jquery.multiselect.filter.js"></script>

Step2:

To have multi-select filter in search bar, add following properties with desired column:

	// multi-select in search filter
	$col["stype"] = "select-multiple";
	$col["searchoptions"]["value"] = $str; // e.g. $str = "key1:value1;key2:value2;key3:value3"

It will replace search text box to multi-select filter for grid column `name`

	$col = array();
	$col["title"] = "Name";
	$col["name"] = "name";

	// this will prepare (key:value) option list for dropdown filters
	$str = $g->get_dropdown_values("select distinct name as k, name as v from clients");

	// multi-select in search filter
	$col["stype"] = "select-multiple";
	$col["searchoptions"]["value"] = $str;

	$cols[] = $col;

If your column contains foreign key data (like client_id) then implementation will look like this:

	$col = array();
	$col["title"] = "Client";
	$col["name"] = "client_id";
	$col["dbname"] = "invheader.client_id";
	$col["width"] = "100";

	// this will prepare (key:value) option list for dropdown filters
	$str = $g->get_dropdown_values("select distinct client_id as k, name as v from clients limit 10");

	// in edit mode render as select
	$col["edittype"] = "select";
	$col["editoptions"] = array("value"=>":;".$str);

	// multi-select in search filter
	$col["stype"] = "select-multiple";
	$col["searchoptions"]["value"] = $str;

	$cols[] = $col;

![Multiselect Filter Search](//www.phpgrid.org/wp-content/gallery/images-v2/multiselect-filter.png)

[^ Top](#top)

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/integrations/multiselect-filter.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/integrations/multiselect-filter.php)
- You can check this demo in archive `demos/integrations/multiselect-filter.php`

[^ Top](#top)

## State Persistence

Step1: Include JS / CSS files required to have this feature. Make sure you include JS files after jQuery JS inclusion.

	<!-- library for persistance storage -->
	<script src="//cdn.jsdelivr.net/jstorage/0.1/jstorage.min.js" type="text/javascript"></script>
	<script src="//cdn.jsdelivr.net/json2/0.1/json2.min.js" type="text/javascript"></script>
	<script src="//cdn.jsdelivr.net/gh/gridphp/jqGridState@10b365046ebd687914855e807eb5f769277317d5/jqGrid.state.js" type="text/javascript"></script>

Step2: Before displaying grid echo $out, set persistence options in script tag:

	<script>
	var opts_list1 = {
		"stateOptions": {
					storageKey: "gridState-list1",
					columns: true, // remember column chooser settings
					selection: true, // row selection
					expansion: true, // subgrid expansion
					filters: true, // filters
					pager: true, // page number
					order: true // field ordering
		}
	};
	</script>

- Set true/false setting in JS object you want to keep persistence on page reload.
- If you have single grid on page, `var opts` will also work. However it's better to use `var opts_<gridid>`
- Option `storageKey` should be unique for each grid, otherwise settings will mix-up.
- It uses client side browser storage. To persist on server, refer demo code below.

[^ Top](#top)

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/misc/persist-settings.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/misc/persist-settings.php)
- You can check this demo in archive `demos/misc/persist-settings.php`

[^ Top](#top)

## Responsive Design

You can define which columns to show or hide based on screen resolution.
Currently it uses following starting breakpoints.

	xs - Extra Small devices (320px)
	sm - Small devices (544px)
	md - Medium devices (768px)
	lg - Large devices (992px)
	xl - Extra Large devices (1200px)

By default it will auto hide columns from end based on screen size.

	$opt["responsive"] = true;
	...
	$g->set_options($opt);

To override and make a column visible on small devices and above, you can set:

	$col["visible"] = "sm+";

Complete column settings will be like following:

	$col = array();
	$col["title"] = "Id";
	$col["name"] = "id";
	$col["width"] = "20";
	$col["editable"] = false;
	$col["visible"] = "sm+";
	$cols[] = $col;

You can also specify certain screen sizes for a column. Following column will be shown on XS, SM and MD screen sizes.

	$col["visible"] = array("xs","sm","md");

You can always show/hide certain columns by Column Chooser.

![Column selection in Responsive mode](//www.phpgrid.org/wp-content/gallery/documentation/responsive-colchoose.png)

Below small devices screen sizes, It changes operation toolbar to 3 line toolbar.

![Toolbar in Responsive mode](//www.phpgrid.org/wp-content/gallery/documentation/responsive-toolbar.png)

And display of add/edit/view dialogs are transposed as well.

![Dialogs in responsive mode](//www.phpgrid.org/wp-content/gallery/documentation/responsive-edit.png)
![Dialogs in responsive mode](//www.phpgrid.org/wp-content/gallery/documentation/responsive-view.png)

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/appearance/responsive.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/appearance/responsive.php)
- You can check this demo in archive `demos/appearance/responsive.php`

[^ Top](#top)

## Localization

![Localization Japanese](//www.phpgrid.org/wp-content/gallery/documentation/localization-japanese.png)
![Localization Arabic](//www.phpgrid.org/wp-content/gallery/documentation/localization-arabic.png)

To enable text labels in your desired language, change source of the local javascript file. Available language packs are stored in this folder `js/jqgrid/js/i18n/`. Over 39 language packs are in the solution. (see localization.php)

	<!-- to enable arabic -->
	<script src="js/jqgrid/js/i18n/grid.locale-ar.js" type="text/javascript"></script>

	<!-- to enable spanish -->
	<script src="js/jqgrid/js/i18n/grid.locale-es.js" type="text/javascript"></script>

	<!-- to enable french -->
	<script src="js/jqgrid/js/i18n/grid.locale-fr.js" type="text/javascript"></script>

	<!-- to enable italian -->
	<script src="js/jqgrid/js/i18n/grid.locale-it.js" type="text/javascript"></script>

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/misc/localization.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/misc/localization.php)
- You can check this demo in archive `demos/misc/localization.php`

To change string constants, you can edit related lang file e.g. "lib/js/jqgrid/js/i18n/grid.locale-en.js" OR do JS override on page:

	<script>
	$.jgrid.edit.bSubmit = "Save";
	</script>

[^ Top](#top)


## Themes
![Themes](//www.phpgrid.org/wp-content/gallery/documentation/themes.png)

You can also have your customized theme (<a href="http://jqueryui.com/themeroller">jqueryui.com/themeroller</a>).

	<link rel="stylesheet" type="text/css" media="screen" href="../../lib/js/themes/redmond/jquery-ui.custom.css"></link>

Instead of redmond in above code, you can use any of the themes from following list

- black-tie
- blitzer
- cupertino
- dark-hive
- dot-luv
- eggplant
- excite-bike
- flick
- hot-sneaks
- humanity
- le-frog
- mint-choc
- overcast
- pepper-grinder
- redmond
- smoothness
- south-street
- start
- sunny
- swanky-purse
- trontastic
- ui-darkness
- ui-lightness
- vader

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/appearance/themes.phps)
- [See Live Demo](//www.phpgrid.org/demo/demos/appearance/themes.php)
- You can check this demo in archive `demos/appearance/themes.php`

[^ Top](#top)

## Connecting with SQL Server

Following code snippet connect PHP Grid Framework to SQL Server.

	$db_conf = array();
	$db_conf["type"] = "mssqlnative";
	$db_conf["server"] = "(local)\sqlexpress";
	$db_conf["user"] = null;
	$db_conf["password"] = null;
	$db_conf["database"] = "master";

	$g = new jqgrid($db_conf);

	...

	$g->table = "[msdb].[dbo].[syscategories]";

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/loading/db-layer-sqlsvr.phps)
- You can check this demo in archive `demos/loading/db-layer-sqlsvr.php`

Connecting Azure database:

	$db_conf = array();
	$db_conf["type"] = "mssqlnative";
	$db_conf["server"] = "phpgrid.database.windows.net"; // ip:port
	$db_conf["user"] = "admin_phpgrid";
	$db_conf["password"] = "xxxxx";
	$db_conf["database"] = "griddemo";

	include("../../lib/inc/jqgrid_dist.php");
	$g = new jqgrid($db_conf);

Using PDO for SQL Server Azure:

	$db_conf = array();
	$db_conf["type"] = "pdo";
	$db_conf["server"] = "sqlsrv:Server=phpgrid.database.windows.net";
	$db_conf["user"] = "admin_phpgrid"; // username
	$db_conf["password"] = "xxxxx"; // password
	$db_conf["database"] = "griddemo"; // database

	include("../../lib/inc/jqgrid_dist.php");
	$g = new jqgrid($db_conf);

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/loading/db-layer-sqlsvr-azure.phps)
- You can check this demo in archive `demos/loading/db-layer-sqlsvr-azure.php`

## Connecting with Postgres

Following code snippet connect PHP Grid with Postgres.

	$db_conf = array();
	$db_conf["type"] = "postgres"; // mysql,oci8(for oracle),mssql,postgres,sybase
	$db_conf["server"] = "localhost";
	$db_conf["user"] = "postgres";
	$db_conf["password"] = "abcd";
	$db_conf["database"] = "testdb"

	$g = new jqgrid($db_conf);

#### Resources

- [Sample Code](//www.phpgrid.org/demo/demos/loading/db-layer-pgsql.phps)
- You can check this demo in archive `demos/loading/db-layer-pgsql.php`

## Connecting with Oracle

Following code snippet connect PHP Grid with Oracle.

	$db_conf = array();
	$db_conf["type"] = "oci8"; // mysql,oci8(for oracle),mssql,postgres,sybase
	$db_conf["server"] = "127.0.0.1:1521";
	$db_conf["user"] = "system";
	$db_conf["password"] = "asd";
	$db_conf["database"] = "xe";

	include("../../lib/inc/jqgrid_dist.php");
	$g = new jqgrid($db_conf);

#### Resources

- [Oracle Sample Code](//www.phpgrid.org/demo/demos/loading/oracle-master-detail.phps)
- You can check this demo in archive `demos/loading/oracle-master-detail.php`

[^ Top](#top)

## Debug Mode

Debug mode is enabled by default and it will show the server side failure reason.
When going in production mode, you should disable the debug mode by following config.

	$g = new jqgrid();
	$g->debug = 0;

If you wish to change the SQL errors, you can turn them off using following setting.

	$g->error_msg = "System was unable to process your request. Please contact technical support.";

For custom message at server side data validation, refer demos/editing/server-validation.php

In order to debug SQL queries, set:

	$g->debug_sql = 1;

In order to debug Search queries, set:

	$g->debug_search = 1;

By enabling `debug_sql` or `debug_search` configuration, you will see SQL queries being sent to database in error message box.
You can also close error box and continue next debug step.

#### Resources

- [See Reference](//www.phpgrid.org/updates/running-php-grid-in-debug-mode/)

[^ Top](#top)

## Basic Todo List Application

To show some basic features of php grid framework, we created a very simple demo of todo list and following features are used:

- Bootstrap 4 + Mobile sidebar filter menu
- Conditional Formatting
- Custom delete event callback for soft delete
- External Search form (date range, text, priority filters)
- Checkbox with default edit mode
- Export to Excel

Desktop screen:

![Desktop View](//www.phpgrid.org/wp-content/uploads/todo-desktop-1024x532.png)

Mobile screen:

![Mobile View](//www.phpgrid.org/wp-content/uploads/todo-app.gif)

#### Resources

- [See Live Demo](//www.phpgrid.org/demo/demos/apps/todos.php)
- [Source Code](//www.phpgrid.org/demo/demos/apps/todos.phps)

[^ Top](#top)

---

Updated Thursday, September 26th, 2019
