View Full Version : Example of editor-grid using php and mysql to save data
bd318
26 Jul 2007, 7:14 AM
Updated post:
I made an update for this example. To make sure all new readers see this instead of the post before, I edit it here.
The new WORKING example is as followed:
The js file:
var GridUI = function() {
//enable Quicktips
Ext.QuickTips.init();
//set vars
var ds; //datastore for grid
var cm; //columnModel
var grid; //component
var fm = Ext.form, Ed = Ext.grid.GridEditor; // shorthand alias
//create the datastores
function setupDataSource() {
//create the Data Store for the grid
ds = new Ext.data.Store({
//set the http-proxy (link to the php document)
proxy: new Ext.data.ScriptTagProxy({
url: 'sample.php?ac=showData' //a function in your php-script must be activated when ac = showdata
}),
//set up the JsonReader
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'id'
},[
{name: 'name', type: 'string', mapping: 'name'} //columnmapping
])
});
//load datastores
ds.load();
}
//create the columnmodel
function getColumnModel() {
cm = new Ext.grid.ColumnModel([{
header: "Names",
dataIndex: 'name',
width: 150,
editor: new Ed(new fm.TextField({
allowBlank: true,
maxLength: 50
}))
}]);
//set the default for sorting the columns
cm.defaultSortable = false;
return cm;
}
//create the grid
function buildGrid() {
//create the form
var gridForm = new Ext.form.Form({});
//create the grid
var grid = new Ext.grid.EditorGrid('editor-grid', {
ds: ds,
cm: getColumnModel(),
enableColLock:false,
selModel: new Ext.grid.RowSelectionModel({singleSelect:true})
});
//set the layout for the grid
var layout = Ext.BorderLayout.create({
center: {
margins:{left:3,top:3,right:3,bottom:3},
panels: [new Ext.GridPanel(grid)]
}
}, 'grid-panel');
//render the grid
grid.render();
//set the header
var gridHead = grid.getView().getHeaderPanel(true);
var tb = new Ext.Toolbar(gridHead, [{}]);
//activate function updateDB when a cell is edited
grid.on('afteredit', updateDB);
function updateDB(oGrid_event){
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'sample.php?ac=saveData&field='+oGrid_event.field+'&row='+oGrid_event.row+'&value='+oGrid_event.value, //php function that saves the data
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
//render form
gridForm.render('editGrid');
}
return {
//the init
init : function() {
setupDataSource();
buildGrid();
},
getDataSource: function() {
return ds;
}
}
}();
Ext.onReady(GridUI.init, GridUI, true);
The php-file:
<?php
//make database connection
mysql_connect("localhost", "YOUR USERNAME", "YOUR PASSWORD") or
die("Could not connect: " . mysql_error());
mysql_select_db("YOUR DATABASE");
if(isset($_GET['ac']) && $_GET['ac']=='showData')
showData();
elseif(isset($_GET['ac']) && $_GET['ac']=='saveData')
saveData($_GET['field'], $_GET['row'], $_GET['value']);
function showData()
{
//query with data
$result = mysql_query("SELECT id, name FROM names");
$rows = mysql_num_rows($result);
while($rec = mysql_fetch_array($result))
$arr[] = $rec;
echo $_GET['callback'].'({"total":"'.$rows.'","results":'.json_encode($arr).'})';
}
function saveData($field, $row, $value)
{
/*
* field: the dataIndex which is being updated
* $row: the row that is being updated
* $value: the new value
*/
//look which record is being updated
$result = mysql_query("SELECT id FROM names");
while($rec = mysql_fetch_array($result))
$id[] = $rec['id'];
//NOTE: this isn't the best way to save your data!
//What I do is look in the database and put all the ID's in an array.
//Then I know that $row is the right array index.
//But when you change the order of the records for example, this isn't enough to know the row
//However, this example works :)
//save data to database
if($field=='name') //the field name is being updated
$result = mysql_query("UPDATE `names` SET `name` = '$value' WHERE `id`='$id[$row]';");
}
?>
The html-file:
<html>
<head>
<title>Sample of a grid</title>
<script language="JavaScript" type="text/javascript" src="adapter/ext/ext-base.js"></script>
<script language="JavaScript" type="text/javascript" src="ext-all.js"></script>
<script language="JavaScript" type="text/javascript" src="sample.js"></script>
<link rel="stylesheet" type="text/css" href="resources/css/ext-all.css" media="screen" />
</head>
<body>
<div id="grid-panel" style="width:1024px;height:668px;">
<div id="editor-grid"></div>
<div id="editGrid">
</div>
</div>
</body>
</html>
The database:
--
-- Table structure for table `names`
--
CREATE TABLE `names` (
`id` int(8) unsigned NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
--
-- Dumping data for table `names`
--
INSERT INTO `names` (`id`, `name`) VALUES
(1, 'Testname'),
(2, 'Testname2'),
(3, 'Testname3'),
(4, 'Testname4');
You acces the grid by going to the sample.html page!
NOTE: Don't forget to set your database username and password in the php-file and include ext-base.js and ext-all.js!!
First post:
In my search on this forum to read a DataStore, display the data in a grid, edit the cells in a grid and then update the database using php and mysql I couldn't find a full working sample. So, now I found out how to do it, I want to share it with you all.
I made the example as easy as possible. Because I'm a new EXT user, there are probably better known ways to update your database, but the example I made must work after a little editting (you have to make your queries for selecting data yourself!) and will hopefully help all the others I saw looking for help on this.
With help of other posts from users (thanks all) I came to the following code.
Create your grid (to make it easy, I made one column): sample.js
var GridUI = function() {
//enable Quicktips
Ext.QuickTips.init();
//set vars
var ds; //datastore for grid
var cm; //columnModel
var grid; //component
var fm = Ext.form, Ed = Ext.grid.GridEditor; // shorthand alias
//create the datastores
function setupDataSource() {
//create the Data Store for the grid
ds = new Ext.data.Store({
//set the http-proxy (link to the php document)
proxy: new Ext.data.ScriptTagProxy({
url: 'index.php?ac=showdata' //a function in your php-script must be activated when ac = showdata
}),
//set up the JsonReader
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'id'
},
{name: test, type: 'string', mapping: 'test'} //columnmapping
)
});
//load datastores
ds.load();
}
//create the columnmodel
function getColumnModel() {
cm = new Ext.grid.ColumnModel([{
header: "Testcolumn",
dataIndex: 'test',
//width: 150,
editor: false
}]);
//set the default for sorting the columns
cm.defaultSortable = false;
return cm;
}
//create the grid
function buildGrid() {
//create the form
var gridForm = new Ext.form.Form({});
//create the grid
var grid = new Ext.grid.EditorGrid('editor-grid', {
ds: ds,
cm: getColumnModel(),
enableColLock:false,
selModel: new Ext.grid.RowSelectionModel({singleSelect:true})
});
//set the layout for the grid
var layout = Ext.BorderLayout.create({
center: {
margins:{left:3,top:3,right:3,bottom:3},
panels: [new Ext.GridPanel(grid)]
}
}, 'grid-panel');
//render the grid
grid.render();
//set the header
var gridHead = grid.getView().getHeaderPanel(true);
var tb = new Ext.Toolbar(gridHead, [{}]);
//activate function updateDB when a cell is edited
grid.on('afteredit', updateDB);
function updateDB(oGrid_event){
jsonData = "[";
for(i=0;i<ds.getCount();i++) {
record = ds.getAt(i);
jsonData += Ext.util.JSON.encode(record.data) + ",";
}
jsonData = jsonData.substring(0,jsonData.length-1) + "]";
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'index.php?ac=saveData', //php function that saves the data
params:{data:jsonData},
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
//render form
gridForm.render('editGrid');
}
return {
//the init
init : function() {
setupDataSource();
buildGrid();
},
getDataSource: function() {
return ds;
}
}
}();
Ext.onReady(GridUI.init, GridUI, true);
The HTML-code: index.tpl
<html>
<head>
<script src="ext-all.js" type="text/javascript"></script>
<script src="adapter/ext/ext-base.js" type="text/javascript"></script>
<script src="sample.js" type="text/javascript"></script>
<link href="resources/css/ext-all.css" media="screen" rel="Stylesheet" type="text/css" />
</head>
<body>
<div id="grid-panel" style="width:1024px;height:668px;">
<div id="editor-grid"></div>
<div id="editGrid">
</div>
</div>
</body>
</html>
The php code (index.php):
function showData()
{
//make your query here that selects all your data for the grid
//you have to modify the $res and fetch yourself to make the query succesfull
$res = $this->dbi->query('your query here');
while($obj =& $this->dbi->fetch())
{
$arr[] = $obj;
}
//encode your data for the jsonreader
echo $_GET['callback'].'({"total":"'.$rows.'","results":'.json_encode($arr).'})';
}
function saveData()
{
$data = json_decode(stripslashes($_POST['data']));
//make here a query that updates the database
}
Remember you still have to do some work yourself: make the database queries and modify the ColumnModel and DataStore so it matches your data.
$data in saveData() is an 2D array, which you have to read by a foreach loop and put it in the database. Use echo var_dump($data); to see how the array is build!
Note that in this example the whole grid is submitted once you edit a sell, so if you have a 100+ record grid it becomes slower and slower.
When I find out how, I post an example in this topic how to update only one cell in the database after editing.
Good luck!
akbeyfb
27 Jul 2007, 1:35 AM
hi it looks helpfull for the new ext users like me is it possible to give us to your work with the source files.i couldnt run on my local server
bd318
27 Jul 2007, 1:36 AM
I found out how I can update only one cell. In the sample.js file, change the function updateDB to the following:
function updateDB(oGrid_event){
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'index.php?ac=saveData&column='+oGrid_event.field+'&row='+oGrid_event.row+'&value='+oGrid_event.value, //php function that saves the data
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
Ofcourse, you can give the url whatever value you want, but (atleast for me), I know when I have the columnid and rowid what value is updated.
So in the PHP you have to change the query to what is updated (it's depending of the column and row). You can work something out like:
If($column==1 & $row==1)
{
//update query (nowing for example that column1 contains names and row 1 is the second user)
}
akbeyfb
27 Jul 2007, 4:58 AM
i got this error message :Ext.QuickTips is null or is not an object..
bd318
27 Jul 2007, 5:24 AM
Make sure you have the includes of the ext-all.js and ext-base.js correct (modify index.tpl if needed). Hopefully that's the problem.
I'll try to get an working example later with source files.
laozhuang
27 Jul 2007, 7:33 PM
I post the submit action to MyServlet,
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'http://localhost:8080/MyServlet',
params:{JSON_OBJECT:jsonData},
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
MyServlet work well but the action response is 'failure'.
How can I track the failure message.
Thank you very much
cluettr
27 Jul 2007, 8:06 PM
Awesome, with a post like this you'll be sure to save a newbie some time and help get them up to speed much faster!
perthkit
1 Aug 2007, 3:23 AM
Thanks for your code.
However, I couldn't make it work. like
sample.js, line 26:
{name: test, type: 'string', mapping: 'test'} -or- {name: 'test', type: 'string', mapping: 'test'}
It will be great if you can post the sql file with the table structure and simple data which we can play around. If it is too much, it will be great if you can post the raw json data for index.php?ac=showdata.
Thanks again.
ccquiles
1 Aug 2007, 9:57 AM
YES! thanks for your code... however I could not get it to work either... I do not get any errors, but nothing happens and I don't see the 'saving data' or either of the alerts in the updateDB function... any ideas?
bd318
2 Aug 2007, 11:44 PM
I updated the initial post with a tested and working example!
All that had errors, try again please with the new code :)
cluettr
3 Aug 2007, 2:04 AM
The screencast in the learning section covers most of the js side.
i understand that this is an example post, but please escape the sql query so it cannot lead to an sql injection attack with something like mysql_real_escape.
//save data to database
if($field=='name') //the field name is being updated
$result = mysql_query("UPDATE `names` SET `name` = '$value' WHERE `id`='$id[$row]';");
vibez
11 Aug 2007, 8:05 AM
Thanks for writing this guide, I do have this problem when editting the cells
syntax error
http://localhost/grid/ext/ext-all.js
Line 38
This is the line
Ext.util.JSON=new(function(){var _1={}.hasOwnProperty?true:false;var _2=function(n){return n<10?"0"+n:n;};var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r","\"":"\\\"","\\":"\\\\"};var _5=function(s){if(/["\\\x00-\x1f]/.test(s)){return"\""+s.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];if(c){return c;}c=b.charCodeAt();return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16);})+"\"";}return"\""+s+"\"";};var _a=function(o){var a=["["],b,i,l=o.length,v;for(i=0;i<l;i+=1){v=o[i];switch(typeof v){case"undefined":case"function":case"unknown":break;default:if(b){a.push(",");}a.push(v===null?"null":Ext.util.JSON.encode(v));b=true;}}a.push("]");return a.join("");};var _11=function(o){return"\""+o.getFullYear()+"-"+_2(o.getMonth()+1)+"-"+_2(o.getDate())+"T"+_2(o.getHours())+":"+_2(o.getMinutes())+":"+_2(o.getSeconds())+"\"";};this.encode=function(o){if(typeof o=="undefined"||o===null){return"null";}else{if(o instanceof Array){return _a(o);}else{if(o instanceof Date){return _11(o);}else{if(typeof o=="string"){return _5(o);}else{if(typeof o=="number"){return isFinite(o)?String(o):"null";}else{if(typeof o=="boolean"){return String(o);}else{var a=["{"],b,i,v;for(i in o){if(!_1||o.hasOwnProperty(i)){v=o[i];switch(typeof v){case"undefined":case"function":case"unknown":break;default:if(b){a.push(",");}a.push(this.encode(i),":",v===null?"null":this.encode(v));b=true;}}}a.push("}");return a.join("");}}}}}}};this.decode=function(_18){return eval("("+_18+")");};})();Ext.encode=Ext.util.JSON.encode;Ext.decode=Ext.util.JSON.decode;
While the table does update, I dont get any message informing me that it has done so.
kayegil.hauan
12 Aug 2007, 1:26 AM
My Grid shows no data using this method, probably due to the php function 'json_encode()' not being installed on my server (PHP version 5.1.6).
Can anyone tell me what a call to the 'sample.php?ac=showData' should ideally output in the above example so I could work my way around the json_encode function?
Mark
13 Aug 2007, 12:32 PM
I'm not sure what you need? Perhaps a sample of the JSON-output helps you along...
({"totalProperty":"3","results":[{"name":"Max"},{"name":"Moritz"},{"name":"Struwelpeter"}]})
Greets, Mark
lake
13 Aug 2007, 10:39 PM
this is what i looking for,thx man!:D
nunez
15 Aug 2007, 9:51 AM
YES! thanks for your code... however I could not get it to work either... I do not get any errors, but nothing happens and I don't see the 'saving data' or either of the alerts in the updateDB function... any ideas?
I test this sample and is working just fine.
The only error in the source is not returning
{success: true/false }
at the end of the
function saveData($field, $row, $value)
Dont' forget to include the
ext-base.js
ext-all.js
and the css files for the grid.
Thanks bd318 for this example.
Keep the good work.
nunez
15 Aug 2007, 2:07 PM
I edit your updateDB function to update the field by id and not by rowindex, and pass the var by post.
function updateDB(grid, e){
id = ds.data.items[grid.row].id;
gridForm.submit(
{
url: 'sample.php?ac=saveData',
params: {
id: id,
field: grid.field,
value: grid.value
},
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
In the sample.php :
saveData($_POST['field'], $_POST['id'], $_POST['value']);
Then in your PHP you only need to do the
UPDATE `names` SET `name` = '$value' WHERE `id`='$id'
nunez
15 Aug 2007, 2:25 PM
After editing all this example, I try to use this in another app.
But the firebug is showing this error
this.el has no properties
BasicForm(null)ext-all.js (line 208)
Form(Object dom=div#teste id=teste visibilityMode=1)ext-all.js (line 210)
buildGrid()actions.js (line 113)
init()actions.js (line 120)
EventManager(function(), Object, true)ext-all.js (line 18)
chrome://firebug/content/blank.gifExt.form.BasicForm=function(el,_2){Ext.apply(this,_2);this.items=new Ext.util.Mi...
in the
gridForm.submit(...)
and the
gridForm.render('editGrid');
if I delete the gridForm.render, the error is resolve, but in the afteredit when the submit is fire, the firebug show the error again.
Anyone know what is the problem?
Is amazing, I edit the example pass from get to post and change to httpproxy and work just fine, when I copy and paste without editing anything to my app the error appear again.
If anyone can help, I appreciate.
bd318
16 Aug 2007, 1:48 AM
Are you sure you copied the code to make the form? And make sure the id from the DIV tag in your htmlfile is set correct (editGrid)
var gridForm = new Ext.form.Form({});
<div id="grid-panel" style="width:1024px;height:668px;">
<div id="editor-grid"></div>
<div id="editGrid">
</div>
</div>
nunez
16 Aug 2007, 4:47 AM
I resolve this. Was nothing to do with the example, was a </div> from another form.
Thank you.
bobz418
22 Aug 2007, 8:26 AM
Thanks for writing this guide, I do have this problem when editting the cells
syntax error
http://localhost/grid/ext/ext-all.js
Line 38
This is the line
Ext.util.JSON=new(function(){var _1={}.hasOwnProperty?true:false;var _2=function(n){return n<10?"0"+n:n;};var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r","\"":"\\\"","\\":"\\\\"};var _5=function(s){if(/["\\\x00-\x1f]/.test(s)){return"\""+s.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];if(c){return c;}c=b.charCodeAt();return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16);})+"\"";}return"\""+s+"\"";};var _a=function(o){var a=["["],b,i,l=o.length,v;for(i=0;i<l;i+=1){v=o[i];switch(typeof v){case"undefined":case"function":case"unknown":break;default:if(b){a.push(",");}a.push(v===null?"null":Ext.util.JSON.encode(v));b=true;}}a.push("]");return a.join("");};var _11=function(o){return"\""+o.getFullYear()+"-"+_2(o.getMonth()+1)+"-"+_2(o.getDate())+"T"+_2(o.getHours())+":"+_2(o.getMinutes())+":"+_2(o.getSeconds())+"\"";};this.encode=function(o){if(typeof o=="undefined"||o===null){return"null";}else{if(o instanceof Array){return _a(o);}else{if(o instanceof Date){return _11(o);}else{if(typeof o=="string"){return _5(o);}else{if(typeof o=="number"){return isFinite(o)?String(o):"null";}else{if(typeof o=="boolean"){return String(o);}else{var a=["{"],b,i,v;for(i in o){if(!_1||o.hasOwnProperty(i)){v=o[i];switch(typeof v){case"undefined":case"function":case"unknown":break;default:if(b){a.push(",");}a.push(this.encode(i),":",v===null?"null":this.encode(v));b=true;}}}a.push("}");return a.join("");}}}}}}};this.decode=function(_18){return eval("("+_18+")");};})();Ext.encode=Ext.util.JSON.encode;Ext.decode=Ext.util.JSON.decode;While the table does update, I dont get any message informing me that it has done so.
I got the same error as you. While it doesn't seem to affect the program, it's annoying and hope someone has a clue to fix it.
nunez
28 Aug 2007, 4:05 PM
I Get a similar error with the grid few weeks a go. The error was in my PHP.
In my case my problem was in the return, I Insert, update or delete in the database, and the php return bad the json was simple
{success:true/false )}
echo ' {success:true} ';
else
echo ' {success:false} ';
my problem was a extra ")" this is not that difficult to resolve if you have the firebug.
One easy way to know if the problem is php is in the grid add success/failure with a message box, if the grid after a transaction don't show the message box is because the php is not returning well.
In my case, the php was inserting well and refreshing well the grid, but didn't show the message box.
I hope all this "work around" can help somebody.
DJERO77
3 Sep 2007, 4:27 AM
Hi,
Sorry for my english
I have created this file :
sample.php
sample.js
sample.html
but when i execute sample.php i have an error :
line 5
character: 1
error: ";" waited
http://localhost/TEST/ext-1.1.1/ext-1.1.1/sample.html
i have download and install Ext 1.1.1 and created table names.
Help me please.
Thank
I have resolve this error, I not have fonction json.
resolve is here : http://www.phpinfo.net/blogs/~jpdezelus/article/installer-extension-json-pour-php4.html
kayegil.hauan
3 Sep 2007, 6:47 AM
I had the same problem. json_encode() does not exist in PHP prior to PHP 5.2.0.
For all you who are using PHP older than 5.2.0 the following code will create a similar function.
Put this on top of your PHP file, but after the <?php start tag:
if (!function_exists(json_encode)) {
function json_encode(&$value) {
switch(gettype($value)) {
case 'double':
case 'integer':
return $value;
case 'bool':
return $value?'true':'false';
case 'string':
return '\''.addslashes($value).'\'';
case 'NULL':
return 'null';
case 'object':
return '\'Object '.addslashes(get_class($value)).'\'';
case 'array':
if (isVector($value))
return '['.implode(',', array_map('json_encode', $value)).']';
else {
$result = '{';
foreach ($value as $k=>$v) {
if ($result != '{') $result .= ',';
$result .= json_encode($k).':'.json_encode($v);
}
return $result.'}';
}
default:
return '\''.addslashes(gettype($value)).'\'';
}
}
function isVector (&$array) {
$next = 0;
foreach ($array as $k=>$v) {
if ($k != $next)
return false;
$next++;
}
return true;
}
}
The code is customized from a user contribution to the json_encode tutorial at php.net
steffenk
4 Sep 2007, 12:59 PM
i use a class found on the net:
if(function_exists('json_encode'))
return json_encode($arr);
else {
require_once(JSON.php');
$json=& new Services_JSON;
return $json->encode($arr);
}
and JSON.php:
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Converts to and from JSON format.
*
* JSON (JavaScript Object Notation) is a lightweight data-interchange
* format. It is easy for humans to read and write. It is easy for machines
* to parse and generate. It is based on a subset of the JavaScript
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
* This feature can also be found in Python. JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C-family of languages, including C, C++, C#, Java,
* JavaScript, Perl, TCL, and many others. These properties make JSON an
* ideal data-interchange language.
*
* This package provides a simple encoder and decoder for JSON notation. It
* is intended for use with client-side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client-side javascript, or
* decoded from incoming Javascript requests. JSON format is native to
* Javascript, and can be directly eval()'ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF-8 format!
*
* LICENSE: Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* @category
* @package Services_JSON
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_SLICE', 1);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_STR', 2);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_ARR', 3);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_OBJ', 4);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_CMT', 5);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_LOOSE_TYPE', 16);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
/**
* Converts to and from JSON format.
*
* Brief example of use:
*
* <code>
* // create a new instance of Services_JSON
* $json = new Services_JSON();
*
* // convert a complexe value to JSON notation, and send it to the browser
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
* $output = $json->encode($value);
*
* print($output);
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
*
* // accept incoming POST data, assumed to be in JSON notation
* $input = file_get_contents('php://input', 1000000);
* $value = $json->decode($input);
* </code>
*/
class Services_JSON
{
/**
* constructs a new JSON instance
*
* @param int $use object behavior flags; combine with boolean-OR
*
* possible values:
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
* "{...}" syntax creates associative arrays
* instead of objects in decode().
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
* Values which can't be encoded (e.g. resources)
* appear as NULL instead of throwing errors.
* By default, a deeply-nested resource will
* bubble up with an error, so all return values
* from encode() should be checked with isError()
*/
function Services_JSON($use = 0)
{
$this->use = $use;
}
/**
* convert a string from one UTF-16 char to one UTF-8 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf16 UTF-16 character
* @return string UTF-8 character
* @access private
*/
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
switch(true) {
case ((0x7F & $bytes) == $bytes):
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x7F & $bytes);
case (0x07FF & $bytes) == $bytes:
// return a 2-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xC0 | (($bytes >> 6) & 0x1F))
. chr(0x80 | ($bytes & 0x3F));
case (0xFFFF & $bytes) == $bytes:
// return a 3-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xE0 | (($bytes >> 12) & 0x0F))
. chr(0x80 | (($bytes >> 6) & 0x3F))
. chr(0x80 | ($bytes & 0x3F));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* convert a string from one UTF-8 char to one UTF-16 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf8 UTF-8 character
* @return string UTF-16 character
* @access private
*/
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
}
switch(strlen($utf8)) {
case 1:
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return $utf8;
case 2:
// return a UTF-16 character from a 2-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x07 & (ord($utf8{0}) >> 2))
. chr((0xC0 & (ord($utf8{0}) << 6))
| (0x3F & ord($utf8{1})));
case 3:
// return a UTF-16 character from a 3-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr((0xF0 & (ord($utf8{0}) << 4))
| (0x0F & (ord($utf8{1}) >> 2)))
. chr((0xC0 & (ord($utf8{1}) << 6))
| (0x7F & ord($utf8{2})));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* encodes an arbitrary variable into JSON format
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encode($var)
{
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
case 'NULL':
return 'null';
case 'integer':
return (int) $var;
case 'double':
case 'float':
return (float) $var;
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = strlen($var);
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var{$c});
switch (true) {
case $ord_var_c == 0x08:
$ascii .= '\b';
break;
case $ord_var_c == 0x09:
$ascii .= '\t';
break;
case $ord_var_c == 0x0A:
$ascii .= '\n';
break;
case $ord_var_c == 0x0C:
$ascii .= '\f';
break;
case $ord_var_c == 0x0D:
$ascii .= '\r';
break;
case $ord_var_c == 0x22:
case $ord_var_c == 0x2F:
case $ord_var_c == 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var{$c};
break;
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var{$c};
break;
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF0) == 0xE0):
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF8) == 0xF0):
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFE) == 0xFC):
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}),
ord($var{$c + 5}));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
}
}
return '"'.$ascii.'"';
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
// treat as a JSON object
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
$properties = array_map(array($this, 'name_value'),
array_keys($var),
array_values($var));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
}
// treat it like a regular array
$elements = array_map(array($this, 'encode'), $var);
foreach($elements as $element) {
if(Services_JSON::isError($element)) {
return $element;
}
}
return '[' . join(',', $elements) . ']';
case 'object':
$vars = get_object_vars($var);
$properties = array_map(array($this, 'name_value'),
array_keys($vars),
array_values($vars));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
default:
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
}
}
/**
* array-walking function for use in generating JSON-formatted name-value pairs
*
* @param string $name name of key to use
* @param mixed $value reference to an array element to be encoded
*
* @return string JSON-formatted name-value pair, like '"name":value'
* @access private
*/
function name_value($name, $value)
{
$encoded_value = $this->encode($value);
if(Services_JSON::isError($encoded_value)) {
return $encoded_value;
}
return $this->encode(strval($name)) . ':' . $encoded_value;
}
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @param $str string string value to strip of comments and whitespace
*
* @return string string value stripped of comments and whitespace
* @access private
*/
function reduce_string($str)
{
$str = preg_replace(array(
// eliminate single line comments in '// ...' form
'#^\s*//(.+)$#m',
// eliminate multi-line comments in '/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us',
// eliminate multi-line comments in '/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
), '', $str);
// eliminate extraneous space
return trim($str);
}
/**
* decodes a JSON string into appropriate variable
*
* @param string $str JSON-formatted string
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to Services_JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
*/
function decode($str)
{
$str = $this->reduce_string($str);
switch (strtolower($str)) {
case 'true':
return true;
case 'false':
return false;
case 'null':
return null;
default:
$m = array();
if (is_numeric($str)) {
// Lookie-loo, it's a number
// This would work on its own, but I'm trying to be
// good about returning integers where appropriate:
// return (float)$str;
// Return float or int, as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-8 FORMAT
$delim = substr($str, 0, 1);
$chrs = substr($str, 1, -1);
$utf8 = '';
$strlen_chrs = strlen($chrs);
for ($c = 0; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = substr($chrs, $c, 2);
$ord_chrs_c = ord($chrs{$c});
switch (true) {
case $substr_chrs_c_2 == '\b':
$utf8 .= chr(0x08);
++$c;
break;
case $substr_chrs_c_2 == '\t':
$utf8 .= chr(0x09);
++$c;
break;
case $substr_chrs_c_2 == '\n':
$utf8 .= chr(0x0A);
++$c;
break;
case $substr_chrs_c_2 == '\f':
$utf8 .= chr(0x0C);
++$c;
break;
case $substr_chrs_c_2 == '\r':
$utf8 .= chr(0x0D);
++$c;
break;
case $substr_chrs_c_2 == '\\"':
case $substr_chrs_c_2 == '\\\'':
case $substr_chrs_c_2 == '\\\\':
case $substr_chrs_c_2 == '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs{++$c};
}
break;
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
// single, escaped unicode character
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
. chr(hexdec(substr($chrs, ($c + 4), 2)));
$utf8 .= $this->utf162utf8($utf16);
$c += 5;
break;
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
$utf8 .= $chrs{$c};
break;
case ($ord_chrs_c & 0xE0) == 0xC0:
// characters U-00000080 - U-000007FF, mask 110XXXXX
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 2);
++$c;
break;
case ($ord_chrs_c & 0xF0) == 0xE0:
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 3);
$c += 2;
break;
case ($ord_chrs_c & 0xF8) == 0xF0:
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 4);
$c += 3;
break;
case ($ord_chrs_c & 0xFC) == 0xF8:
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 5);
$c += 4;
break;
case ($ord_chrs_c & 0xFE) == 0xFC:
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 6);
$c += 5;
break;
}
}
return $utf8;
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
if ($str{0} == '[') {
$stk = array(SERVICES_JSON_IN_ARR);
$arr = array();
} else {
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = array();
} else {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = new stdClass();
}
}
array_push($stk, array('what' => SERVICES_JSON_SLICE,
'where' => 0,
'delim' => false));
$chrs = substr($str, 1, -1);
$chrs = $this->reduce_string($chrs);
if ($chrs == '') {
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} else {
return $obj;
}
}
//print("\nparsing {$chrs}\n");
$strlen_chrs = strlen($chrs);
for ($c = 0; $c <= $strlen_chrs; ++$c) {
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c, 2);
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = substr($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
if (reset($stk) == SERVICES_JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
array_push($arr, $this->decode($slice));
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name and set an
// element in an associative array,
// for now
$parts = array();
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[1];
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
}
}
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
//print("Found start of string at {$c}\n");
} elseif (($chrs{$c} == $top['delim']) &&
($top['what'] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '[') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '{') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
}
}
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
return $obj;
}
}
}
}
/**
* @todo Ultimately, this should just call PEAR::isError()
*/
function isError($data, $code = null)
{
if (class_exists('pear')) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
is_subclass_of($data, 'services_json_error'))) {
return true;
}
return false;
}
}
if (class_exists('PEAR_Error')) {
class Services_JSON_Error extends PEAR_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
}
}
} else {
/**
* @todo Ultimately, this class shall be descended from PEAR_Error
*/
class Services_JSON_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
}
}
}
?>
i think this is from PEAR, if installed it can be used instead single file above.
errorfun
5 Sep 2007, 12:17 AM
:(=D>B)/:)B)B)B)B)B)
I have some problem to post a datefield. I have 5 fields and the submit works just fine.
But is not working with datefield. Not submitting the value in the date field.
Firebug result
String Field:
id: 1
field: name
value: Test
Datefield:
id: 1
field: date
The value is not posted when is a datefield, I test with number and work just fine.
I know the error is in ' ' I try with value: '10-10-2007' and work fine, but without the ' ' is not working, anyone know how to resolve this?
Thank you.
waitMsg: 'Saving changes, please wait...',
url:'index.php?module=data',
params: {
id: ds.data.items[grid.row].id,
field: grid.field,
value: grid.value
},
success:function(form, action) {
Ext.MessageBox.alert('Success', ' Success' );
},
failure: function(form, action) {
Ext.MessageBox.alert('Warning', ' Error ' );
}
With the Sakalos help I resolve the problem.
format date field values before submit.
robin30
12 Sep 2007, 5:25 AM
i followed the example and changed it so it would work with my database.
everytime i change something and press enter i get this error:
syntax error
http://localhost/test/ext-all.js
Line 23
i tried the reply about json and added it at the top of the page after the <?php tag but still i get this error.
it will change it in the database but when i wanna use the Waitmessage. this hangs and it doesn't change it in my database.
hopefully someone can else me
nunez
14 Sep 2007, 6:11 AM
In my samples, If the waiting message hangs, is because the PHP didn't return anything.
try to do the transaction to a empty php file with just: {success:true}
waitMsg: 'Saving changes, please wait...',
failure: function(form, response) {
alert("Error");
},
success:function(form, response){
alert("Ok");
}
motshagen
17 Sep 2007, 4:20 AM
The new sample code works, it writes data to database and displays fine..
BUT i get an error.. Line: 24 1521 syntaxerror... If i anable the waitmsg it keeps waiting.. Could someone help?
JustinHoMi
19 Sep 2007, 7:02 PM
Thanks for the example... it helps a lot.
However, it's not always efficient to update the database on every change. Does anyone have an example of how to update the database with a submit button?
mjlecomte
20 Sep 2007, 5:06 PM
Thanks for posting this.
Some mistakes I made I'll post in case it helps someone else:
1. I forgot to upload the sql to my database at first (absent minded I know).
2. I am working on php < 5.2. I knew there was a json encode issue, but I included the encoding class outside of the method where it was being used, which meant I was trying to use the class out of scope. See below for the modification I made to the original post to get it to work:
function showData()
{
//query with data
$result = mysql_query("SELECT id, name FROM names");
$rows = mysql_num_rows($result);
while($rec = mysql_fetch_array($result))
$arr[] = $rec;
require_once("../examples/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
echo $_GET['callback'].'({"total":"'.$rows.'","results":'.$data.'})';
}
kayegil.hauan
22 Sep 2007, 5:20 AM
I use your example to update the MySQL database, and it works as long as you submit valid values in each cell.:)
But how how do I get feedback from the php file so I know if the data were actually saved or not?:s
My JavaScript code looks like this:
grid.on('afteredit', updateDB);
function updateDB(oGrid_event){
var rowID = oGrid_event.record.get("recordID")
gridForm.submit(
{
url:'index.php?action=updateGridCell&field='+oGrid_event.field+'&id='+rowID+'&value='+oGrid_event.value,
failure: function(form, action) {
alert('Oops! The changes were not saved!');
}
}
);
}
The string that is passed to my PHP file tells it to run function updateGridCell(), which evaluates the variables and updates the database.
In other words: What kind of data should my php function return in order to trigger the failure alert when something is wrong?
mjlecomte
22 Sep 2007, 8:03 AM
In other words: What kind of data should my php function return in order to trigger the failure alert when something is wrong?
I put the following in my php code and it triggered the failure method.
echo "{failure:true}";
pro1000may
11 Oct 2007, 1:26 AM
This is a 2.0 sample?
I use extjs2.0 and copy all code from this sample, but i have an error:
Ext.form.Form is not a constructor
buildGrid()index.htm (line 84)
init()index.htm (line 136)
fire()ext-all-debug.js (line 1495)
fireDocReady()ext-all-debug.js (line 1532)
chrome://firebug/content/blank.gifvar gridForm = new Ext.form.Form({});
my code.php (url always code.php?from=0&limit=100
$callback = $_GET['callback'];
$from = $_GET['from'];
$limit = $_GET['limit'];
$sql = "SELECT `id`, `name` FROM `test` LIMIT $from, $limit ";
$res = $db->query($sql);
$num = $db->num_rows($res);
$data = $db->process_table($res);
echo $callback.'({"total":"'.$num.'","results":'.json_encode($data).'})';
what`s wrong? :(
kushal
11 Oct 2007, 2:18 AM
I post the submit action to MyServlet,
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'http://localhost:8080/MyServlet',
params:{JSON_OBJECT:jsonData},
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
MyServlet work well but the action response is 'failure'.
How can I track the failure message.
Thank you very much
Hi,
1)
I'm trying to save all the edited records on grid(instead of one row at a time)) on one go.I've tried this with the example mentioned on this thread..
following is sample of my code...
========================================
var arrModifiedRecord=grid.store.getModifiedRecords();
var submitData ="";
var iCnt=arrModifiedRecord.length;
while(iCnt>=0)
{
iCnt--;
if(null != arrModifiedRecord[iCnt])
{
submitData += Ext.util.JSON.encode(arrModifiedRecord[iCnt].data) + ",";
}
}
submitData = submitData.substring(0,submitData.length-1);
submitData = Ext.util.JSON.decode(submitData);
var AjaxRequest= Ext.Ajax.request({
url: 'submitservlet.do',
method:'post',
params: submitData,
success:function(request)
{
alert('success')
}
});
========================================
However , i'm not able to save all the records at one go, rather it saves the last edited record...anyone..pls help me to know what is going wrong here..
Note: I've also tried submitting thru form ,(as explained in this thread), but only to get same result..:-/
alerting of 'submitData' shows array of objects having size = no. of records edited...
Oneway of doing this might be to call the Ajaxsubmit in loop for each modified record object..but I gues that won't be good idea from performance and design point of view!!!
2)
I'm using 'grid.store.commitChanges();' method to clear all the modifications indicators on grid , is there any way by which i can do this for a particular record row?..Actually I've code which submits one row of grid at a time..
(Sorry, this may not be matching with topic of this thread..)
Thnx..
I'll probably get corrected by one of the dev's for unnecessary code or something :p
but anyways here is a working version of this code for EXT 2.2
I used the ext 2 grid example coupled with this example:
html and php code are the same
.js code
/*
* Ext JS Library 2.0 Beta 1
* Copyright(c) 2006-2007, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
Ext.onReady(function(){
Ext.QuickTips.init();
function formatBoolean(value){
return value ? 'Yes' : 'No';
};
function formatDate(value){
return value ? value.dateFormat('M d, Y') : '';
};
// shorthand alias
var fm = Ext.form;
// the column model has information about grid columns
// dataIndex maps the column to the specific data field in
// the data store (created below)
var cm = new Ext.grid.ColumnModel([{
header: "Date",
dataIndex: 'date',
width: 100,
renderer: formatDate,
editor: new fm.DateField({
format: 'm/d/y',
minValue: '01/01/06'
})
},{
header: "Category",
dataIndex: 'category',
width: 100,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Detail",
dataIndex: 'detail',
width: 100,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Amount",
dataIndex: 'amount',
width: 100,
align: 'right',
renderer: 'usMoney',
editor: new fm.NumberField({
allowBlank: false,
allowNegative: false,
maxValue: 10000
})
},{
header: "Account",
dataIndex: 'light',
width: 100,
align: 'right',
editor: new Ext.form.ComboBox({
typeAhead: true,
triggerAction: 'all',
transform:'light',
lazyRender:true,
listClass: 'x-combo-list-small'
})
}
]);
// by default columns are sortable
cm.defaultSortable = true;
// this could be inline, but we want to define the Plant record
// type so we can add records dynamically
var expense = Ext.data.Record.create([
// the "name" below matches the tag name to read, except "availDate"
// which is mapped to the tag "availability"
{name: 'date', mapping: 'availability', type: 'date', dateFormat: 'm/d/Y'},
{name: 'category', type: 'string', mapping: 'Category'},
{name: 'detail', type: 'string', mapping: 'Description'},
{name: 'amount', type: 'float', mapping: 'Amount'},
{name: 'light', type: 'string', mapping: 'Account'} //columnmapping
]);
// create the Data Store
var ds = new Ext.data.Store({
//set the http-proxy (link to the php document)
proxy: new Ext.data.ScriptTagProxy({
url: 'update.php?ac=showData' //a function in your php-script must be activated when ac = showdata
}),
//set up the JsonReader
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'id'
},expense)
});
// create the editor grid
var grid = new Ext.grid.EditorGridPanel({
ds: ds,
cm: cm,
renderTo: 'editor-grid',
width:600,
height:300,
title:'Expenses',
frame:true,
tbar: [{
text: 'Add New Expense',
handler : function(){
var p = new expense({
date: new Date(),
category: 'None',
detail: 'None',
amount: 0,
light: 'None'
});
grid.stopEditing();
ds.insert(0, p);
grid.startEditing(0, 0);
}
}]
});
grid.on('afteredit', updateDB);
function updateDB(oGrid_event){
Ext.Ajax.request(
{
//waitMsg: 'Saving changes, please wait...',
url:'update.php?ac=saveData&field='+oGrid_event.field+'&row='+oGrid_event.row+'&value='+oGrid_event.value, //php function that saves the data
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
// trigger the data store load
ds.load();
});
Ext.grid.CheckColumn = function(config){
Ext.apply(this, config);
if(!this.id){
this.id = Ext.id();
}
this.renderer = this.renderer.createDelegate(this);
};
Ext.grid.CheckColumn.prototype ={
init : function(grid){
this.grid = grid;
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
}, this);
},
onMouseDown : function(e, t){
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]);
}
},
renderer : function(v, p, record){
p.css += ' x-grid3-check-col-td';
return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'"> </div>';
}
};
@pro1000may
Ext.form.Form is no longer around (Ext.form.FormPanel looks to be the replacement, but it works slightly different), my work around was just to use Ext.Ajax.request to submit the changes.
@ Others feel free to point out any problems or quicker code around, basically just got this code working and there are probably areas where it can be better...
I just need to figure out how to save the added data now as it replaces the first row of data due to it being allocated an id of 1 which replaces the current data with an id of 1.
Guess I'll just get it to count the number of rows and allocate an id #num of rows+1, will add that fix in when i do it.
*Fixed if by cheating slightly (update also needs to be changed, will post when it looks better):
grid.stopEditing();
ds.add(p);
var num=ds.getTotalCount();
grid.startEditing(num, 0);
Deni Setiadhi
2 Nov 2007, 9:40 PM
very helfull coding bro :D
Deni Setiadhi
2 Nov 2007, 10:35 PM
may be, all user can posting resume of this thread, so we can learning with clear program :)
pludikhu
5 Nov 2007, 1:54 AM
He piers
You saved my day! I wanted to convert to 2.0 too and was fighting several days with Ext.form.Form or Formpanel but couldn't get it to work.
(Obviously asking for help was out of the question because there are some wild beasts here who rather laugh at your face than help a newbie. Not at all the spirit of the open source community in these forums sometimes!
They seem to think that everyone does this for a living which in my case is not so.)
Anyway, your Ajax call gave me the break I needed.
Mind you however that these calls are asynchronous: the user can continue working in the grid whether or not the Ajax call ended (successfully) or not.
You can clearly demonstrate this if you send information back from the server by including a 'sleep(10)' in your code.
Also I wanted to point out that success or failure are fired when the http request succeeded or not. This has nothing to do with the success or failure of the server side code: e.g. if the update fails, Ajax success is being fired if there is no 404 (page not found) or 403 (insufficient access) or other http error.
So at least the success function should do something with the result of the action of the server.
I too borrowed some example code here and there to put together some proof of concept:
(not PHP code but I like the colours ;-))
function doJSON(stringData) {
try {
var jsonData = Ext.util.JSON.decode(stringData);
Ext.MessageBox.alert('Success', 'Decode of stringData OK<br />Sum = ' + jsonData.sum);
}
catch (err) {
Ext.MessageBox.alert('ERROR', 'Could not decode ' + stringData);
}
}
function updateDB(oGrid_event){
// Better use a unique (DB) id in your dataStore when fetching your data from the server!
// It doesn't have to be made visible to the user but if row order isn't fixed ...
id = ds.data.items[oGrid_event.row].id;
Ext.Ajax.request({
url: 'sample.php',
method: 'POST',
params: {
ac: 'saveData',
id: id,
field: oGrid_event.field,
value: oGrid_event.value
},
success: function ( result, request) {
// This is the simple way to get feedback from the server
// Ext.MessageBox.alert('Success', 'Data returned from the server: '+ result.responseText);
// This is the proper way
doJSON(result.responseText);
},
failure: function ( result, request) {
Ext.MessageBox.alert('Failed');
}
// Or one could use only one callback (instead of success/failure)
// callback: function (options, success, result) {
// if (success) {
// Ext.MessageBox.alert('OK',result.responseText);
// var json = Ext.util.JSON.decode(result.responseText);
// Ext.MessageBox.alert('OK',json.sum);
// 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('Ajax call failed',result.responseText);
// }
// }
});
}
Server side:
[PHP]
// Db login etc.
// Using POST for saveData
if(isset($_GET['ac']) && $_GET['ac']=='showData')
showData();
elseif(isset($_POST['ac']) && $_POST['ac']=='saveData')
saveData($_POST['field'], $_POST['id'], $_POST['value']);
function showData()
{
//query with data
$result = mysql_query("SELECT id, name FROM names");
$rows = mysql_num_rows($result);
// Use MYSQL_ASSOC otherwise you sent too much useless data to the client
while($rec = mysql_fetch_array($result, MYSQL_ASSOC)) {
// If you have special characters like
Deni Setiadhi
6 Nov 2007, 2:08 AM
newbie ask :
what should i do if this condition true
Ext.MessageBox.alert('ERROR', 'Could not decode ' + stringData);
http://indoupload.net/files/7776/error_extjs_grid.jpg
btw PHP engine version in my computer : 5.1.6
Deni Setiadhi
6 Nov 2007, 2:58 AM
finally success bro !!! :):)
thanks for all
JasonMichael
9 Nov 2007, 6:49 AM
Successful here too, after 4 hours of messing around with it... ScriptTagProxy never works for me.... I keep forgetting to just change it over to HttpProxy and life is alot better!
mjlecomte
10 Nov 2007, 11:35 AM
Successful here too, after 4 hours of messing around with it... ScriptTagProxy never works for me.... I keep forgetting to just change it over to HttpProxy and life is alot better!
I originally had problems with that as well. Check where the data is being passed, it might be in $_POST when you're checking $_GET. You might also do an if statement to check both automatically.
Oh, and the other part that got me was that for ScriptTagProxy you have to 'wrap the data object with a call to a callback function'. The name of the callback function is a passed as a a parameter by the ScriptTagProxy. The docs say HttpProxy is preferable anyway, maybe for that reason among other reasons.
Pytte
15 Nov 2007, 2:12 PM
still dont have a working 2.0 rc1 example :/ .. i get wierdo errors now ..
C has no properties
[Break on this error] Ext.form.ComboBox=Ext.extend(Ext.form.TriggerField,{defaultAutoCreate:{tag:"inpu...
and this is in ext-all.js .. ?
juzy
16 Nov 2007, 12:26 PM
still dont have a working 2.0 rc1 example :/ .. i get wierdo errors now ..
C has no properties
[Break on this error] Ext.form.ComboBox=Ext.extend(Ext.form.TriggerField,{defaultAutoCreate:{tag:"inpu...
and this is in ext-all.js .. ?
Hi!
Probably, in html you do not have such text:
<select name="light" id="light" style="display: none;">
<option value="Shade">Shade</option>
<option value="Mostly Shady">Mostly Shady</option>
<option value="Sun or Shade">Sun or Shade</option>
<option value="Mostly Sunny">Mostly Sunny</option>
<option value="Sunny">Sunny</option>
</select>
Juzy
Pytte
16 Nov 2007, 1:05 PM
yea seems like its not taking anything from the database.. hmm
Pytte
16 Nov 2007, 1:41 PM
yea obviously .. anyone have a database sample of the example piers is doing?
I just want to get something working before i start fiddling around.
mjlecomte
17 Nov 2007, 8:14 AM
I posted another example of using php/mysql here (http://extjs.com/forum/showthread.php?p=88050#post88050). It has a complete working .zip that should plug and play pretty much. I thought about posting in the Examples forum (http://extjs.com/forum/forumdisplay.php?f=7), but my example is specific to 2.0 so I just posted in the 2.0 forum (one of the moderators can move it if they think appropriate).
teapear
26 Nov 2007, 6:26 PM
not working!!!
calavera
6 Jan 2008, 2:18 PM
Updated post:
I made an update for this example. To make sure all new readers see this instead of the post before, I edit it here.
The new WORKING example is as followed:
The js file:
var GridUI = function() {
//enable Quicktips
Ext.QuickTips.init();
//set vars
var ds; //datastore for grid
var cm; //columnModel
var grid; //component
var fm = Ext.form, Ed = Ext.grid.GridEditor; // shorthand alias
//create the datastores
function setupDataSource() {
//create the Data Store for the grid
ds = new Ext.data.Store({
//set the http-proxy (link to the php document)
proxy: new Ext.data.ScriptTagProxy({
url: 'sample.php?ac=showData' //a function in your php-script must be activated when ac = showdata
}),
//set up the JsonReader
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'id'
},[
{name: 'name', type: 'string', mapping: 'name'} //columnmapping
])
});
//load datastores
ds.load();
}
//create the columnmodel
function getColumnModel() {
cm = new Ext.grid.ColumnModel([{
header: "Names",
dataIndex: 'name',
width: 150,
editor: new Ed(new fm.TextField({
allowBlank: true,
maxLength: 50
}))
}]);
//set the default for sorting the columns
cm.defaultSortable = false;
return cm;
}
//create the grid
function buildGrid() {
//create the form
var gridForm = new Ext.form.Form({});
//create the grid
var grid = new Ext.grid.EditorGrid('editor-grid', {
ds: ds,
cm: getColumnModel(),
enableColLock:false,
selModel: new Ext.grid.RowSelectionModel({singleSelect:true})
});
//set the layout for the grid
var layout = Ext.BorderLayout.create({
center: {
margins:{left:3,top:3,right:3,bottom:3},
panels: [new Ext.GridPanel(grid)]
}
}, 'grid-panel');
//render the grid
grid.render();
//set the header
var gridHead = grid.getView().getHeaderPanel(true);
var tb = new Ext.Toolbar(gridHead, [{}]);
//activate function updateDB when a cell is edited
grid.on('afteredit', updateDB);
function updateDB(oGrid_event){
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'sample.php?ac=saveData&field='+oGrid_event.field+'&row='+oGrid_event.row+'&value='+oGrid_event.value, //php function that saves the data
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
//render form
gridForm.render('editGrid');
}
return {
//the init
init : function() {
setupDataSource();
buildGrid();
},
getDataSource: function() {
return ds;
}
}
}();
Ext.onReady(GridUI.init, GridUI, true);
The php-file:
<?php
//make database connection
mysql_connect("localhost", "YOUR USERNAME", "YOUR PASSWORD") or
die("Could not connect: " . mysql_error());
mysql_select_db("YOUR DATABASE");
if(isset($_GET['ac']) && $_GET['ac']=='showData')
showData();
elseif(isset($_GET['ac']) && $_GET['ac']=='saveData')
saveData($_GET['field'], $_GET['row'], $_GET['value']);
function showData()
{
//query with data
$result = mysql_query("SELECT id, name FROM names");
$rows = mysql_num_rows($result);
while($rec = mysql_fetch_array($result))
$arr[] = $rec;
echo $_GET['callback'].'({"total":"'.$rows.'","results":'.json_encode($arr).'})';
}
function saveData($field, $row, $value)
{
/*
* field: the dataIndex which is being updated
* $row: the row that is being updated
* $value: the new value
*/
//look which record is being updated
$result = mysql_query("SELECT id FROM names");
while($rec = mysql_fetch_array($result))
$id[] = $rec['id'];
//NOTE: this isn't the best way to save your data!
//What I do is look in the database and put all the ID's in an array.
//Then I know that $row is the right array index.
//But when you change the order of the records for example, this isn't enough to know the row
//However, this example works :)
//save data to database
if($field=='name') //the field name is being updated
$result = mysql_query("UPDATE `names` SET `name` = '$value' WHERE `id`='$id[$row]';");
}
?>
The html-file:
<html>
<head>
<title>Sample of a grid</title>
<script language="JavaScript" type="text/javascript" src="adapter/ext/ext-base.js"></script>
<script language="JavaScript" type="text/javascript" src="ext-all.js"></script>
<script language="JavaScript" type="text/javascript" src="sample.js"></script>
<link rel="stylesheet" type="text/css" href="resources/css/ext-all.css" media="screen" />
</head>
<body>
<div id="grid-panel" style="width:1024px;height:668px;">
<div id="editor-grid"></div>
<div id="editGrid">
</div>
</div>
</body>
</html>
The database:
--
-- Table structure for table `names`
--
CREATE TABLE `names` (
`id` int(8) unsigned NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
--
-- Dumping data for table `names`
--
INSERT INTO `names` (`id`, `name`) VALUES
(1, 'Testname'),
(2, 'Testname2'),
(3, 'Testname3'),
(4, 'Testname4');
You acces the grid by going to the sample.html page!
NOTE: Don't forget to set your database username and password in the php-file and include ext-base.js and ext-all.js!!
First post:
In my search on this forum to read a DataStore, display the data in a grid, edit the cells in a grid and then update the database using php and mysql I couldn't find a full working sample. So, now I found out how to do it, I want to share it with you all.
I made the example as easy as possible. Because I'm a new EXT user, there are probably better known ways to update your database, but the example I made must work after a little editting (you have to make your queries for selecting data yourself!) and will hopefully help all the others I saw looking for help on this.
With help of other posts from users (thanks all) I came to the following code.
Create your grid (to make it easy, I made one column): sample.js
var GridUI = function() {
//enable Quicktips
Ext.QuickTips.init();
//set vars
var ds; //datastore for grid
var cm; //columnModel
var grid; //component
var fm = Ext.form, Ed = Ext.grid.GridEditor; // shorthand alias
//create the datastores
function setupDataSource() {
//create the Data Store for the grid
ds = new Ext.data.Store({
//set the http-proxy (link to the php document)
proxy: new Ext.data.ScriptTagProxy({
url: 'index.php?ac=showdata' //a function in your php-script must be activated when ac = showdata
}),
//set up the JsonReader
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'id'
},
{name: test, type: 'string', mapping: 'test'} //columnmapping
)
});
//load datastores
ds.load();
}
//create the columnmodel
function getColumnModel() {
cm = new Ext.grid.ColumnModel([{
header: "Testcolumn",
dataIndex: 'test',
//width: 150,
editor: false
}]);
//set the default for sorting the columns
cm.defaultSortable = false;
return cm;
}
//create the grid
function buildGrid() {
//create the form
var gridForm = new Ext.form.Form({});
//create the grid
var grid = new Ext.grid.EditorGrid('editor-grid', {
ds: ds,
cm: getColumnModel(),
enableColLock:false,
selModel: new Ext.grid.RowSelectionModel({singleSelect:true})
});
//set the layout for the grid
var layout = Ext.BorderLayout.create({
center: {
margins:{left:3,top:3,right:3,bottom:3},
panels: [new Ext.GridPanel(grid)]
}
}, 'grid-panel');
//render the grid
grid.render();
//set the header
var gridHead = grid.getView().getHeaderPanel(true);
var tb = new Ext.Toolbar(gridHead, [{}]);
//activate function updateDB when a cell is edited
grid.on('afteredit', updateDB);
function updateDB(oGrid_event){
jsonData = "[";
for(i=0;i<ds.getCount();i++) {
record = ds.getAt(i);
jsonData += Ext.util.JSON.encode(record.data) + ",";
}
jsonData = jsonData.substring(0,jsonData.length-1) + "]";
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'index.php?ac=saveData', //php function that saves the data
params:{data:jsonData},
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
//render form
gridForm.render('editGrid');
}
return {
//the init
init : function() {
setupDataSource();
buildGrid();
},
getDataSource: function() {
return ds;
}
}
}();
Ext.onReady(GridUI.init, GridUI, true);
The HTML-code: index.tpl
<html>
<head>
<script src="ext-all.js" type="text/javascript"></script>
<script src="adapter/ext/ext-base.js" type="text/javascript"></script>
<script src="sample.js" type="text/javascript"></script>
<link href="resources/css/ext-all.css" media="screen" rel="Stylesheet" type="text/css" />
</head>
<body>
<div id="grid-panel" style="width:1024px;height:668px;">
<div id="editor-grid"></div>
<div id="editGrid">
</div>
</div>
</body>
</html>
The php code (index.php):
function showData()
{
//make your query here that selects all your data for the grid
//you have to modify the $res and fetch yourself to make the query succesfull
$res = $this->dbi->query('your query here');
while($obj =& $this->dbi->fetch())
{
$arr[] = $obj;
}
//encode your data for the jsonreader
echo $_GET['callback'].'({"total":"'.$rows.'","results":'.json_encode($arr).'})';
}
function saveData()
{
$data = json_decode(stripslashes($_POST['data']));
//make here a query that updates the database
}
Remember you still have to do some work yourself: make the database queries and modify the ColumnModel and DataStore so it matches your data.
$data in saveData() is an 2D array, which you have to read by a foreach loop and put it in the database. Use echo var_dump($data); to see how the array is build!
Note that in this example the whole grid is submitted once you edit a sell, so if you have a 100+ record grid it becomes slower and slower.
When I find out how, I post an example in this topic how to update only one cell in the database after editing.
Good luck!
This new method just doesn't work for me. I access sample.html and nothing happens, nothing appears.Just the title of the page in my browser but no data ...What can it be ? Thank you!
mjlecomte
6 Jan 2008, 4:19 PM
This new method just doesn't work for me. I access sample.html and nothing happens, nothing appears.Just the title of the page in my browser but no data ...What can it be ? Thank you!
Did you try this in firefox? If no, try it there. Once you've tried it in firefox, does firebug throw any errors?
There's another similar example (http://extjs.com/forum/showthread.php?t=18435) you might also want to check out.
calavera
6 Jan 2008, 4:44 PM
Did you try this in firefox? If no, try it there. Once you've tried it in firefox, does firebug throw any errors?
There's another similar example (http://extjs.com/forum/showthread.php?t=18435) you might also want to check out.
I always use Firefox. I gave it a try with firebug. It seems that there's an error on sample.js. I have a print screen with firebug's output. Also, the other example you posted is not working for me, lots of firebug errors. Please help.Thank you !
mjlecomte
7 Jan 2008, 4:54 AM
What version of ext are you using? I think this code is for ext1.
The other example I pointed you to works with ext2.
calavera
7 Jan 2008, 8:37 AM
I use version 2. Maybe that's the problem but the second example doesn't work either :( I'm so sad
mjlecomte
8 Jan 2008, 4:46 AM
I think the other example works out of the box. If you're having problems you should probably be more specific if you'd like assistance....just saying something "doesn't work" isn't very helpful. If you have problems with the other example you should probably post your problems in that thread, not this one.
Have you downloaded ext and have other examples, ie. the samples working? Check the faq page also, make sure you've put your files in an appropriate location so it can find the required resources (js, css, etc.).
calavera
8 Jan 2008, 10:53 AM
Ok, sorry for being so short but I posted in a rush. As I do now too. I will recheck both examples and post more details into specific thread. Thank you!
bmw-m-power
8 Mar 2008, 3:35 AM
hi, i'm new to ext and i copied your example. the problem is that my firefox error console give me an error: Error: A has no properties
Source File: http://localhost/my_site/admin_panel/jscripts/extjs/ext-all.js ("Ext.grid.GridView=function(A){...}")
Line: 142
I'm using Ext 2.0.2 and php 5.2.1. I also received 2 errors about the form and grid objects but i resolved them
var GridUI = function() {
//enable Quicktips
Ext.QuickTips.init();
//set vars
var ds; //datastore for grid
var cm; //columnModel
var grid; //component
var fm = Ext.form, Ed = Ext.grid.GridEditor; // shorthand alias
//create the datastores
function setupDataSource() {
//create the Data Store for the grid
ds = new Ext.data.Store({
//set the http-proxy (link to the php document)
proxy: new Ext.data.ScriptTagProxy({
url: 'includes/test.php?ac=showData' //a function in your php-script must be activated when ac = showdata
}),
//set up the JsonReader
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'id'
},[
{alias: 'alias', type: 'string', mapping: 'alias'} //columnmapping
])
});
//load datastores
ds.load();
}
//create the columnmodel
function getColumnModel() {
cm = new Ext.grid.ColumnModel([{
header: "Pages",
dataIndex: 'alias',
width: 150,
editor: new Ed(new fm.TextField({
allowBlank: true,
maxLength: 50
}))
}]);
//set the default for sorting the columns
cm.defaultSortable = false;
return cm;
}
//create the grid
function buildGrid() {
//create the form
var gridForm = new Ext.form.FormPanel({});
//create the grid
var grid = new Ext.grid.EditorGridPanel('editor-grid', {
ds: ds,
cm: getColumnModel(),
enableColLock:false,
selModel: new Ext.grid.RowSelectionModel({singleSelect:true})
});
//set the layout for the grid
var layout = Ext.BorderLayout.create({
center: {
margins:{left:3,top:3,right:3,bottom:3},
panels: [new Ext.GridPanel(grid)]
}
}, 'grid-panel');
//render the grid
grid.render();
//set the header
var gridHead = grid.getView().getHeaderPanel(true);
var tb = new Ext.Toolbar(gridHead, [{}]);
//activate function updateDB when a cell is edited
grid.on('afteredit', updateDB);
/*function updateDB(oGrid_event){
gridForm.submit(
{
//waitMsg: 'Saving changes, please wait...',
url:'inlcludes/test.php?ac=saveData&field='+oGrid_event.field+'&row='+oGrid_event.row+'&value='+oGrid_event.value, //php function that saves the data
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}*/
function updateDB(grid, e){
id = ds.data.items[grid.row].id;
gridForm.submit(
{
url: 'includes/test.php?ac=saveData',
params: {
id: id,
field: grid.field,
value: grid.value
},
success:function(form, action) {
alert('Congrats! Your changes were saved!!!!');
},
failure: function(form, action) {
alert('Oops the delete did not work out too well!');
}
}
);
}
//render form
gridForm.render('editGrid');
}
return {
//the init
init : function() {
setupDataSource();
buildGrid();
},
getDataSource: function() {
return ds;
}
}
}();
Ext.onReady(GridUI.init, GridUI, true);
the html:
{if:ismsg}<div class="message"><p>{mesaj:h}</p></div>{end:}
{if:islist}
<div class="mainTitle">
<p style="float:left;">{section_title}</p>
<p style="text-align:right;font-size:13px;float:right;">
<a href="index.php?page=1&act=add"><img src="images/new.png" border="0" alt="New" title="New" /></a>
<a href="#">
<img src="images/trash.png" border="0" alt="Delete" title="Delete" onclick="alert('Vreti sa stergeti?');document.listForm.submit();" />
</a>
<!--<img src="images/apply.png" border="0" />
<img src="images/cancel.png" border="0" />-->
</p>
</div>
<div id="grid-panel">
<div id="editor-grid"></div>
<div id="editGrid"></div>
</div>
{else:}
<div class="mainTitle">
<p style="float:left;">{section_title} » {title}</p>
<p style="text-align:right;font-size:13px;float:right;">
<img src="images/save.png" border="0" alt="Save" title="Save" />
<img src="images/apply.png" border="0" alt="Apply" title="Apply" />
<a href="index.php?page=1"><img src="images/cancel.png" border="0" alt="Cancel" title="Cancel" /></a>
</p>
</div>
{form:h}
{end:}
mjlecomte
8 Mar 2008, 10:38 AM
This thread is for a grid that works with ext1. You might want to check the example in my signature which works out of box for ext2.
sandy
17 Mar 2008, 10:55 PM
this is my jsp page
---------------------
Account[] accounts = new Account[hits.length()];
for(int i = 0;i<hits.length();i++){
account=new Account();
Document doc = hits.doc(i);
account.setAccountId( doc.get("accountId"));
account.setAccountNo( doc.get("accountNo"));
account.setOcaId( doc.get("ocaId"));
account.setCCN( doc.get("CCN"));
accounts[i] = account;
}
//Echo $_GET['callback'].'({"total":"'.$hits.length().'","results":'.json_encode($accounts).'})';
//above i had all the values in the account object array
how to convert the above line code to write in jsp.please help me..
and this is my paging.js
-------------------------
/*
* Ext JS Library 2.0.2
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
Ext.onReady(function(){
// create the Data Store
var store = new Ext.data.Store({
// load using ScriptTagProxy script tags for cross domain, if the data in on the same domain as
// this page, an HttpProxy would be better
proxy: new Ext.data.ScriptTagProxy({
url: 'pagination.jsp'
}),
// create reader that reads the Topic records
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'accountId',
fields: [
{name: 'accountNo', mapping: 'accountNo'},
{name: 'ocaId', mapping: 'ocaId'},
{name: 'CCN', mapping: 'CCN'}
]
}),
// turn on remote sorting
remoteSort: true
});
// store.setDefaultSort('lastpost', 'desc');
// the column model has information about grid columns
// dataIndex maps the column to the specific data field in
// the data store
var cm = new Ext.grid.ColumnModel([{
id: 'accountNo', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
header: "AccountNo",
dataIndex: 'accountNo',
width: 420
},{
header: "OCAID",
dataIndex: 'ocaId',
width: 100
//hidden: true
},{
header: "CCN",
dataIndex: 'CCN',
width: 70,
align: 'right'
}]);
// by default columns are sortable
cm.defaultSortable = true;
var grid = new Ext.grid.GridPanel({
el:'topic-grid',
width:500,
height:300,
title:'Pagination',
store: store,
cm: cm,
trackMouseOver:false,
sm: new Ext.grid.RowSelectionModel({selectRow:Ext.emptyFn}),
loadMask: true,
viewConfig: {
forceFit:true,
enableRowBody:true,
showPreview:true,
getRowClass : function(record, rowIndex, p, store){
if(this.showPreview){
p.body = '<p>'+record.data.excerpt+'</p>';
return 'x-grid3-row-expanded';
}
return 'x-grid3-row-collapsed';
}
},
bbar: new Ext.PagingToolbar({
pageSize: 25,
store: store,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No results to display",
items:[
'-', {
pressed: true,
enableToggle:true,
text: 'Show Preview',
cls: 'x-btn-text-icon details',
toggleHandler: toggleDetails
}]
})
});
// render it
grid.render();
// trigger the data store load
store.load({params:{start:0, limit:25}});
function toggleDetails(btn, pressed){
var view = grid.getView();
view.showPreview = pressed;
view.refresh();
}
});
mjlecomte
18 Mar 2008, 4:08 AM
Suggestions:
post code inside code tags
start your own thread for this subject
your problem is server side, you need to query your database according to the paging parameters that are sent by extjs to your server side script
A search of the forums, including the FAQ, may be helpful for you, and is highly encouraged before posting questions
zitadeveloper
19 Mar 2008, 4:44 AM
"id = ds.data.items[oGrid_event.row].id; "
this line is saving me a lot of work. Thanks alot pludikhu (http://extjs.com/forum/member.php?u=15112)!!
dfarias
13 Apr 2008, 11:22 AM
Please where you could download your full example editor-grid using php and mysql
That copy of your post, but gives me the error siquiente
This.recordType.prototype has no properties
[Break on this error] Ext.data.Store = function () (this.data = new Ext.util.MixedCollection (false); this.da. ..
Thanks
mjlecomte
13 Apr 2008, 11:58 AM
Suggest you look at more recent examples. There are 2 in the tutorials section for this. http://extjs.com/learn/w/index.php?title=Tutorials§ion=10#Grid
tassz
15 May 2008, 5:59 AM
Hi, I'm new to extjs and working through grid examples/php/mysql.. having a probelm with mysql_connect -when I run code nothing is displayed in grid. Can you help?
mysql_connect("localhost", "root", "pwd") or
die("Could not connect: " . mysql_error());
mysql_select_db("tutorial");
Tassz
mjlecomte
15 May 2008, 8:39 AM
Which example are you working with, this thread, the one in my signature or there's yet another in the Tutorials section? Also note the FAQ in my signature as well.
tassz
16 May 2008, 8:36 AM
Hi
Thanks for your reply....
Is it possible to send me a link to: examples of a mulitselect combobox?
Thanks
Tassz
mjlecomte
16 May 2008, 9:32 AM
Look for LOV combo on www.extjs.eu. Several other examples as well. Try the http://extjs.com/learn/Ext_Extensions as well.
tassz
16 May 2008, 9:37 AM
Hi mjlecomte
Thanks for the links..
pafciu17
8 Jun 2008, 12:49 PM
Hi, I am quite new in using Ext. I work with that example a bit and find it very good.
But I have question. I want to add listener to editor of combobox, and I want do some action on record when combobox is change, but i dont know how to get information about which record is changing into that function. Mayby somone know?
{
dataIndex: 'industryID',
header: "Industry",
sortable: false,
width: 23,
//create a dropdown based on server side data (from db)
editor: new Ext.form.ComboBox({
//if we enable typeAhead it will be querying database
//so we may not want typeahead consuming resources
typeAhead: false,
triggerAction: 'all',
//By enabling lazyRender this prevents the combo box
//from rendering until requested
lazyRender: true,//should always be true for editor
//where to get the data for our combobox
store: dsIndustry,
//the underlying data field name to bind to this
//ComboBox (defaults to undefined if mode = 'remote'
//or 'text' if transforming a select)
displayField: 'industryName',
//the underlying value field name to bind to this
//ComboBox
valueField: 'industryID',
listeners: {
change : function() {
//some instructions
}
}
}),
renderer: //custom rendering specified inline
function(data) {
record = dsIndustry.getById(data);
if(record) {
return record.data.industryName;
} else {
//return data;
return 'missing data';
}
}
});
parag.r@iworktech.com
23 Jul 2008, 6:24 AM
HI:
I have tried running this example but it is not working at my side. In IE explorer it shows nothing.
When I clicks on Done warning message it shows "Object Expected".
I am not able to find out where the problem is? Could you please help me out to find it?
tassz
23 Jul 2008, 6:30 AM
Have you used Firefox (2.0 or 3.0) instead using of IE7, which is problematic....
Tassz:)
parag.r@iworktech.com
23 Jul 2008, 6:36 AM
Hi:
I tried it using firefox. The message is not comming i.e. Object Expected.
But the screen is comming as blank.
I mean no output.............?
tassz
23 Jul 2008, 6:40 AM
Hi
what tutorials are you working from?
and can you send me a link?
Tassz:)
parag.r@iworktech.com
23 Jul 2008, 6:46 AM
http://extjs.com/forum/showthread.php?t=10002 this is the link I am referring to connect to mysql database and show data in grid using EXT JS.
I have followed all the steps as mentioned in the post but still not able run it fine.
tassz
23 Jul 2008, 6:57 AM
Hi
I also had problem with Ext js when using it with Coldfusion 8/Mysql 5.0...
Instead I've moved away from ext js, and found Coldfusion/Dhtmlx more reliable and they offer better support and examples...
Coldfusion is a growing technolgy for webbased development, and the forums are good (type: houseoffusion in browser serach engine)
The link for ColdFusion is:http://www.adobe.com/support/coldfusion/downloads.html
The link for dhtmlx is: http://www.dhtmlx.com/
Hope that this is of some help!
Tassz:)
tassz
23 Jul 2008, 7:04 AM
Finally in your code I can't see where you have assigned the database name - the same name of your mysql db...
I also got problems at this stage, that's why I changed to Coldfusion & dhtmlx gridt Definitions */ @font-face {font-family:Verdana; panose-1:2 11 6 4 3 5 4 4 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1593833729 1073750107 16 0 415 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:Verdana; mso-fareast-font-family:"Times New Roman"; mso-bidi-font-family:"Times New Roman"; mso-ansi-language:EN-GB;} code {font-family:"Courier New"; mso-ascii-font-family:"Courier New"; mso-fareast-font-family:"Times New Roman"; mso-hansi-font-family:"Courier New"; mso-bidi-font-family:"Courier New";} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} --> ....
Tassz
parag.r@iworktech.com
23 Jul 2008, 9:24 PM
But I have to go with Ext JS.
Thanks for your feedbacks.
tassz
24 Jul 2008, 12:37 AM
Hi ya
Just want to know why do you have to go with ext js?
there is an array of development tools out there, as some are better than others....
Tassz:)
irfander
11 Sep 2008, 7:37 PM
Hello,
I have an error like this:
Ext.form is not a constructor
on the line:
chrome://firebug/content/blank.gif var gridForm = new Ext.form.Form({});
Please give me further help, thanks
calavera
12 Sep 2008, 6:41 AM
Hello. Please check your heading call to extjs base files. The path might be wrong or not at all.
Hope that helps.
Hello,
I have an error like this:
Ext.form is not a constructor
on the line:
chrome://firebug/content/blank.gif var gridForm = new Ext.form.Form({});
Please give me further help, thanks
mjlecomte
12 Sep 2008, 8:26 AM
Why are you asking a form question in a thread about grids? I haven't looked at the base code for this example, so you might want to quote your reference with more code so someone knows what you are talking about.
Anyway, I don't know what version you are using but Ext 2.2 doesn't appear to have Ext.form.form(). You might have Ext.form.BasicForm or Ext.form.FormPanel, but you have not provided enough code to give more meaningful help.
igorshmigor
12 Sep 2008, 1:03 PM
I get the same error message.
I use firefox 3.0 with ExtJS 2.2 and test the code locally.
The web developer toolbar tells me:
Ext.form.Form() is not a constructor
http://localhost/extjs/sample.js line 110
It's the first line of the buildGruid() function
var gridForm = new Ext.form.Form({});
I've checked the paths to the JavaScripts, they are all correct.
Both, adapter/ext/ext-base.js and ext-all.js are loaded.
mjlecomte
12 Sep 2008, 4:12 PM
Ok, I looked at the introductory code for this thread.
This code shown in this thread is for Ext 1, not Ext 2. You can not use this code for Ext 2. Go to the tutorials section in the wiki and look at tutorials applicable for Ext 2.
igorshmigor
14 Sep 2008, 4:08 AM
This code shown in this thread is for Ext 1, not Ext 2. You can not use this code for Ext 2.
I didn't realize, sorry. Must have missed that part.
Your own thread (http://extjs.com/forum/showthread.php?t=18435) seems quite useful, I'll have a look at that, thanks.
Surinder singh
28 May 2009, 12:19 PM
Here is the example grid , it may help you.
lm.moreira
15 Jul 2009, 12:08 PM
I have made the first code (samples.*), and got these javascript error
Error: Ext.form.Form is not a constructor
Source File: http://localhost/grid-mysql-edit/sample.js
Line: 109
Is necessary the application being on the same page of the ext-path..
My .html
<html>
<head>
<title>Sample of a grid</title>
<script language="JavaScript" type="text/javascript" src="../ext-2.2.1/adapter/ext/ext-base.js"></script>
<script language="JavaScript" type="text/javascript" src="../ext-2.2.1/ext-all.js"></script>
<script language="JavaScript" type="text/javascript" src="sample.js"></script>
<link rel="stylesheet" type="text/css" href="../ext-2.2.1/resources/css/ext-all.css" media="screen" />
</head>
<body>
<div id="grid-panel" style="width:1024px;height:668px;">
<div id="editor-grid"></div>
<div id="editGrid">
</div>
</div>
</body>
</html>
calavera
15 Jul 2009, 10:00 PM
I have made the first code (samples.*), and got these javascript error
Error: Ext.form.Form is not a constructor
Source File: http://localhost/grid-mysql-edit/sample.js
Line: 109
Is necessary the application being on the same page of the ext-path..
My .html
<html>
<head>
<title>Sample of a grid</title>
<script language="JavaScript" type="text/javascript" src="../ext-2.2.1/adapter/ext/ext-base.js"></script>
<script language="JavaScript" type="text/javascript" src="../ext-2.2.1/ext-all.js"></script>
<script language="JavaScript" type="text/javascript" src="sample.js"></script>
<link rel="stylesheet" type="text/css" href="../ext-2.2.1/resources/css/ext-all.css" media="screen" />
</head>
<body>
<div id="grid-panel" style="width:1024px;height:668px;">
<div id="editor-grid"></div>
<div id="editGrid">
</div>
</div>
</body>
</html>
As it was stated a few posts back, this code is for Ext version 1 and you're using it with Ext ver 2. You can use this thread (http://extjs.com/forum/showthread.php?t=18435) for Ext ver 2.
uzzal.masud
7 Apr 2010, 11:43 PM
it doesn't work.
shaynl
11 May 2010, 1:43 AM
is this still working with Ext Js 3.x?
mayurid
1 Jun 2010, 11:15 PM
m following the same code u posted and made changes to the paths of header files i e ext-all.js and ext-base.js,
m using 3.2.1 it gives the following error in firefox firebug ext.form.Form is not a constructor.... help me with some code or more information
Powered by vBulletin™ Version 4.0.3 Copyright © 2010 vBulletin Solutions, Inc. All rights reserved.