PDA

View Full Version : Dynamically adding accordion panel content to dynamically created accordion panels



TW_Burger
25 Nov 2010, 12:04 PM
We have been attempting to make the following code (inherited from an old project that was abandoned, lost, swept under a desk, buried in kitty litter, found, lost again, found again, and now my problem) work correctly. The code attempts to create a set of extended accordion panels that are filled with URLS that the user can select to bring documents into the browser. The information comes from back-end handlers that read in the directories and documents in those directories.

If the directory panels are created statically everything works as expected.

If the directory panels are created dynamically the document URL content does not display in the web page although tracing through the code shows that all of it runs as expected.

Why does the static way work perfectly and the dynamic fail?

Additional: back-end code is Visual Basic built in VS2010 and uses ASP.NET.

Here is the code. Some of the original code that did not work is commented out but still included. Note the code initComponent: function () { Ext.Ajax.request({ that dynamically creates the directory panels is commented out and the code works correctly as shown. Your help is appreciated.



/// <reference path="~/portal/scripts/ext/debug/Ext.js" />
/// <reference path="~/portal/scripts/ext/debug/ext-base.js" />
/// <reference path="~/portal/scripts/ext/debug/ext-all-debug.js" />

if (!ETK.widgets.CanadaLinks)
{
Ext.ns('widgets.CanadaLinks'); // ceate a name space

Ext.Ajax.timeout = 900000; // set the ajax call timeout to 9 seconds

var AjaxURL_DOCS = '/portal/widgets/bby_canada/link_test/handlers/get/links/default.ashx';
var AjaxURL_DIRS = '/portal/widgets/bby_canada/link_test/handlers/get/links/Dir_Handler.ashx';

/**
* @class ETK.widgets.Canada
* @extends Ext.form.TabPanel
*/
ETK.widgets.CanadaLinks = Ext.extend(Ext.Panel,
{

/**
* @cfg {integer} activeTab
*/
activeTab: 0,

/**
* @cfg {bool} autoHeight
*/
autoHeight: true,

/**
* @cfg {bool} autoWidth
*/
autoWidth: true,

// defaults are applied to items, not the container
// defaults do not have precedence over
// options in config objects, so the defaults
// will not be applied to items

defaults: {
style: 'height: auto;',
collapsed: true, // if false the active tab is shown expanded
//xtype: 'Links'
},

/**
* @cfg {bool} deferrender
*/
//deferredRender: true, // drawn using deferred shading

/**
* @cfg {bool} layoutOnTabChange
*/
layoutOnTabChange: true,
/**
* @cfg {bool} resizeTabs
*/
resizeTabs: true,
/**
* @cfg {string} title (this is the top layer folder in SharePoint)
*/
title: 'Shared Documents',
/**
* @private
* @method initComponent
* First time we load this card
*/

layout: 'accordion',

layoutConfig: {
animate: true,
align: 'stretch',
pack: 'start',
titleCollapse: true
},


// define the items in the panel
initComponent: function () {

// array of items these are each separate tabs. The title needs to be exactly what the folders are in
// sharepoint

/*
// the following code attempts to create the 'Links' panels dynamically.
// It works and correctly builds the panels but the LinksView code is not called
// when the panels are selected.
// The mechanism that creates the correct objects is broken unless the static "this.items = [{"
// code created originally is used.

// An attempt was made to create an array of constructors each with the item's parameters
// but the Ajax request code is called after all of the other initComponent function code
// so the array is empty.

var folder = this.title; // use the control title as the base directory to get the document directories

//debugger; //****************************************************************

Ext.Ajax.request({

//point to the handler file
url: AjaxURL_DIRS,

callback: Ext.emptyFn,

success: function (resp, args) // resp is the response, args are the argument parameters
{
//create a json response containing the directories to dynamically create panels

//debugger; //****************************************************************

//var aPanels = new Array();
//var aPanels = [];
var dirsfromhandler = Ext.decode(resp.responseText);
var ID = '';
var i = 0;
for (i = 0; i < dirsfromhandler.number; i = i + 1) {
ID = dirsfromhandler.nodes[i].title;
ID = ID.split(' ').join(''); // no spaces allowed in the item ID
//aPanels.push(
//aPanels[i] = [
//this.items.add(
this.add(
new Ext.Panel(
{
itemId: ID,
title: dirsfromhandler.nodes[i].title,
xtype: 'Links' //An xtype is a symbolic name given to a class.
//,border: true
}
)
);
//];
}

// this.items = [];
// for (var i = 0; i < aPanels.length; i++) {
// this.items[i] = aPanels[i];
// }

//this.items = aPanels;

this.doLayout();
},

// define the arguments passed in by the args paramter in the AJAX request.
params: {
//using the names of the folders that are passed in from the activate listener
folder: folder
},

// on failure of the ajax call popup a messagebox
failure: function (resp, args) {

//debugger; //******************************************************************

// note that this is rendered as HTML which ignores \n as new lines so insert
// HTML <br> line breaks
var mssg = "Error: " + (resp.responseText == undefined) ? 'No detail avalilable' : resp.responseText + "<br>URL:" + AjaxURL_DIRS + "<br>Folder: " + args.params.folder;

Ext.MessageBox.show({
title: "Ajax call for directories failed",
msg: mssg,
buttons: Ext.MessageBox.OK,
icon: Ext.MessageBox.ERROR
});

},

scope: this // without this nothing will work

});

*/


// this code is the original that creates 'Links' panels that will be created as
// LinkView and run the LinkView code below
this.items = [{
itemId: '1',
title: 'Test Folder 1',
xtype: 'Links' // An xtype is a symbolic name given to a class.
}, {
itemId: '2',
title: 'Test Folder 2',
xtype: 'Links'
}, {
itemId: '3',
title: 'Test Folder 3',
xtype: 'Links'
}
];

ETK.widgets.CanadaLinks.superclass.initComponent.call(this);
} // initcomponent

}); // end of creation of ETK.widgets.CanadaLinks


/**
* @class ETK.widgets.Canada.LinkView
* @extends Ext.DataView
*/
ETK.widgets.CanadaLinks.LinkView = Ext.extend(Ext.Panel,
{
/**
* @cfg {bool} autoHeight
*/
autoHeight: true,
/**
* @cfg {string} emptyText
*/
emptyText: 'There are no links at this time.',
/**
* @cfg {string} itemSelector (needs to be here. JavaScript throws an error on the template if not)
*/
//itemSelector: 'div.noSelector', // TWB - seems to have no effect
/**
* @cfg {object} listeners
*/

// This is a list of functions that are run when an event is 'heard'
listeners:
{
// The expand event is when an accordian panel is left clicked.
// This code uses the controlling panel name and the name of the subpanel to
// create a request event with these two parameters which will be used to create
// subpanel content which will be URLs pointing to the sharepoint documents.
expand: function () {

//debugger; //*****************************************

// the folder is the tile of the parent/owner control panel object
var folder = this.ownerCt.title;
// the subfolder is the title name of the sub-panel item
var subfolder = this.title;
// so both must match the folder name in Sharepoint

if (this.activated !== true) {
this.activated = true;
//in this function we do the ajax call. Folder comes from the top
//level title and sub folder is the title for each tab.

//debugger; //*****************************************

this.request(folder, subfolder);
}
}
},

/**
* @cfg {string} style
*/
style: 'padding: 5px;',
/**
* @private
* @method initComponent
* First time we load this card
*/
initComponent: function () {

/**
* @cfg {object} store
*/

//debugger; //*************************

/*
this.store = new Ext.data.JsonStore({
autoLoad: false,
root: 'nodes',
fields: [
{ name: 'title' },
{ name: 'url' }
]
});
*/

/**
* @cfg {object} tpl (this sets up the layout of the card and fills in the values with the
response from the ajax call in the store)
*/

//debugger; //****************************************************************

/*
this.tpl = new Ext.XTemplate(
'<div style=\"height:300px\">',
'<tpl if="values[0].title == \'\' ">',
'<tpl for".">',
'<div>There are no links at this time</div>',
'</tpl>',
'</tpl>',
'<tpl if="values.length &gt; 0 ">',
'<tpl for=".">',
'<div><a href="{url}">{title}</a></div>',
'</tpl>',
'</tpl>',
'</div>'
);
*/

ETK.widgets.CanadaLinks.LinkView.superclass.initComponent.call(this);
},

//
request: function (folder, subfolder) {
Ext.Ajax.request({

// when the request completes call this function
callback: Ext.emptyFn,

//point to the handler file
url: AjaxURL_DOCS,

success: function (resp, args) // resp is the response, args are the argument parameters
{
//load the json response into the store

//debugger; //****************************************************************

var textfromhandler = Ext.decode(resp.responseText);

//this.store.loadData(textfromhandler, false); // true - add to existing records, false - add new
//this.store.loadData(Ext.decode(r.responseText));

//console.log(this.tpl);
//console.log(Ext.decode(r.responseText));

var i = 0;
var url = '';
for (i = 0; i < textfromhandler.number; i = i + 1) {
url = '<div><a href="' + textfromhandler.nodes[i].url + '">' + textfromhandler.nodes[i].title + '</a></div>';
this.add(new Ext.Panel(
{
html: url
}
));
}

this.doLayout();
},

// define the arguments passed in by the args paramter in the AJAX request.
params: {
//using the names of the folders that are passed in from the activate listener
folder: folder,
subfolder: subfolder
},

// on failure of the ajax call popup a messagebox
failure: function (resp, args) {

// debugger; //******************************************************************

// note that this is rendered as HTML which ignores \n as new lines so insert
// HTML <br> line breaks
var mssg = "Error: " + (resp.responseText == undefined) ? 'No detail avalilable' : resp.responseText + "<br>URL:" + AjaxURL_DOCS + "<br>Folder: " + args.params.folder + "<br>Subfolder: " +
args.params.subfolder;

Ext.MessageBox.show({
title: "Ajax call for documents failed",
msg: mssg,
buttons: Ext.MessageBox.OK,
icon: Ext.MessageBox.ERROR
});
},

scope: this
});
}

}); // end of ETK.widgets.CanadaLinks.LinkView creation

//register the xtype. An xtype is a symbolic name given to a class.
Ext.reg('LinkTest', ETK.widgets.CanadaLinks);
Ext.reg('Links', ETK.widgets.CanadaLinks.LinkView); // associates this panel with 'Links' panels

}

Condor
27 Nov 2010, 7:29 AM
I think you are running into sizing problems because of your autoHeight/autoWidth/style:'height:auto' use.

How should these panels actually be sized?

TW_Burger
27 Nov 2010, 3:59 PM
Thanks Condor,

Yes, I felt that the problem may be that the data is in place but that it simply was not showing due to differences in the display defaults when creating the panels dynamically.

I am finding ExtJS incredibly difficult to work with. Almost there are no examples that match anything near to what I am trying to achieve, large parts of the documentation are incomplete, and every example in every site uses static techniques. Well, if the world was built like that we would not need computers. Books work really well for storing unchanging information. I build all of my apps to be data driven, not to force the data to conform and be limited by the code.

The widget project is an inherited app that has to match the parent company's information framework so I'm having to struggle through ExtJS and make it work (I think I am the third or fourth person to tackle this). Otherwise I would knock this out in an afternoon using C# ASP.Net or Silverlight.

There is one good source of ExtJS examples. It's Google Code and Code Search.

http://code.google.com/p/extjs-public/
http://googleajaxsearchapi.blogspot.com/2009/06/ext-core-ready-to-go.html
http://www.google.com/codesearch

This has been a big help. I built a fairly complete ajax driven directory tree using an extended treepanel object yesterday (although I had to adapt the 3.3 code to my 2.2 release I have to use). The SharePoint access backend code I inherited is a bit messed up but the front end works fine.

Again, thanks for the tip, I will look over the code and let you know what I find.