Archive for the ‘Javascripts’ category

Extjs : Remotesort. Serverseitiges Paging und die vielgesuchte Serverresponse

January 17th, 2010

Ich bastle seit Tagen an einer Groupinggrid mit Paging, Search, Exportfunktion, Inlineediting mit Roweditor, RSA Verschlüsslung und remote Sortierung auf alle Spalten.
Gleich ein wenig viel für den Anfang.

Also beschränke ich mich vorerst auf das Remotesorting, Grouping, RSA  und eben das Paging.

Wichtig zu wissen ist hier:
Der JsonReader verarbeitet die wesentlichen Serverresponse-Values. Wie die Gesamtzahl(totalProperty) der Datensätze. “totalProperty” ist wichtig für das Paging. Ohne die Zahl werden die Navigationsbuttons nicht aktiviert und paging suxx.
root: ‘data’, Enthält die Daten zur Anwort. Ohne Daten kein View. Klar.

Die Response muss allso mindestens 3 JS-Objekte liefern. “totalCOunt, sort und data”.
Die Resonse zu der Grid mit 2 Datensätzen oben sieht also folgendermassen aus:

{ "totalCount":206, "sort":"company_name", "message":"ewqeqwewqe", "data":
 [
     { "copyID":"227", "survey_name":"Mitarbeiterumfrage", "orga_name":"Trainer", "company_name":"Test23 AG", "created":"2009-06-16 19:19:13",    "description":"Test" },

     { "copyID":"226", "survey_name":"Mitarbeiterumfrage2", "orga_name":"Trainer2", "company_name":"Test AG 22", "created":"2009-06-16 19:19:13",    "description":"Test" },

] }

Groupstore: Beinahe noch wichtiger ist der Initialload der ersten page. Der Datastore wird beim Rendern mit der page 0 geladen

gridedtorstore.load({params:{start: 0, limit: 20}});

Der Code für die Grid dann so. Nicht über die RSA Sachen wundern. Die verschlüsslung ist hier Standar

var columnobjectsurvey = Ext.data.Record.create([{name: 'copyID',type: ''},{name: 'company_name',type: 'string'},{name: 'orga_name',type: 'string'},{name: 'created',type: 'string'},{name: 'description',type: 'string'},{name: 'survey_name',type: 'string'}]);

        //proxi
        surveyproxy = new Ext.data.HttpProxy({
            url: '/cocominZend/0.0.1/public/survey/store/get'
        });
        //reader
        this.surveyreader = new Ext.data.JsonReader({
        totalProperty: 'totalCount',
        successProperty: 'success',
        idProperty: 'id',
        root: 'data',
        messageProperty: 'message',
        fields: columnobjectsurvey
        });
        //writer
        // The new DataWriter component.
        this.surveywriter = new Ext.data.JsonWriter({
            encode: false   // <-- don't return encoded JSON -- causes Ext.Ajax#request to send data using jsonData config rather than HTTP params
        });

        this.gridedtorstore = new Ext.data.GroupingStore({
        id: 'survey',
        proxy: surveyproxy,
        idProperty: 'copyID',
        remoteSort: true,
        reader:surveyreader,
        writer:surveywriter,
        restful: true,     // <-- This Store is RESTful
        groupField:'survey_name',
        sortInfo: {field: 'company_name', direction: 'ASC'},
    });
        gridedtorstore.load({params:{start: 0, limit: 20}});

         var roweditorsurvey = new Ext.ux.grid.RowEditor({
                saveText: 'Update',
                listeners :
                {
                    afteredit : function(row) {

        var secure = true;
        var secureParam = secure ? 't' : 'f';
        val='copyID###'+row.record.data.copyID+'||'+'company_name###'+row.record.data.company_name+'||'+'orga_name###'+row.record.data.orga_name+'||'+'created###'+row.record.data.created+'||'+'description###'+row.record.data.description+'||'+'survey_name###'+row.record.data.survey_name+'||';
        alert(val);
        if(secure){
            val = rsajax.encrypt(val);
        }

        $.ajax({
            url: '/cocominZend/0.0.1/public/admin/pgp/decrypt',
            data: {val: val, secure: secureParam},
            dataType: 'json',
            success: function(data)
            {
                var val = data.val;
                if(secure)
                {
                    val = rsajax.decrypt(val);
                    Ext.MessageBox.alert('encrypted answer:',val);
                }
                else
                {
                    Ext.MessageBox.alert('dsds','Anybody who happened to be monitoring your network activity could have seen that data.');
                }
          },
            error: function(e)
            {
                Ext.MessageBox.alert('plain answer:',e.responseText);
            }
        });
            row.record.commit();
                    },
                }
            });

        var checkboxSelection = new Ext.grid.CheckboxSelectionModel({});
        var editorgridsurvey = new Ext.grid.GridPanel({
        store: gridedtorstore,
        region:'center',
        viewConfig: {forceFit: true},
        stripeRows:	true,
        stripeCols:	true,
        enableColLock: false,
loadMask: true,
plugins: [roweditorsurvey],
        view: new Ext.grid.GroupingView({
            markDirty: true
        }),
        tbar: [
{
text:		'list selected',
handler:	function(){
var seltext = '';
var sels = editorgridsurvey.getSelectionModel().getSelections();
for( var i = 0; i < sels.length; i++ ) {
seltext += sels[i].get('username');
}
Ext.Msg.alert('Selected', seltext);
}
}
                        ,
       {
            iconCls: 'icon-user-add',
            text: 'addSurvey',
            handler:
            function(){
                var e = new columnobjectsurvey({
            copyID:'newUser',company_name:'company_name',orga_name:'orga_name',created:'01/01/2010',description:'description',survey_name:'survey_name'
                });

            }

        },
        {
            ref: '../removeBtn',
            iconCls: 'icon-user-delete',
            text: 'removeSurvey',
            disabled: true,
            handler: function(){
                roweditorsurvey.stopEditing();
                var selections = editorgridsurvey.getSelectionModel().getSelections();

        var secure = true;
        var secureParam = secure ? 't' : 'f';
        val='userID###'+selections[0].data.userID+'||delete###true';
        alert(val);
        if(secure){
            val = rsajax.encrypt(val);
        }

        $.ajax({
            url: '/cocominZend/0.0.1/public/admin/pgp/decrypt',
            data: {val: val, secure: secureParam},
            dataType: 'json',
            success: function(data)
            {
                var val = data.val;
                if(secure)
                {
                    val = rsajax.decrypt(val);
                    Ext.MessageBox.alert('encrypted answer:',val);
                }
                else
                {
                    Ext.MessageBox.alert('dsds','Anybody who happened to be monitoring your network activity could have seen that data.');
                }
          },
            error: function(e)
            {
                Ext.MessageBox.alert('plain answer:',e.responseText);
            }
        });
                for(var i = 0, r; r = selections[i]; i++){
                    gridedtorstore.remove(r);

                }
            }
        },
        {
            text   : 'printSurvey',
            iconCls: 'icon-user-print',
            handler: function() {
            Ext.ux.GridPrinter.print(editorgridsurvey);
            },
        },
        {
            text   : 'printSurvey',
            iconCls: 'icon-user-print',
            handler: function() {
            document.location = '/cocominZend/0.0.1/public/survey/export/excel';
            }
       },

     new Ext.PagingToolbar({
            pageSize: 10,
            store: gridedtorstore,
            displayInfo: true,
            emptyMsg: "No topics to display"

        })
        ],
        columns: [new Ext.grid.RowNumberer(),{
                        id: 'company_name',
                        header: 'company_name',
                        inputType:'textfield',
                        dataIndex: 'company_name',
                        sort: 'company_name',

                        sortable: true,
                        width:200,
                        editor: {
                        xtype: 'textfield',
                        allowBlank: false,
                        inputType:'textfield',
                        disabled:false
                       }},{
                        id: 'orga_name',
                        header: 'orga_name',
                        inputType:'textfield',
                        dataIndex: 'orga_name',
                        sort: 'orga_name',

                        sortable: true,
                        width:100,
                        editor: {
                        xtype: 'textfield',
                        allowBlank: false,
                        inputType:'textfield',
                        disabled:false
                       }},{
                        id: 'created',
                        header: 'created',
                        inputType:'textfield',
                        dataIndex: 'created',
                        sort: 'created',

                        sortable: true,
                        width:120,
                        editor: {
                        xtype: 'textfield',
                        allowBlank: false,
                        inputType:'textfield',
                        disabled:true
                       }},{
                        id: 'description',
                        header: 'description',
                        inputType:'textfield',
                        dataIndex: 'description',
                        sort: 'description',

                        sortable: true,
                        width:200,
                        editor: {
                        xtype: 'textfield',
                        allowBlank: false,
                        inputType:'textfield',
                        disabled:false
                       }},{
                        id: 'survey_name',
                        header: 'survey_name',
                        inputType:'textfield',
                        dataIndex: 'survey_name',
                        sort: 'survey_name',

                        sortable: true,
                        width:200,
                        editor: {
                        xtype: 'textfield',
                        allowBlank: false,
                        inputType:'textfield',
                        disabled:false
                       }}]
    });

        this.surveyEditorgridPanel = new Ext.Panel({
        title: 'registeredUser',
        layout: 'border',
        autoScroll:true,
        width:1200,
        height: 500,
        items: [editorgridsurvey]
    });

            editorgridsurvey.getSelectionModel()
            .on('selectionchange', function(sm){
                editorgridsurvey.removeBtn.setDisabled(sm.getCount() < 1);
            });
             var categoryStore = new Ext.data.JsonStore({
            fields:['sum','categories'],data:[
                { categories:'Sonstiges',
                  sum: 42
                },
                { categories:'Coaching',
                  sum: 162
                }]
            }); var countryStore = new Ext.data.JsonStore({
            fields:['sum','countries'],data:[
                { countries:'Deutschland',
                  sum: 197
                },
                { countries:'Schweiz',
                  sum: 5
                },
                { countries:'Österreich',
                  sum: 2
                }]
            }); var companyCategoriesStore = new Ext.data.JsonStore({
            fields:['sum','companyCategory'],data:[
                { companyCategory:'Finanzdienstleistung',
                  sum: 199
                },
                { companyCategory:'Automobilindustrie',
                  sum: 5
                }]
            }); var companySizeStore = new Ext.data.JsonStore({
            fields:['sum','companySize'],data:[
                { companySize:'Mehr als 500 Mitarbeiter',
                  sum: 126
                },
                { companySize:'Mehr als 1000 Mitarbeiter',
                  sum: 70
                },
                { companySize:'50 -100 Mitarbeiter',
                  sum: 1
                },
                { companySize:'20 - 50 Mitarbeiter',
                  sum: 2
                },
                { companySize:'weniger als 10 Mitarbeiter',
                  sum: 5
                }]
            });
 var SurveyWithAveragesStore = new Ext.data.JsonStore({
        fields:['name', 'surveys', 'average'],
        data: [{name:'02', surveys: 32, average:'16'},{name:'03', surveys: 23, average:'11.5'},{name:'04', surveys: 30, average:'15'},{name:'05', surveys: 7, average:'3.5'},{name:'06', surveys: 39, average:'19.5'},{name:'07', surveys: 4, average:'2'},{name:'08', surveys: 4, average:'2'},{name:'09', surveys: 16, average:'8'},{name:'10', surveys: 24, average:'12'},{name:'11', surveys: 25, average:'12.5'}]});  //gets dynamicly replaced with content
        var xg = Ext.grid;

        // shared reader
        var reader = new Ext.data.ArrayReader({}, [

            {name: 'title'},
            {name: 'username'},
            {name: 'lastChange', type: 'date'},
            {name: 'desc',type:'text',selectable:true}
        ]);

    // row expander
    var expander = new Ext.ux.grid.RowExpander({
        tpl : new Ext.Template(
            '<p><b>Notiz:</b> {desc}</p>'
        )
    });

und der Gridpanel noch zu guterletzt

new Ext.Panel({
                id              :'surveyEditorgridPanel',
                title           :'surveyEditorgridPanel',
                region          :'center',
                deferredRender  :false,
                layout          :'table',
                frame           :true,
                padding         :10,
                autoScroll      :true,
                layoutConfig    :{columns:1},
                defaults        :{frame:true, width:900, height: 450},
                items:[

         {
                    title:'User: cocomin',
                    items:[{}],
                    colspan:2,
                    width:900,
                    height:70,
                    margin:10,
                    html: '<h1>Hallo cocomin heute ist der #date#. Willkommen in Deiner Umfrageadministration</h1><p>Im folgenden findest Du die neuesten Daten aus Deinen Umfragen. <input type="button" value="export"></p>'
                }
        ,
                    surveyEditorgridPanel
                ]
            })

EXTJS Ext.Formpanel encrypted formvalues

January 9th, 2010

In meinem letzen Artikel habe ich beschrieben, wie man mit Ajax-PHP RSA PKi umsetzen kann.
Nun habe ich mir die Mühe gemacht und das Ganze in eine Extjs BasicForm implementiert.

Problem hierbei war die getForm().submit() Methode zu erweitern. submit() generiert die Values automatisch und überträgt sie.
Um die Values zu verschlüsseln, muss das Formpanel einen Listener bekommen der auf “beforeAction” und “actioncomplete” feuert.

Ersteren, um die Values verschlüsselt zurück ins form zu schreiben. Dannach steht in den Textfeldern jedoch verschlüsselter inhalt. Das ist unschön im Workflow, weil der User einen Fehler vermuten könnte. Daher werden die Values in einem Object zwischengespeichert bevor sie verschlüsselt werden.

Nach dem dem Submit werden die zwischengespeicherten Values mit den Originalvalues zurück ins Form geschrieben und der User sieht nur für einen Moment (dauer der Uebertragung) die verschlüsselten Values. Da über dem Form ein Overlay liegt und er einen Preloader sieht ist das kaum wahrnehmbar.
1) RSA Codes client und Serverseitig einbinden. siehe Tutorial
2) ein Form wie folgendes erstellen.

{xtype:'form',url:'/controller/0.0.1/public/admin/save',title:'Mailserver',listeners:
          {
             beforeaction: {
               fn: function(frm, action) {
                //klasse speichert die unverschlüssleten values zwischen
                function ValueObjects() {
                     this.values    = [];
                   }
                valueobject= new ValueObjects();
                        var form= Ext.getCmp('formMailserver').getForm();
                        var value = form.getValue();
                        valueobject.values['mailserver_server']=value;
                         form.findField('mailserver_server').setValue(rsajax.encrypt(value));

                }
              },
              actioncomplete : {
               fn: function(frm, action) {
                        var form= Ext.getCmp('formMailserver').getForm();
                        form.findField('mailserver_server').setValue(valueobject.values['mailserver_server']);
                }
              }
            }
,labelWidth:150,
id:'formMailserver',
frame:true,
items:[
{xtype:'textfield',
value:'test',
fieldLabel:'mailserver_server',
id:'mailserver_server',
allowBlank:false},
{id:'mailserver_buttonMailserver',
text:'speichern',
xtype:'button',handler:function(){
        var formAction = Ext.getCmp('formMailserver').getForm().url;
        if(formAction=='')
        {
            alert('URL or the formMailserver ist not defined in table : forms');
        }

          Ext.getCmp('formMailserver').getForm().submit({
                        method: 'POST',
                        waitMsg: 'saving ...',
                        success: function (f, a) {
                            Ext.Msg.alert('',''+a.result.data.message);
                        },
                        failure: function (f, a) {
                            Ext.Msg.alert("Error", "Failed .............")
                        }
                    });

    }}]}

RSA Verschlüsselung von Requests Client und Serverseitig für Zend mittels RC4 per Ajax

January 8th, 2010

Die einfachste Lösung seine Daten verschlüsselt zu übertragen ist SSL.
Wer an Opensource Webprojekten schraubt kann aber weder den User zwingen teure Zertifikate zu kaufen oder entsprechende Module wie mycrypt für AES oder openSSL bei seinem Hoster nachzurüsten.

Eine symetrische Verschlüsselung mit AES scheidet wegen dem “man in the middle” Problem aus. Also muss eine Methode her, die bei Netzwerküberwachung keine Daten preisgibt die einfach zu entschlüsseln wären.

Ich habe mich auf Anraten eines Commuitymitglieds (Danke an goosejan für die Nerven) entschieden, das asymetrische PKI Verfahren zu verwenden.
Auf der Clientseite werden die Formularinhalte mittels Javascript RC4 mit einem öffentlichen Schlüssel verschlüsselt, den der Server liefert und per Ajax an den Server übertragen. Das Ganze funktioniert 2 Way. Die Antwort des Servers wird natürlich auch verschlüsselt und clientseitig wieder entschlüsselt.

Als Privatekey auf dem Server wird eine 40 Zeichen lange Zeichenkette verwendet.

Als Grundlage habe ich die Implementierung verschiedener Programmierkollegen verwendet (siehe Sourcecomments).
Das Ganze habe ich auf Zend Framework 1.9.6 mit jquery (jquery-min) portiert und als Zend Modul “Zend_RSAjax” für Zend-Framework Projekte flott gemacht.

Hier sind die Sourcen dazu.
library: liegt bei mir unter library im Zend_Framework Projektordner, damit sie automatisch geladen werden
library:Zend_RSAjax
public: javascripte im publicordner
public:javascripts

Lizenzen: Bitte die Lizenzen MIT und GPL der einzelnen Implementierungen beachten.

Hier das Tutorial:
1) Controller anlegen, der die Requests entgegennimmt. Bei mir liegt der im Modul Admin also :( Admin_PgpController)

<?php
/**
 * @desc implements the serverside RAS RC4
 * @author: Peter Boethig
 */
class Admin_PgpController extends Zend_Controller_Action {

    public function init() {

        $this->RSAWrapper = new Zend_RSAjax_Wrapper();
    }

    public function indexAction() {
        ;
    }
    //disable layout for Ajaxcalls
    public function preDispatch() {
        $this->_helper->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);
    }

    //return the pKey for clientsite
    public function getpublickeyAction() {
        $json = array('n'=>$this->RSAWrapper->rsajax_server_n, 'e'=>$this->RSAWrapper->rsajax_server_e);
        print(json_encode($json));
    }

    //saves PK into session
    public function setsessionAction() {
        if($this->_request->getParam('key') !=null) {
            if(!session_id){session_start();}
            $_SESSION['s_rsajax_client_key'] = $this->RSAWrapper->decrypt($this->_request->getParam('key'));
        }
    }

    //decodes Value and returns encoded
    public function getkeyAction() {
        if($this->_request->getParam('secure')=='t') {
            $val = $this->RSAWrapper->encrypt($this->RSAWrapper->decrypt($this->_request->getParam('val')));
        }
        header('Content-Type: text/html;charset=utf-8');
        print(json_encode(array('val'=>utf8_encode($val))));
    }
}

2) RC4 und RAS Javscripte für die Clientseite einhängen
Hier im Downloadlink sind die Sourcen dazu. einfach in den html Head einhängen.

3) In dem Viewscript oder in einem Helper, welches das Formular enthält zb. index.phtml wird ein Javascript ausgeben, welches die Secure Session startet.

$SecureSession = new Zend_RSAjax_SecureSession();
$this->getController     = $this->baseURL."/admin/pgp/getpublickey";  // Pfad auf  die Controlleraction (bei mir admin)
$this->sessionController = $this->baseURL."/admin/pgp/setsession";
echo $SecureSession->create();

4) Das Formular übertragen

<input type=’submit’ onclick=’sendForm()’>

function sendForm(){
        var secure = true; //should be tested
        var secureParam = secure ? 't' : 'f';
        val='testpass';  // your formvalues

        if(secure){
            val = rsajax.encrypt(val);
        }

        $.ajax({
            url: '/cocominZend/0.0.1/public/admin/pgp/getkey', //your requestcontroller in Zend
            data: {val: val, secure: secureParam},
            dataType: 'json',
            success: function(data)
            {
                var val = data.val;
                if(secure)
                {
                    val = rsajax.decrypt(val);
                    alert(val + 'As you can see, your data was encrypted. Nobody could have read it by monitoring your network activity.');
                }
                else
                {
                    alert('Anybody who happened to be monitoring your network activity could have seen that data.');
                }
          },
            error: function(e)
            {
                alert('error:'+e.responseText);
            }
        });
}

Extjs: Checkboxvalues unchecked übertragen

December 30th, 2009

Das leidige Thema checkboxen im Submit macht auch in Extjs keine Ausnahme.
Checkboxen und Radiobuttons werden beim Submit nicht übertragen wenn sie nicht gesetzt sind. In HTML ist das ganze recht einfach.

In Extjs habe ich die einfachste Lösung gefunden. Man überschreibt das Defaultverhalten und setzt seinen eigenen unchecked-Value.

Hier iist der Code dazu.

Ext.lib.Ajax.serializeForm = function(F){
	if(typeof F==\"string\"){
		F=(document.getElementById(F)||document.forms[F])
	}
	var G,E,H,J,K=\"\",M=false;
	for(var L=0;L<F.elements.length;L++){
		G=F.elements[L];
		J=F.elements[L].disabled;
		E=F.elements[L].name;
		H=F.elements[L].value;
		if(!J&&E){
			switch(G.type){
				case\"select-one\":
				case\"select-multiple\":
					for(var I=0;I<G.options.length;I++){
						if(G.options[I].selected){
							if(Ext.isIE){
								K+=encodeURIComponent(E)+\"=\"+encodeURIComponent(G.options[I].attributes[\"value\"].specified?G.options[I].value:G.options[I].text)+\"&\"
							}else{
								K+=encodeURIComponent(E)+\"=\"+encodeURIComponent(G.options[I].hasAttribute(\"value\")?G.options[I].value:G.options[I].text)+\"&\"
							}
						}
					}
					break;
				case\"radio\":
				case\"checkbox\":
					if(G.checked){
						K+=encodeURIComponent(E)+\"=\"+encodeURIComponent(H)+\"&\"
					} else {
						K+=encodeURIComponent(E)+\"=\"+encodeURIComponent('false')+\"&\"
					}
					break;
				case\"file\":
				case undefined:
				case\"reset\":
				case\"button\":
					break;
				case\"submit\":
					if(M==false){
						K+=encodeURIComponent(E)+\"=\"+encodeURIComponent(H)+\"&\";M=true
					}
					break;
				default:
					K+=encodeURIComponent(E)+\"=\"+encodeURIComponent(H)+\"&\";
					break
			}
		}
	}
	K=K.substr(0,K.length-1);
	return K
}

Extjs- Propertygrid. Daten submitten

December 24th, 2009

Leider verhalten sich die Propertygrids nicht wie normale Extjs Formulare obwohl sie eigentlich nur eine spezielle Form davon sein sollten.

Eine Möglichkeit über this.getForm().submit() die Daten zu senden gibts leider nicht.

Hier ist es am einfachsten, einen Button zu adden und einen Event zu registrieren, der einen Jsonstring generiert und überträgt.
Hier ist dieser Event. Einfach an die Propertygrid anhängen.
Wichtig ist zu wissen, dass die Propertygrid die Daten in einer “source” Property vorhält. Die kann man aber schlecht iterieren um die Variablen zu ermitteln.
Die Jsonencodierung dieser Source liefert jedoch einen verwendbaren “Pseudo”-Jsonstring in dem die ” mit \ escaped sind. Die muss man nach dem Request einfach entfernen. Dann kann man mit json_decode() sauber die Vars extrahieren.

buttons:
                [{
                    text: 'speichern',
                    handler: function(){
                    var values = Ext.util.JSON.encode(ID_der_Propertygrid.source)  ;
                    Ext.Ajax.request({
                                url       : 'index.jsp',
                                method    : 'POST',
                                params    : {
                                        values : values
                                },
                                scope     : this,
                                callback  : function(options, success, response) {
                                        if (success) {
                                                this.el.unmask();
                                                Ext.MessageBox.alert('Success!', response.responseText);
                                        }else
                                        {
                                            Ext.MessageBox.alert('Failsure!', 'Suxx');
                                        }
                                }
                        })

                    }
                }]

Extjs “Combo -Boxen” und der geliebte “selected” status auf die aktive Option.

December 22nd, 2009

Manche Dinge, die in Standard – HTML so gewohnt einfach und selbstverständlich daherkommen, dass die Erstellung für einen Programmierer ein paar Sekunden dauern, können einen Einsteiger in DOM und speziell in Extjs 3.1 Tage abverlangen.
Ein Selectfield in HTML ist schnell geschrieben. Die selected-Option auf ein bestimmtes Value noch schneller gesetzt.

in HTML sag ich einfach

<select  id ="" name="" >
<option value="id" selected>ein optionvalue</option>
</select>

fertig. Das Value ist voreingestellt.

In Extjs gibts die Komponente “combo” dafür. Sieht echt toll aus und man hat viele Ajaxoptions dafür.
Sie ist auch leicht erstellt.

{
            xtype: 'combo',
            id: 'username',
            fieldLabel: 'Username',
            hiddenName: 'userID',
            emptyText: 'Select a username...',
            store:
              new Ext.data.SimpleStore({
                fields: ['userID','username'],
                data: [['1','cocomin'],['2','testuser']]

            }), // end of Ext.data.SimpleStore
            displayField: 'username',
            valueField: 'userID',
            selectOnFocus: true,
            mode: 'local',
            typeAhead: true,
            editable: false,
            triggerAction: 'all',
            valueField: 'userID',
            value: '1',
          }

Ja, ist doch easy. Klar. Leicht und verständlich.
Ja. Wenn man folgendes berücksichtigt schon.

1) Wenn man weis, dass man für die Options einen Datastore erstellen muss

2) das forceSelection auf true stehen muss

3) das der hiddenvalue (zb userid). der variablenname im request ist

4) das man den Diplayvalue explizit setzen muss
(in diesem Fall displayField: ‘,valueField: ‘username’,)

5) Das die Verwendung eines lokalen Datastores immer mode:local benötigt. (mode:remote versucht einen jsonstring vom server in den Store zu laden)

6) und das ist das wichtigste in Bezug auf vorselectierte Options
value:’Herr Kannengiesser’ setzt einerseits einfach einen Direktvalue. Tut man das so wird jedoch nur der Value übertragen (”Herr Kannengiesser”), weil er ja keine dazugehörige ID kennt. Klar soweit.
Verwendet man jedoch eine ID (z.B.valueField: ‘userID’, value=’1′) aus dem Datastore zeigt er nicht etwa die ID an. Nein, gut erkannt, er sucht im Datastore zuerst eine ID zum Value=’1′. Exsitiert diese ID im Datastorte zeigt er statt “1″ (value:’1′) den value unter “value:’1′” an. Hierzu muss man den Valuefield auf den Key im Store setzen (valueField: ‘userID’),
Dieser ist dann auch fein selected. Im Request kommt dann brav unter $_REQUEST[userID] (hiddenvalue:’userID’) die “1″ als userID an.
Die Doku und das Forum dazu dazu ist so umfangreich, dass ich von Hacks bis zum dynamischen Nachladen bis über eingeharkte HTML Selectfields in Panelkonstrukten alles gefunden und ausprobiert habe.

Ein “selectedValueInStore” wäre eine feine Sache gewesen.. Nunja. Ich freue ich mich nun über die gefundene Lösung und dass ich vielleicht jemandem die 2 Tage Suche sparen kann.

KISS. Keep it short and simple………..

Formulare aufwerten mit EXTJS

July 27th, 2009

EXTJS bringt seit der 1er Version die Transformationsfunktion für Formularinhalte mit.

Damit kann man sehr schnell seine langweiligen HTML Formulare aufbessern. Geht schnell und  sieht hochwertig aus.

Unterstützt werden alle Elemente eines Forms.

Formulare mit EXTJS

Wie man sieht setzt EXTJS definierte Stylesheets mittels Javascript
Das Formular hat folgenden HTM-Content

<fieldset style="padding:5px;">
<legend>{$smarty.request.defaultvalue} (ID: {$smarty.request.testantID})</legend>
  <table  cellspacing="0" cellpadding="0" border="0">
          <tr>
            <td height="25">
                <select  id="salutation">
                    <option value="Herr">Herr</option>
                    <option value="Frau">Frau</option>
                </select>
            </td>
            <td><input  id="firstname" maxlength="80" size="30" value="{if $surnane!="" }$firstname {/if}" name="firstname" ></td>
          </tr>

          <tr>
            <td height="25" colspan="2"><input id="surname" maxlength="80" size="30" value="{if $surnane!="" }$surname {/if}" name="surname"></td>
          </tr>
          <tr>
            <td height="25" colspan="2"><input  id="email" maxlength="80" size="30" value="{if $email!="" }$email{/if}" name="email"></td>
          </tr>
          <tr >
            <td align="left" colspan="2">
               {if $smarty.request.action eq 'newTestant'}
            <input onclick="SaveTestants('')" type="button" class="save" value="Speichern">
            <input onclick="closeForm()" type="button" class="cancel" value="abbrechen">
       {else}
            <input onclick="SaveTestants('{$smarty.request.testantID}')" type="button" class="save" value="Speichern">
            <input onclick="closeForm('testantenDiv')" type="button" class="cancel" value="abbrechen">
       {/if}
            </td>
          </tr>
      </table>
</fieldset>

Das Javascript dazu ist denkbar einfach.
Wie man sieht kann man sowohl die Size als auch die Defaultvalues definieren.
Auch die Eventhandler sind leicht zu definieren.

<script>
 var tf = new Ext.form.TextField({
    applyTo:'firstname',
	width:140,
	emptyText:'Vorname'
  });

var tf = new Ext.form.TextField({
    applyTo:'surname',
	width:200,
	emptyText:'Nachname'
  });

var tf = new Ext.form.TextField({
    applyTo:'email',
	width:200,
	emptyText:'Email'
  });

  var converted = new Ext.form.ComboBox({
    typeAhead: true,
    triggerAction: 'all',
    transform:'salutation',
    width:60,
    forceSelection:true
});

 </script>