Introduction
This post is mostly a whole bunch of information I have gathered to using ExtJs 3.4 grouped by different subjects.
I hope any one stuck with Extjs 3.4 to have use for it.
Errors and possible solutions
Writing code and debugging ExtJs can sometimes be a pain because errors trown by browsers are not always clear. Like with most software, not all errors shown point directly to the actual problem. Unforntunately because javascript is very flexible, it can go wrong on many levels.
The following list gives you a guide in which errors indicate to which problems.
this.addEvents is not a function:’statesave’
Check if you use new for all of your created Ext components.
‘events’ is null or not an object
Check comma’s in items arrays
‘minWidth’ is null or not an object
Check comma’s in buttons arrays.
Expected identifier, string or number
Check comma’s inside Ext element config objects or/and arrays.
Comp is undefined
Check for non existing or empty references in an items list.
‘id’ is null or not an object
Check comma’s in ColumnModel arrays.
Unterminated string constant
If it occurs in Internet Explorer it is likely caused by disabling a form prior uploading a file. This somehow causes internet explorer to not send any form information when it is submitted.
TypeError: this.ds is undefined
Stores is not defined for a grid(panel)
Unable to get value of the property ‘0’: object is null or undefined
Check comma’s in field array of stores.
TypeError: this.config[col] is undefinedvar width = this.config[col].width;
Column model with autoexpand not pointing to a valid column. Must point to an id that exists within the column model.
TypeError: c is undefined
Calling add() on a panel/component with an empty or otherwhise faulty reference
Debugging events
Blog about logging all events. https://coderwall.com/p/jnqupq
Ext.util.Observable.capture(myObj, function(evname) {console.log(evname, arguments);})
Store query on exact value
var selectedOptions = this.optionStore.query('id', new RegExp('^' + Ext.escapeRe(String(selRecord.get("answer"))) + '$')); //Returns: MixedCollection\\ //Returns an Ext.util.MixedCollection of the matched records
Store ‘fix’ modifiedRecords()
ExtJS store by default does NOT remove records from modified records on remove or load.
To make this happen use pruneModifiedRecords: true to do this
this.data.productsComboStore=new Ext.data.SimpleStore({ fields:["id","name"], pruneModifiedRecords: true });
Create new record for store
var data = { id: 4, name: 'something' }; //initial data var recCreate = myStore.recordType; //cosntructor for a new record (can allso be called directly) var rec = new recCreate(data); //create record rec.set("id", 0); //alter after creation myStore.add(rec); //add to store
Find row index from record
var recIndex = myStore.indexOf(rec); myGrid.getView().focusRow(recIndex);
Find data index from columnIndex and record from rowIndex
var dataIndex = fGrid.getColumnModel().getColumnAt(fColumnIndex).dataIndex; var record = fGrid.getStore().getAt(fRowIndex); var recValue = record .get(dataIndex);
Using filter with combobox
Apply following config options on combo to make it work
clearFilterOnReset: false, //to make filter on store work lastQuery: '', //another filter fix
Grid rendereres
percentageRenderer:function(fValue, fMeta, fRecord, fRowIndex, fColumnIndex, fStore) { fMeta.css += "cssClass"; return fValue + "%"; }, checkboxRenderer:function(fValue, fMeta, fRecord, fRowIndex, fColumnIndex, fStore){ return ''; }
Set scope of renderer to current object
renderer: { fn: this.someUsefulRenderer, scope: this }
Grid cellclick with image or other elements in renderer
When rendering images or other deep elements within a cell the cellclick events do not longer work correctly. To fix this increase the GridViews depth search paramters. This works on any type of grid view.
view: new Ext.grid.GridView({ cellSelectorDepth: 4, //increase to find deeper elements rowSelectorDepth: 10 //increase to find deeper elements })
Grid using drag an drop in grids
define following grid config options
enableDragDrop: true, ddGroup: 'mygrid-dd', ddText: 'Place this row.'
Create drop target class after render
this.data.grid.period.on("afterrender", function(){ var store = this.stores.periodEdit; //change to actual store var grid = this.periodGrid; //change to actual grid var ddrow = new Ext.dd.DropTarget(grid.getEl(), { ddGroup: 'mygrid-dd', copy: false, scope: this }) }, this);
Override notifyOver on this dropTarget instance to see if may be dropped Notice: using ‘dd.getDragData(e)’ causes the selections in the selectionModel to be changed
notifyOver : function(dd, e, data){ var sourceIndex = data.rowIndex; //get sourceIndex var targetIndex = dd.getDragData(e).rowIndex; //get targetIndex }
Override notifyDrop on this dropTarget instance to do an action when dropped
notifyDrop : function(dd, e, data){ var sourceIndex = data.rowIndex; //get sourceIndex var targetIndex = dd.getDragData(e).rowIndex; //get targetIndex }
Prompt for question
When you want input from the user on a question. Questions like: “sure you want to delete this?”, “Sure you want to go on and lose your unsaved data” etc.
Use the here under described function
Note: Although the buttons can be localized the answer inside the function doesn’t change. Look up the function to see more button configurations if needed.
Ext.Msg.show({ title: "Opslaan", msg: "Would you like to delete this item?", //use translate to localize the message width: 400, buttons: Ext.Msg.YESNO, // buttons : { ok: 'Actie uitvoeren', cancel: 'Terug' }, closable: false, hideBorders: true, style: "border: 0;", fn: function(answer, text){ if (answer == "yes"){ this.deleteItem(); } else { //do nothing } }, icon: Ext.MessageBox.QUESTION, scope: this });
Checkbox column in grid
Toggle selection
this.grid.on("cellclick", function(grid, rowIndex, columnIndex) { //get record var rec = grid.store.getAt(rowIndex); //get data index var dataIndex= grid.getColumnModel().getDataIndex(columnIndex); //toggle value false/true rec.set(dataIndex, !rec.get(dataIndex)); }, this);
Renderer
function(fValue, fMeta, fRec, fRow, fCol, fStore){ fMeta.css += " x-grid-col-selected"; return ''; }
Grouping grid The column you want to group with must be included within the columnModel. Even if it’s hidden, it MUST be included.
Use CSS background class to an image
'';
Replacing or reseting upload field
Because of security reasons an upload field cannot be set or reset.
The only way to do so, is to replace the whole field.
See the example below:
//replace upload field var config = uploadField.initialConfig; uploadField.destroy(); uploadField = new Ext.form.TextField(config); //re-add to the fomd the upload field contained too //this can also be a grouping label etc form.add(FF.paragraphImageUploadField); form.doLayout();
Show / hide loadmask
When you are loading or saving something inside your interface, you don’t want the user to change things that might get updated the next second or will not be saved because the actual data is already send to the server. Additionally you would like show the user a vissual indication something is going on.
The following functions add a loadmask to a component to achieve this. The inner workings have been proven to fix problems that occur when this function is called before the actual component is rendered. And even shows the loadMask in the event that rendering completes before loading does.
//show load mask //shows it on this gui, waits for gui to render if not already done //and if hideMasks is called before showLoadMask. The loadMask will not be shown. showLoadMask:function(){ //see if main screen is already rendered if(this.rendered){ //if no loadmask created if(!this.loadMask){ //create loadmask this.loadMask = new Ext.LoadMask(this.getEl(), { msg: app.instance.translate("loading data") + "..." }); } //if supress load mask flag is set if(this.surpressLoadMask){ //do now show mask delete this.surpressLoadMask; }else{ //if everything ok, show load mask this.loadMask.show(); } }else{ //if main screen not rendered, rerun when rendered with small delay this.on('render', this.showLoadMask, this, {single: true, delay: 100}); } }, //hide the load mask (and additional masks if added) hideMasks:function(){ //if loadmask is created if(this.loadMask){ //hide loadmask this.loadMask.hide(); }else{ //if loadmask is not created, but this function is called. //set supressloadmask flag to prevent load mask from being shown here after this.surpressLoadMask = true; } },