Ext JS - Learning Center

Tutorial:ExtJs CodeIgniter

From Ext JS - Learn

Jump to: navigation, search
Summary: Binding ExtJS Grid with MySQL using CodeIgniter
Author: Romer Ventura
Published: March 13 2008
Ext Version: 2.0
Languages: en.png English

Contents

About

HOWTO - CodeIgniter and ExtJs Grid.

First of all i am no expert on neither of them, but just know enough to get what i need from them. If you dont agree with the practices here, please feel free to provide constructive feedback.

Now i will assume you have knowledge and experience with CodeIgniter since i will only be posting the functions that are used on this example. I wont be defining what a controller, model or view is since you should know if you have worked with CI.

For a more detailed HOWTO on PHP+MySQL+ExtJs please check this: http://extjs.com/forum/showthread.php?t=18435

What is "HOWTO - CodeIgniter and ExtJs Grid."? It is an illustration on how to use the nice and pretty ExtJs Grid with CodeIgniter which at the same time will be retrieving the data from MySQL.

CI Model

So we have the model: with my model i only get the data from MySQL that i want to use with my grid. The function i used looks like this:

function getBoards()
{
    $this->db->select('WOrder, PartNumber, WOPartQuantity, PartPriority, 
                        WODateIn, WODateOut, PartState, PartStatus, PartLocation');
    $this->db->from('WorkOrder');
        $this->db->join('PartNumber', 'WorkOrder.PartNumberID = PartNumber.PartNumberID');
        $this->db->join('PartState', 'PartState.PartStateID = WorkOrder.PartStateID');
        $this->db->join('PartStatus', 'PartStatus.PartStatusID = WorkOrder.PartStatusID');
        $this->db->join('PartPriority', 'PartPriority.PartPriorityID = WorkOrder.PartPriorityID');
        $this->db->join('PartLocation', 'PartLocation.PartLocationID = WorkOrder.PartLocationID');
    $this->db->limit(15);
 
    $lBoards = $this->db->get();
    return $lBoards;
}

Above we have 3 things happening:
1.- We are asking MySQL to get fields using "db->select()" from the table "WorkOrder" using "db->from()" and joining data from other tables. This is a copy and paste from my model, but you may simplify it by ignoring the "join" lines, just make sure that the fields exist on the table you are using.
2.- We are assigning the MySQL query to $lBoards using the "db->get()".
3.- Finally, we are returning all the data stored in "$lBoards".

CI Controller

Then we have the controller: with my controller i just process the data returned by the model, in this case "$lBoards".

function index()
{
    $this->load->view('main-grid');
}
 
function js_listBoards()
{
    $Boards = $this->Boards->getBoards();
 
    foreach($Boards->result() as $row)
    {
        $item = Array("WOrder" => $row->WOrder, 
                      "PartNumber" => $row->PartNumber,
                      "WOPartQuantity" => $row->WOPartQuantity, 
                      "PartPriority" => $row->PartPriority,
                      "WODateIn" => $row->WODateIn,
                      "WODateOut" => $row->WODateOut,
                      "PartState" => $row->PartState,
                      "Partstatus" => $row->PartStatus,
                      "PartLocation" => $row->PartLocation);
 
        $itemList[] = $item;
    }
 
    $rows = $Boards->num_rows();
    $data = json_encode($itemList);
 
    echo '({"total":"' . $rows . '","results":' . $data . '})';
}

We have a little more going on here:
1.- NOTE THAT THERE IS NO VIEW BEING LOADED FROM THE "js_listBoards" controller, we load the view from the index function only, nowhere else.
2.- Now to get the data from the model to the controller, we call the method that returns the "$lBoards" and we assign a local the local variable "$Boards".
3.- Since we are dealing with rows and not individual values we need to use and array of an array. We use a "foreach" to get each row and create an "$item" array with the values in the first row.

NOTE: I recommend using the same names for the fields here, this way you can keep track of what you are doing and find mistakes a lot quicker (plus you can assign whatever headers to the grid later on).

So having an array "$item" is not enough to get the whole set of rows so we store that array into second array "$itemList". This will produce an array with x number of arrays in it. This will loop until the end is reached.

Then we have the $rows and $data variables:

$rows: it just counts how many rows of data you will have.
NOTE: you must get the $rows. i could not get the grid populated without this being there.

$data: this is what contains all the data the "foreach" loop got for you. YOU MUST ENCODE IT USING "json_encode($itemList)" else it will not work since we will be using json_reader to create the data store to be used by the grid. The json_encode should give you something like this:

({"total":"1","results":[{"WOrder":"97350","PartNumber":"H35146AAD","WOPartQuantity":"3","PartPriority":"Medium","WODateIn":"2007-02-13","WODateOut":"2007-02-16","PartState":"None","Partstatus":"Done ","PartLocation":"Primary"}]})

You can test if your function is working by calling: http://localhost/index.php?c=CONTROLLER&m=METHOD and you should see your json string similar to the one above.
NOTE: in the CI config folder you must set the following:

$config['enable_query_strings'] = TRUE;
        $config['controller_trigger'] = 'c';
        $config['function_trigger'] = 'm';

Also make sure that you set up the routes file found in the CI config folder:

$route['default_controller'] = "listboards";

The "listboards" is the controller where i have all my code. If you dont set this up and you see the welcome message from CI in your browser you know that you forgot to change the default controller.

NOTE: Maybe there is another way, but i was not able to get it working without changing the default controller. If i set it back to "welcome" and use http://localhost/index.php/listboards only the HTML loads up in the page, but none of the css, js, etc will execute even when the links are there. Firebug gives no error about anything missing so it must be a routing problem, but it works just fine when you assign a default controller.

And last, but not least the echo statement which is pretty much straight forward.

JS File

Now we have the JS file which has all the JS code:

Ext.onReady(function(){        
    var dataRecord = new Ext.data.Record.create([
        {name: 'WOrder'},
        {name: 'PartNumber'},
        {name: 'WOPartQuantity'},
        {name: 'PartPriority'},
        {name: 'WODateIn', type: 'date', dateFormat: 'Y-m-d'},
        {name: 'WODateOut', type: 'date', dateFormat: 'Y-m-d'},
        {name: 'PartState'},
        {name: 'Partstatus'},
        {name: 'PartLocation'}
    ]);
 
    var dataReader = new Ext.data.JsonReader({
        root: 'results'
        },
        dataRecord
    );
 
    var dataProxy = new Ext.data.HttpProxy({
        url: '../../../index.php/listboards/js_listboards',
        method: 'POST'
    });
 
    var dataStore = new Ext.data.Store({
            proxy: dataProxy,
            reader: dataReader
    });
 
    var colModel = new Ext.grid.ColumnModel([
        {header: "Work Order", sortable: true, dataIndex: 'WOrder'},
        {header: "Part Number", dataIndex: 'PartNumber'},
        {header: "QTY", dataIndex: 'WOPartQuantity'},
        {header: "Priority", sortable: true, dataIndex: 'PartPriority'},
        {header: "Date In", renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'WODateIn'},
        {header: "Date Out",renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'WODateOut'},
        {header: "Part State", dataIndex: 'PartState'},
        {header: "Part Status", dataIndex: 'PartStatus'},
        {header: "Part Location", dataIndex: 'PartLocation'},
    ]);
 
    var grid = new Ext.grid.GridPanel({
        autoHeight: true,
        renderTo: 'mainGrid',
        store: dataStore,
        id: 'grid',
        width: 740,
        viewConfig: {
            forceFit: true
        },
        cm: colModel
    });
 
    dataStore.load();
 
 
// DEBUGGING ONLY - UNCOMMENT ONLY WHEN DEBUGGING CODE
    /*dataStore.on({
        'load':{
            fn: function(store, records, options){
                console.log('01 - Data Store listener fired (load), arguments:',arguments);
                console.log('         this:',this);
            }
            ,scope:this
        }
        ,'loadexception':{
            fn: function(httpProxy, dataObject, arguments, exception){
                console.log('** - Data Store listener fired (loadexception), arguments:',arguments);
            }
            ,scope:this
        }
    });
 
    Ext.Ajax.on({
         //Fires before a network request is made to retrieve a data object:
         'beforerequest':{
            fn: function(connection, options){
                console.log('03 - Ajax listener fired (beforerequest), arguments(connection, options):',arguments);
            }
            ,scope:this
        }
        //Fires if the request was successfully completed:
        ,'requestcomplete':{
            fn: function(connection, response, options){
                console.log('10 - Ajax listener fired (requestcomplete), arguments(connection, response, options):',arguments);
            }
            ,scope:this
        }
        //Fires if an error HTTP status was returned from the server. See HTTP Status Code 
        //Definitions for details of HTTP status codes:
        ,'requestexception':{
            fn: function(connection, response, options){
                console.log('Ajax listener fired (requestexception), arguments:(connection, response, options)',arguments);
            }
            ,scope:this
        }
    });
 
    dataProxy.on({
         'beforeload':{
            fn: function(store, options){
                console.log('02 - Proxy listener fired (beforeload), arguments:',arguments);
            }
            ,scope:this
        }
        ,'load':{
            fn: function(store, options){
                console.log('Proxy listener fired (load), arguments:',arguments);
            }
            ,scope:this
        }
        ,'loadexception':{
            fn: function(store, options){
                console.log('Proxy listener fired (loadexception), arguments:',arguments);
            }
            ,scope:this
        }
    });*/
 
});

This is where i had most of my problems since when i started to write the code i had no idea of what i needed and other examples were not specific about it, yet they were good about giving more details, but no requirements.

To get your grid working you must have:
1.- A dataRecord:
Here all you do is define how the record or row should received, you dont have to have all the fields you got from the SQL query, but if you want to use it you must define it here. Defining data types is not mandatory, BUT if you have any "date" fields and want to format that date, you will need to specify the data type "date" as you can see from my code above.

2.- A dataReader:
Here you are telling it how to read the data. Since we are returning a json string you need to use a json reader.

3.- A dataProxy:
Here is where we tell it where to get the data from. In this example we use the CI url model, but you can also use "http://localhost/index.php?c=CONTROLLER&m=METHOD", if you have it configure to allow that kind of url.
NOTE: you must give the path for the file and not a full URL. EX: http://localhost/index.php?c=CONTROLLER&m=METHOD nor http://localhost/index.php/CONTROLLER/METHOD. This will result on access denied and you will have to use scriptHttpProxy.

4.- A dataStore:
With the 3 previous steps we can now create a data store and since we have created each property separate it is pretty easy to create.

5.- A ColumnModel:
This is optional, but if defined by itself it makes your grid code look much nicer, otherwise, you will have to define the columns within the grid definition.

The header property is whatever makes sense to your grid, but the dataIndex MUST MATCH any property name defined in step #1 (dataRecord) else the mapping will fail and you will have empty columns or the entire grid.

6.- A Grid:
Finally here is where we build the grid with all of the previous data which makes it easier to understand.

Also defining all of those separate will give you better control for usage and debugging so i recommend you do it that way.

Finally you will see i have commented out the "debugging" part so if you need to debug it just un-comment it and see the messages in firebug.

View

And to conclude we will create the view which must match the value specified in the "load->view('main-grid')" located in the index():

<html>
<head>
    <title>Grid Test</title>
 
    <!-- Include Ext and app-specific scripts: -->
    <script type="text/javascript" src="system/resources/js/extjs/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="system/resources/js/extjs/ext-all-debug.js"></script>
    <script type="text/javascript" src="system/resources/js/js_listboards.js"></script>
    <script type="text/javascript" src="system/resources/js/mainMenu.js"></script>
 
    <!-- Include Ext stylesheets here: -->
    <link rel="stylesheet" type="text/css" href="system/resources/js/extjs/resources/css/ext-all.css">
    <link rel="stylesheet" type="text/css" href="system/application/views/css/ExtStart.css">
 
</head>
<body>
    <h1>My Grid</h1>
    <div id="mainMenu"></div>
 
    <div id="mainGrid"></div>
 
</body>
</html>

This all possible thanks to "mjlecomte" for helping me out through all this... with his help i learned not just used the code..
Thanks

This page was last modified on 14 March 2008, at 15:08. This page has been accessed 47,026 times.