I would like to display many different grids in their own tab panel. I also want keep both the code and memory usage as small as possible. Each grid panel will function essentially the same so I am trying to create a generic class with all the code that would be duplicated across all the grid panels. Then I can just instantiate them when needed while passing in what's different about them so they can render.

I believe I've run into scoping problems and am trying to understand how javascript scoping works especially in relation to EXT.

As you can see below I have a generic class from which I create a new object. I then set it up with the record and grid column information specific to that grid and then call the function do display it. It all seems to work fine until I call the grid doubleClick function where I can no longer seem to get ahold of the grid object (scoping issue?). In GridDoubleClick() I've tried getting the object directly: "var obj = this.grid" and getting by id: "var obj = Ext.getCmp('tab-' + this.objType + '.list');" but can't seem to get it.

If you could take a quick gander at the code below you might tell me this is completely the wrong way to go. Maybe I should go down a pre-configured object path? Some other factory design pattern? Any direction would certainly be appreciated.

Code:
GenericView = function(type,plural) {
	this.objType = type;
	this.objTypePlural = plural;
	this.dbUrl = this.objType + '.php';
	
	this.toString=this.getName=function(){ return this.objType } 
        this.DEBUG = 0;
        this.INFO  = 1;
        this.WARN  = 0;
        this.ERROR = 0;
	
	this.gridRecFields;
	this.gridSortColumn;
	this.gridColumns;
	this.gridRecCount = 25;
	this.gridRec, 
	this.gridReader;
	this.gridStore;
	this.gridToolbar;
	this.gridPager;
	this.grid;
	
    this.LoadTab = function(viewType,initialID) {
        if (this.INFO) { console.info(this.objType + ".LoadTab('" + viewType + "') called"); }
        switch(viewType) {
            case 'list': this.ListView(); break;
            case 'view': this.OneView(initialID);  break;
        }
    }

	// Helper functions
	this.RefreshGrid = function() { this.gridStore.reload(); }
	this.ViewItem = function() { 
		if ( this.grid.getSelectionModel().hasSelection() ) {
			id = this.grid.getSelectionModel().getSelected().data.id;
			this.LoadTab('view');
		} else {
			Ext.Msg.alert('Whoops!','No Record Selected!');
		}
	}
	this.GridDoubleClick = function() {
		//var obj = this.grid;
		var obj = Ext.getCmp('tab-' + this.objType + '.list');
		id = obj.getSelectionModel().getSelected().data.id;
		cmp = Ext.getCmp('content-tabs').findById('tab-'+objType+'.view');
		if ( Ext.isDefined(cmp) ) {
			Ext.getCmp('content-tabs').remove('tab-'+objType+'.view',true);
		}
		showContentTabFor(objType+'.view',id);
	}

	// Grid View
	this.ListView = function() {
		this.gridRec = Ext.data.Record.create(this.gridRecFields);
        this.gridReader = new Ext.data.JsonReader({root: 'rows', totalProperty: 'count', id: 'id'}, this.gridRec );
        this.gridStore = new Ext.data.Store({
            id: this.objType + '-list-store',
            autoDestroy: true,
            proxy: new Ext.data.HttpProxy({url:this.dbUrl,method:'POST'}),
            baseParams: {task:'list'},
            reader: this.gridReader,
            remoteSort: true,
            sortInfo: {field:this.gridSortColumn,direction:'ASC'}
        });
        this.gridStore.load({params: { start:0, limit:this.gridRecCount } });

		this.gridToolbar = new Ext.Toolbar({
			style: 'padding-top:3px;padding-bottom:3px',
			items: [
				{ xtype: 'tbtext', text : this.objType + ' List', style: 'color:#069;font-size:12pt;font-weight:bold' },
				'->', 
				'-',  { text : 'Refresh', id: 'btn-'+this.objType+'-refresh'  , iconCls : 'icon-arrow_refresh',handler: this.RefreshGrid },
				'-',  { text : 'View Selected', id: 'btn-'+this.objType+'-add' , iconCls : 'icon-add' ,handler: this.ViewItem    }
			]
		});

        this.gridPager = new Ext.PagingToolbar({
            pageSize: this.recCount,
            store: this.listStore,
            displayInfo: true,
            displayMsg: 'Viewing ' + this.objType + ' {0} - {1} of {2}',
            emptyMsg: "No " + this.objType + " to display"
        });
        
        this.grid = new Ext.grid.GridPanel({
            id: 'tab-' + this.objType + '.list',
            title: 'All ' + this.objTypePlural,
            closable: true,
            loadMask: true,
            stripeRows: true,
            store: this.gridStore,
            tbar: this.gridToolbar,
            bbar: this.gridPager,
            viewConfig: { forceFit: true },
            autoExpandColumn: 'notes',
            columns: this.gridColumns,
            listeners: { rowdblclick: this.GridDoubleClick}
        });
		
		Ext.getCmp('content-tabs').add( this.grid ).show();
	}
	
	this.OneView = function() {
		var gridRec = Ext.data.Record.create(this.gridRecFields);
	}

}

myView = new GenericView('Lender','Lenders');
myView.gridRecFields = [{name:'id'},{name:'name'},{name:'address'},{name:'address2'},{name:'city'},{name:'state'},{name:'zip'},{name:'phone'},{name:'fax'},{name:'notes'}];
myView.gridSortColumn = 'address';
myView.gridColumns = [
	{ header:'ID',          dataIndex:'id', hidden: true },
	{ header:'Lender',      dataIndex:'name'        ,width: 130 ,sortable: true },
	{ header:'Address',     dataIndex:'address'     ,width: 100 ,sortable: true },
	{ header:'Address 2',   dataIndex:'address2'    ,width: 100 },
	{ header:'City',        dataIndex:'city'        ,width: 100 ,sortable: true },
	{ header:'State',       dataIndex:'state'       ,width: 45 ,sortable: true },
	{ header:'Zip',         dataIndex:'zip'         ,width: 45 ,sortable: true },
	{ header:'Phone',       dataIndex:'phone'       ,width: 80 },
	{ header:'Fax',         dataIndex:'fax'         ,width: 80 },
	{ header:'Notes',       dataIndex:'notes', id: 'notes' }
];

myView.LoadTab('list');