Sabtu, 18 Februari 2012

ExtJS: Simple CRUD

Cara paling mudah untuk membuat contoh CRUD (Create, Read, Update dan Delete) adalah menggunakan widget GridEdtiorPanel. Untuk proses backend dapat menggunakan server scripting seperti PHP dengan database MySQL.


Buat tabel di MySQL dengan nama employees
CREATE TABLE `employees` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `emp_no` varchar(20) DEFAULT NULL,
  `fullname` varchar(50) DEFAULT NULL,
  `sex` varchar(10) DEFAULT NULL,
  `dob` date DEFAULT NULL,
  `city` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM
Inisialisasi halaman index.php  Untuk path dan sebagainya, sesuaikan dengan konfigurasi folder aplikasi.


Selanjutnya, buat file app.js yang berisi kode utama CRUD
Ext.require([
    "Ext.window.*",
    "Ext.grid.*",
    "Ext.data.*",
    "Ext.selection.*",
    "Ext.form.*"
]);

// Fixed: Paging Toolbar
Ext.require('Ext.toolbar.Paging', function(){
 Ext.override(Ext.toolbar.Paging, {
  getPageData: function () {
   var store = this.store,
    totalCount = store.getTotalCount();
   
   totalCount = totalCount == 0 ? 1 : totalCount;
   return {
    total : totalCount,
    currentPage : store.currentPage,
    pageCount: Math.ceil(totalCount / store.pageSize),
    fromRecord: ((store.currentPage - 1) * store.pageSize) + 1,
    toRecord: Math.min(store.currentPage * store.pageSize, totalCount)

   };
  }
 });
});

// Fixed: Checkbox Sel Model on CellEditing
Ext.require("Ext.grid.plugin.CellEditing", function(){
 Ext.override(Ext.grid.plugin.CellEditing, {
  startEdit: function(record, columnHeader) {
   var me = this,
    value = record.get(columnHeader.dataIndex),
    context = me.getEditingContext(record, columnHeader),
    ed;
   
   record = context.record;
   columnHeader = context.column;

   me.completeEdit();
   
   context.originalValue = context.value = value;
   if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', context) === false || context.cancel) {
    return false;
   }
   
   if (columnHeader && (!columnHeader.getEditor || !columnHeader.getEditor(record))) {
    return false;
   }
   
   ed = me.getEditor(record, columnHeader);
   
   if (ed) {
    me.context = context;
    me.setActiveEditor(ed);
    me.setActiveRecord(record);
    me.setActiveColumn(columnHeader);
    me.editTask.delay(15, ed.startEdit, ed, [me.getCell(record, columnHeader), value]);
   } else {
    me.grid.getView().getEl(columnHeader).focus((Ext.isWebKit || Ext.isIE) ? 10 : false);
   }        
   return true;
  }
 })
});

Ext.define("MyGrid", {
    extend: "Ext.grid.Panel",
    pageSize: 5,
    url: "crud.php",
    constructor: function (config) {
        
        config = config || {};
        
        Ext.define("Employee", {
            extend: "Ext.data.Model",
            fields: [
                {name: "id"},
                {name: "emp_no"},
                {name: "fullname"},
                {name: "sex"},
                {name: "dob", type: "date"},
                {name: "city"}
            ]
        });        
        
        var store = Ext.create("Ext.data.Store", {
            model: "Employee",
            pageSize: this.pageSize,
            proxy: {
                type: "ajax",
                url: this.url,
                actionMethods: {
                    read: "POST"
                },
                extraParams: {
                    action: "read"  
                },
                reader: {
                    type: "json",
                    root: "data",
                    totalProperty: "total",
                    idProperty: "id"
                }
            },
            autoLoad: {
                start: 0,
                limit: this.pageSize
            }
        });
        
        Ext.applyIf(config, {
            border: false,
            columns: [
                {
                    header: "Emp. No",
                    dataIndex: "emp_no",
                    editor: {
                        xtype: "textfield"
                    }
                },
                {
                    header: "Fullname",
                    dataIndex: "fullname",
                    editor: {
                        xtype: "textfield"
                    }
                },
                {
                    header: "Sex",
                    dataIndex: "sex",
                    editor: {
                        xtype: "combo",
                        store: Ext.create("Ext.data.ArrayStore", {
                            fields: ["sex"],
                            data: [["Male"], ["Female"]]
                        }),
                        displayField: "sex",
                        valueField: "sex",
                        triggerAction: "all",
                        queryMode: "local",
                        lazyRender: true,
                        typeAhead: true
                    }
                },
                {
                    header: "DOB",
                    xtype: "datecolumn",
                    format: "Y-m-d",
                    dataIndex: "dob",
                    editor: {
                        xtype: "datefield",
                        format: "Y-m-d"
                    }
                },
                {
                    header: "City",
                    dataIndex: "city",
                    editor: {
                        xtype: "textfield"
                    }
                }
            ],
            store: store,
            selModel: Ext.create("Ext.selection.CheckboxModel"),
            viewConfig: {
                loadMask: true,
                stripeRows: true
            },
            columnLines: true,
            plugins: [
                Ext.create('Ext.grid.plugin.CellEditing', {
                    clicksToEdit: 1,
                    pluginId: "cellediting"
                })
            ],
            dockedItems: [
                {
                    xtype: "toolbar",
                    dock: "top",
                    items: [
                        {
                            text: "Add",
                            iconCls: "icon-plus-16",
                            scope: this,
                            handler: this.onAddClick
                        },
                        {
                            text: "Delete",
                            iconCls: "icon-cross-16",
                            scope: this,
                            handler: this.onDeleteClick
                        },
                        {
                            text: "Save",
                            iconCls: "icon-disk-16",
                            scope: this,
                            handler: this.onSaveClick
                        },
                        "-",
                        {
                            text: "Reload",
                            iconCls: "icon-refresh-16",
                            scope: this,
                            handler: this.reload
                        }
                    ]
                },
                {
                    xtype: "pagingtoolbar",
                    dock: "bottom",
                    store: store,
                    displayInfo: true
                }
            ]
        });
        
        this.callParent([config]);
        
    },
    reload: function () {
        this.getStore().load();
    },
    onAddClick: function () {
        var ce = this.getPlugin("cellediting"),
            ds = this.getStore();
        
        ds.insert(0, Ext.create("Employee"));
        ce.startEditByPosition({row: 0, column: 1});
    },
    onSaveClick: function () {
        
        var ds = this.getStore(),
            phantoms = ds.getNewRecords(),
            updates = ds.getUpdatedRecords(),
            data = [], i;
        
        if (phantoms.length) {
            this.body.mask("Creating data...");
            for (i = 0; i < phantoms.length; i++) {
                var o = phantoms[i].data;
                o.token = phantoms[i].getId();
                data.push(o);
            }
            
            if (data.length) {
                Ext.Ajax.request({
                    scope: this,
                    url: this.url,
                    params: {
                        action: "create",
                        data: Ext.encode(data)
                    },
                    callback: function (o, s, r) {
                        this.body.unmask();
                        if (s) {
                            var d = Ext.decode(r.responseText);
                            if (d.failed) {
                                for (i = 0; i < d.failed.length; i++) {
                                    ds.remove(ds.getById(d.failed[i].token));
                                }
                            }
                            if (d.created) {
                                for (i = 0; i < d.created.length; i++) {
                                    var rec = ds.getById(d.created[i].token);
                                    if (rec) {
                                        rec.set("id", d.created[i].id);
                                        rec.commit();
                                    }
                                }
                            }
                        }
                    }
                });
            }
        }
        
        if (updates.length) {
            
            this.body.mask("Updating data...");
            
            for (i = 0; i < updates.length; i++) {
                var o = updates[i].data;
                o.token = updates[i].getId();
                data.push(o);
            }
            
            if (data.length) {
                Ext.Ajax.request({
                    scope: this,
                    url: this.url,
                    params: {
                        action: "update",
                        data: Ext.encode(data)
                    },
                    callback: function (o, s, r) {
                        this.body.unmask();
                        if (s) {
                            var rec;
                            var d = Ext.decode(r.responseText);
                            if (d.failed) {
                                for (i = 0; i < d.failed.length; i++) {
                                    rec = ds.getById(d.failed[i].token);
                                    if (rec) rec.reject();
                                }
                            }
                            if (d.updated) {
                                for (i = 0; i < d.updated.length; i++) {
                                    var rec = ds.getById(d.updated[i].token);
                                    if (rec) rec.commit();
                                }
                            }
                        }
                    }
                });
            }            
            
        }
        
    },
    onDeleteClick: function () {
        var rs = this.getSelectionModel().getSelection(),
            ds = this.getStore();
            
        if (rs.length) {
            Ext.Msg.confirm(
                "Confirm",
                "Delete selected record(s) ?",
                function (b) {
                    if (b === "yes") {
                        var data = [], i;
                        for (i = 0; i < rs.length; i++) {
                            if (rs[i].phantom === true) {
                                ds.remove(rs[i]);
                            } else {
                                data.push({token: rs[i].getId(), id: rs[i].data.id});
                            }
                        }
                        
                        if (data.length) {
                            this.body.mask("Deleting...");
                            Ext.Ajax.request({
                                scope: this,
                                url: this.url,
                                params: {
                                    action: "delete",
                                    data: Ext.encode(data)
                                },
                                callback: function (o, s, r) {
                                    this.body.unmask();
                                    if (s) {
                                        var d = Ext.decode(r.responseText);
                                        if (d.deleted) {
                                            for (i = 0; i < d.deleted.length; i++) {
                                                ds.remove(ds.getById(d.deleted[i].token));
                                            }
                                        }
                                    }
                                }
                            });
                        }
                    }
                },
                this
            );
        }
    }
});

Ext.onReady(function(){
    
    // Buat window sebagai container untuk grid
    var win = Ext.create("Ext.window.Window", {
        title: "CRUD Example",
        width: 600,
        height: 300,
        layout: "fit",
        items: Ext.create("MyGrid")
    });
    
    win.show();
    
});

Untuk backend (pemrosesan data), buat file crud.php
$action = isset($_POST["action"]) ? $_POST["action"] : "read";


// database
try {
    if ( ! mysql_connect("localhost", "root", "root"))
        throw new Exception("Cannot connect to database server!");
    if ( ! mysql_select_db("latihan"))
        throw new Exception("No database selected!");
} catch(Exception $e) {
    die(json_encode(array(
        "success" => FALSE,
        "msg"     => $e->getMessage()
    )));
}

// CRUD several functions
if (function_exists($action)) {
    $action();
}

function field_data($table) {
    $query  = mysql_query("SELECT * FROM $table LIMIT 1");
    $fields = array();
    if ($query) {
        for ($i = 0; $i < mysql_num_fields($query); $i++) {
            $fields[] = mysql_fetch_field($query, $i);
        }
        mysql_free_result($query);
    }
    return $fields;
}

function db_insert($table, $data) {
    
    $fields = field_data($table);
    
    if (count($data) > 0 AND count($fields) > 0) {
        $insert = array();
        foreach($fields as $field) {
            foreach($data as $key => $value) {
                if ($key == $field->name) {
                    $insert[$key] = "'$value'";
                }
            }
        }
        if (count($insert) > 0) {
            
            $fld = "";
            $val = "";
            foreach($insert as $key => $value) {
                $fld .= "$key,";
                $val .= "$value,";
            }
            $fld = substr($fld, 0, -1);
            $val = substr($val, 0, -1);
            
            if (!empty($fld) AND !empty($val)) {
                $sql = "INSERT INTO $table ($fld) VALUES ($val)";
                return mysql_query($sql);
            }
        }
    }
    
    return FALSE;

}

function db_update($table, $data, $keys) {
    
    $fields = field_data($table);
    
    if (count($data) > 0 AND count($fields) > 0) {
        $update = array();
        foreach($fields as $field) {
            foreach($data as $key => $value) {
                if ($key == $field->name) {
                    $update[$key] = "'$value'";
                }
            }
        }
        if (count($update) > 0) {
            
            $sql = "UPDATE $table SET ";
            
            foreach($update as $key => $value) {
                $sql .= "$key = $value,";
            }
            $sql = substr($sql, 0, -1);
            
            if (is_array($keys)) {
                $sql .= " WHERE ";
                foreach($keys as $key => $value) {
                    $sql .= "$key = $value AND";
                }
                $sql = substr($sql, 0, strrpos($sql, "AND"));
            }
            
            return mysql_query($sql);
            
        }
    }

    return FALSE;    
    
}

function create() {
    
    $data   = json_decode($_POST["data"]);
    
    $result = new stdClass();
    $result->created = array();
    $result->failed  = array();
    
    if (is_array($data)) {
        foreach($data as $row) {
            if (db_insert("employees", $row)) {
                $result->created[] = array(
                    "token" => $row->token,
                    "id"    => mysql_insert_id()
                );
            } else {
                $result->failed[] = array(
                    "token" => $row->token
                );
            }
        }
    }

    print json_encode($result);    
    
}

function read() {
    
    $result = new stdClass();
    $result->total  = 0;
    $result->data   = array();
    
    $sql    = "SELECT SQL_CALC_FOUND_ROWS *
               FROM employees";
    
    $start  = isset($_POST["start"]) ? $_POST["start"] : 0;
    $limit  = isset($_POST["limit"]) ? $_POST["limit"] : 5;
    
    // limit
    $sql .= " LIMIT $start, $limit";    
    
    $query  = mysql_query($sql);
    if ($query) {
        
        $result->total = mysql_fetch_object(
                            mysql_query("SELECT FOUND_ROWS() as total")
                         )->total;
        
        while($row = mysql_fetch_object($query)) {
            $result->data[] = $row;
        }
        
    }
    
    print json_encode($result);
    
}

function update() {
    
    $data = json_decode($_POST["data"]);
    
    $result = new stdClass();
    $result->updated  = array();
    $result->failed   = array();    
    
    if (is_array($data)) {
        foreach($data as $row) {
            if (db_update("employees", $row, array("id" => $row->id))) {
                $result->updated[] = array("token" => $row->token);
            } else {
                $result->failed[] = array("token" => $row->token);
            }
        }
    }
    
    print json_encode($result);
    
}

function delete() {
    $data = json_decode($_POST["data"]);
    $result = new stdClass();
    $result->deleted = array();
    if (is_array($data)) {
        foreach($data as $row) {
            if (mysql_query("DELETE FROM employees WHERE id = {$row->id}")) {
                $result->deleted[] = array("token" => $row->token);
            }
        }
    }
    print json_encode($result);
}


@mysql_close();

Hasilnya seperti ini:






Download source code contoh aplikasi.
Download library extjs


4 komentar:

  1. nice work.... Its working perfectly .....
    b4 that small changes are required in index.php

    great job......
    thanq......

    BalasHapus
  2. Makasih gan tutor nya, bisa buat belajar nih... :D

    BalasHapus
  3. Untuk crud(insert, update dan delete) tidak jalan.
    Data tidak bisa di insert, update dan delete di table gan.
    Apa ada yang mesti di setting lagi?

    BalasHapus
  4. iya tuuh bener kata bro very richart,
    crudnya ga bisa di pake, apanya ya...?

    BalasHapus