PDA

View Full Version : Config value passed into new() object cant be changed?



lotsofquestions
8 Apr 2010, 7:10 AM
I am extending a Panel and inside this panel I have a propertygrid but my problem is simpler than that. I create a new instance of my custom object type, and pass in an id as a parameter as follows:


var win = new Ext.Window({
layout: 'fit',
autoHeight: true,
width: 400,
items : new LI.PropertyGrid({
iPropertyId : 2
})
});
win.show();

As you can see I am passing in iPropertyId as 2. The following code is the main logic of my new class.


// See http://www.extjs.com/forum/showthread.php?t=41390 for help
Ext.ns('LI');
LI.PropertyGrid = Ext.extend(Ext.Panel, {

//store: null,
configLoaded: false,
items: null,
fields: [],
rawfields: [],
values: [],

layout: 'fit',
autoScroll: false,
height: 200,
//width: 400,
border: false,

// the parent component should set these before calling save or load
iPropertyId: 0,
sConfig: 'job', // this can be any string (20 chars) describing a config in the db

// set this to true to create buttons for debugging
debug: true, // extend Panel rather than container to see debug buttons


initComponent: function() {

//this.createStore();

var config = {
items : [{
xtype: 'propertygrid2',
itemId: 'propGrid',
//autoHeight: true,
//height: 200,
//autoWidth: true,
api: {
update: PropertyGrid.aLoad
},
//nameWidth: 150,
fields: this.fields,
source: {},
trackMouseOver: true,
// no horizontal scrollbar
viewConfig: {
forceFit: true
}
}],

store : this.newStore(),

buttons: this.debug ? [{
text: 'Load1',
scope: this,
listeners: {
'click' : function(){
this.loadConfig(1);
}.createDelegate(this)
}
},{
text: 'Load2',
scope: this,
listeners: {
'click' : function(){
this.loadConfig(2);
}.createDelegate(this)
}
},{
text: 'Load3',
scope: this,
listeners: {
'click' : function(){
this.loadConfig(3);
}.createDelegate(this)
}
},{
text: 'Save',
scope: this,
listeners: {
'click' : this.save.createDelegate(this, [this.iPropertyId])
}
},{
text: 'Reset',
scope: this,
listeners: {
'click': this.doLayout.createDelegate(this)
}
}] : ''
}; // eo config object

// apply config
Ext.apply(this, Ext.apply(this.initialConfig, config));

// call parent
LI.PropertyGrid.superclass.initComponent.apply(this, arguments);

} // eo function initComponent

,
onRender: function() {

this.loadConfig();

// call parent
LI.PropertyGrid.superclass.onRender.apply(this, arguments);

} // eo function onRender
,

newStore: function(){
var store = new Ext.data.DirectStore({
storeId: 'propertyGrid',
autoLoad: false,
api: {
read: PropertyGrid.aLoad
//update: PropertyGrid.aLoad
},
paramsAsHash: true,
totalProperty: 'total',
root: 'data',
fields: ['id',
{
name: 'xtype',
type: 'string'
},{
name: 'name',
type: 'string'
},{
name: 'value',
type: 'string'
},{
name: 'combovalues',
type: 'string'
},{
name: 'required',
type: 'integer'
}]
});

store.setBaseParam('sConfig', this.sConfig);

return store;
},

loadConfig: function( iPropertyId ) {
this.iPropertyId = iPropertyId;
console.log(iPropertyId);
console.log(this.iPropertyId);

this.store.load({
scope: this,
callback: this.createFields,
params: {
iPropertyId : this.iPropertyId
}
});
},

/**
* Save the values in the grid to the database for the passed iPropertyId (optional)
* if iPropertyId is not specified use the iPropertyId for the last loadConfig call
*
*/
save: function( iPropertyId ){

if ( typeof iPropertyId == 'number' ){
//var saveValues = this.getComponent('propGrid').getSource();
var saveValues = [];

// set the iPropertyId if passed
if ( iPropertyId ) this.iPropertyId = iPropertyId; // ALWAYS SAME AS WHEN IT IS INSTANTIATED??

// any parent component should set the propertyId before calling save on this component
if ( this.iPropertyId != 0 )
{
Ext.each(this.rawfields, function(r){
saveValues.push({
id: r.getId(),
value: r.getRawValue()
});
}, this);
//console.log(saveValues);

// Calling an Ext.Direct method can cause undesirable results such as 'too much recursion' on different line numbers.
// this can usually be fixed by using paramsAsHash:true or if making a direct call not through an api then check the parameters!
// if in doubt get the function to work with inline values such as PropertyGrid.bSave(1, [1,2]);
// Problem was found to be iPropertyId was an object not an integer
PropertyGrid.bSave(this.iPropertyId, saveValues);
}
}else{
throw "iPropertyId is not a number";
}
},

reset: function(){
this.iPropertyId = 0;
// set the value of the 'editor fields' to zero then call createFields
// which will set the values of the underlying 'rawfields' and update the
// propertygrid store
this.store.each(function( r ){
var value = r.set('value', '');
}, this);
this.createFields();
},

createFields: function() {

// initially only the config is loaded (fields i.e. each row of the grid)
// the values are loaded later (below)
if ( this.configLoaded == false )
{
this.store.each(function( r ){
//console.log(r);

var xtype = r.get('xtype');
var name = r.get('name');
var id = r.get('id');
var combovalues = r.get('combovalues')==""?"":Ext.decode(r.get('combovalues'));
var field = null;
var renderer = function(val, metadata, record, rowIndex, colIndex, store){
// if the field is required set the background as pale red
var allowBlank = record.data.field.editor.field.allowBlank;
if (val=='' && !allowBlank){
metadata.attr += ' style="background-color:red; opacity:.2; filter:alpha(opacity=20);"';
}
return val;
};
var allowBlank = r.get('required')==1?false:true;

switch ( xtype ){
case 'combo':
// make up local data store
field = new Ext.form.ComboBox({
typeAhead: false,
triggerAction: 'all',
lazyRender:false,
mode: 'local',
store: new Ext.data.JsonStore({
id: 'id',
fields: [
'id',
'config',
'value'
],
data: combovalues
}),
valueField: 'value',
displayField: 'value'
});
break;

case 'spinnerfield':
field = new Ext.ux.form.SpinnerField({});
break;

case 'datefield':
field = new Ext.form.DateField({
format: 'd/m/Y'
});
renderer = function(val, metadata, record, rowIndex, colIndex, store){
// initially the passed value is a text string in the format above.
// when the value is set by the field it is returned as a Date object
if ( Ext.isDate(val) ){
val = new Date(val);
val = val.format('d/m/Y');
}
return val;
}.createSequence(renderer);
break;

case 'numberfield':
field = new Ext.form.NumberField({});
break;

case 'checkbox':
field = new Ext.form.Checkbox({});
break;

case 'htmleditor':
field = new Ext.form.HtmlEditor({
height: 200
});
break;

case 'timefield':
field = new Ext.form.TimeField({});
break;

default:
field = new Ext.form.TextField({
selectOnFocus: true,
style: 'text-align: left;'
});
}

Ext.apply(field, {id : id, allowBlank: allowBlank, editable: false});
this.rawfields.push(field);

var editor = new Ext.grid.GridEditor(
field
);

this.fields.push({
dataIndex: id,
header: name,
editable : true,
editor: editor,
renderer: renderer
});

}, this);

this.configLoaded = true;
}

// set the values
// this is first called when there are no values
// subsequent calls contain the values (after the config was laoaded onRender)
this.values = {};
this.store.each(function( r ){
// the id of the config in property_grid_config
var id = r.get('id');
var value = r.get('value');
// set the value of the fields inside the property grid
Ext.each(this.rawfields, function(r){if(r.id==id)r.setValue(value);}, this);

// the value of the config for below
this.values[id] = value;

}, this);

//console.log(this.rawfields);

// set the values of the Property Grid, based on values of actual fields UNDERNEATH!
var propertyGrid = this.getComponent('propGrid');

//console.log(this.values);
//console.log(this.fields);
propertyGrid.load(this.values, this.fields);

}
});

Ext.reg('propertygrid', LI.PropertyGrid);


The problem is that when I call the load function and pass in a new iPropertyId, it is only changed inside the load function (i.e. if I console.log(this.iPropertyId) it is set as the new value. When I call save() using the text buttons I create near the top of the script, the value of this.iPropertyId is always 2 - i.e. the same value as when the class was instantiated. Am I missing something crucial in the way that JS works or the way that ExtJS Extends objects?

lotsofquestions
8 Apr 2010, 7:18 AM
I have tried defining iPropertyId inside initComponent and also inside the config but I still cannot change the value of it after it is instantiated, i.e. It is set inside the loadConfig() function when I echo it to the console but it is not set when I save from:



{
text: 'Save',
scope: this,
listeners: {
'click' : this.save.createDelegate(this, [this.iPropertyId])
}
}

Animal
8 Apr 2010, 7:21 AM
Why extend a layout fit Panel to get a property grid?

Why not extend a property grid?

In fact, why not just USE a property grid?

lotsofquestions
8 Apr 2010, 7:34 AM
Maybe I will change the implementation later but my original question still stands which is am I doing something wrong with the passed iPropertyId to cause the value to be fixed even if I change this.iPropertyId when calling loadConfig?

steffenk
8 Apr 2010, 7:40 AM
like always, you are not in the scope of the object inside listener. Set the scope!

You know what createDelegate does? Looks like a wild guess.

lotsofquestions
8 Apr 2010, 7:53 AM
I thought I had set the scope?
Could the button code be written differently?

steffenk
8 Apr 2010, 7:56 AM
listeners: {
'click' : function(){ ...},
scope: this
}

lotsofquestions
8 Apr 2010, 8:00 AM
I have tried this but I still get the same result:



var config = {
items : [{
xtype: 'propertygrid2',
itemId: 'propGrid',
//autoHeight: true,
//height: 200,
//autoWidth: true,
api: {
update: PropertyGrid.aLoad
},
//nameWidth: 150,
fields: this.fields,
source: {},
trackMouseOver: true,
// no horizontal scrollbar
viewConfig: {
forceFit: true
}
}],

store : this.newStore(),

buttons: this.debug ? [{
text: 'Load1',
scope: this,
listeners: {
scope: this,
'click' : function(){
this.loadConfig(1);
}.createDelegate(this)
}
},{
text: 'Load2',
scope: this,
listeners: {
scope: this,
'click' : function(){
this.loadConfig(2);
}.createDelegate(this)
}
},{
text: 'Load3',
scope: this,
listeners: {
scope: this,
'click' : function(){
this.loadConfig(3);
}.createDelegate(this)
}
},{
text: 'Save',
scope: this,
listeners: {
scope: this,
'click' : this.save.createDelegate(this, [this.iPropertyId])
}
},{
text: 'Reset',
scope: this,
listeners: {
scope: this,
'click': this.doLayout.createDelegate(this)
}
}] : ''
}; // eo config object


One thing I have noticed is that when the object renders the two console logs in loadConfig show as undefined. But I guess the iPropertyId has not been set yet?