PDA

View Full Version : Create my own widget



independent
26 Nov 2007, 10:14 AM
I've been working with dojo and there I can easily create my own widgets building a HTML template and adding to a js the functionality I need. I want to know how to create my own widgets using Ext if that's is possible.

Thanks.

tryanDLS
26 Nov 2007, 10:22 AM
I'd say yes, but you'll have to provide some detail as to what you're trying to accomplish so folks can offer input.

Foggy
26 Nov 2007, 10:26 AM
I think Sakis tutorial would be a great start for you ;)
http://extjs.com/learn/Tutorial:Extending_Ext_Class

26 Nov 2007, 10:39 AM
I've been working with dojo and there I can easily create my own widgets building a HTML template and adding to a js the functionality I need. I want to know how to create my own widgets using Ext if that's is possible.

Thanks.

Tim's right. Your question is waaaaaaay too vague. What type of wedgies are you trying to produce?

independent
26 Nov 2007, 11:02 AM
For example: in dojo I can build a widget with many components inside, including another widgets (textfields, combos, textareas, etc.) and I can add to the widget all the functionality I want.

Ex: Having inside my widget a textfield and a combo if I choose some value from combo and I want to show that value automatically in the textfield, I can add that functionality to my widget and I don't have to do a function on a js to do that. That's an small an easy example, but I could want to do something else more complicated and I have to use that in many parts of my application for example and creating my own widget will help me to reuse code and avoid me to rewrite the same thing in different js.

Sorry if I'm not very clear expressing my ideas, but I'm learning english right now. Thanks.

tryanDLS
26 Nov 2007, 11:07 AM
I think you really need to take a step back and understand the components of Ext before you go trying to build some complex widget. Look at the examples and the tutorials and understand how to put things together.

independent
26 Nov 2007, 11:15 AM
I'll do that, maybe I'm missing something, thanks anyway...

Animal
26 Nov 2007, 11:21 AM
Sounds like you're just wanting to build a form.

In Ext 2, any Component subclass can be added to any Container subclass. So adding stuff into things is a piece of cake.

independent
26 Nov 2007, 11:34 AM
Sounds like you're just wanting to build a form.

In Ext 2, any Component subclass can be added to any Container subclass. So adding stuff into things is a piece of cake.
I just want to put many Components together in just one Component and add to that new Component the functionalities I need or I want. For example: I want to put a textfield, a textarea and a combo all together in one component created by me named MyComponent and then add to this component many functionalities. After that I just want to use this component like I use another component of Ext.

Maybe I'm not explaining myself very well...

26 Nov 2007, 11:47 AM
Ah ok.

It's easy. Create an object and include all of the components that you're using.

One of my newest ones contains:
Gridpanel with paging toolbar
Window with tabbed form
row context menues
custom ajax functions

to call it, i just do:
var appDetailsPanel = new cmdbAppDetailsGrid(jsonData.hostData[0].CMDB_ID,' Associated Applications');


:)

independent
26 Nov 2007, 11:59 AM
djliquidice, could you share the source of some component like that?? It will help me a lot to learn how to do that, I'm just starting with Ext and an example will be very useful...

Thanks

26 Nov 2007, 12:35 PM
This is pretty big, but is completely OO.
Look at the doTabForm, doGrid, doFormWindow methods

You can see it in action:
http://tdg-i.com/img/extjs/complex_tab_object.swf

I'm warning you that this is huge and will not look 100% formatted here. I suggest copying and pasting in an editor.


var cmdbAppDetailsGrid = function(hostId, title){
this.hostId = hostId || null;
this.gridTitle = title || null;
this.gridTab = false;
this.ds = false;
this.dsLimit = 35;
this.pagingCombo = false;
this.cm = false;
this.gridView = false;
this.grid = false;
this.caqGridFoot = false;
this.paging = false;
this.recipients = false;
this.outputType = false;
this.parentEl = false;
this.appDescEditorWindow = false;
this.appForm = false;
this.globalRowIndex = false;
this.ctxMenuRecord = false;
};

cmdbAppDetailsGrid.prototype = {

setGridLimit : function (record) {
this.dsLimit = record;
//Ext.MessageBox.alert('num', dsLimit);
this.paging.pageSize = record;
//alert(paging.pageSize);//= dsLimit;
this.parent.refreshGrid();
},
pagingGridComboBoxSelectHandler : function (combo, record, index) {
this.setGridLimit(record.data.num);
},


appBRSRenderer : function (val) {
if (val) {
if (val == 0) {
return('Is NOT required for BRS');
}
else if (val == 1) {
return('IS required for BRS');
}
}
},
doGrid : function(hostname, el, masterPanel){
var ds;
var dsLimit;
if (! this.ds) {

// Data Store
this.ds = new Ext.data.Store({
// load using script tags for cross domain, if the data in on the same domain as
// this page, an HttpProxy would be better
proxy: new Ext.data.ScriptTagProxy({
url: 'cmdbAppDetails.php?action=query&hostId=' + this.hostId,

timeout: 1000000
}),

// create reader that reads the Topic records
reader: new Ext.data.JsonReader({
root : 'records',
totalProperty : 'totalCount',
id : 'test'
}, [
{name: 'CMDB_ID' , mapping: 'CMDB_ID'},
{name: 'APPLICATION' , mapping: 'APPLICATION'},
{name: 'APP_DESCRIPTION' , mapping: 'APP_DESCRIPTION'},
{name: 'APP_SCOPE' , mapping: 'APP_SCOPE'},
{name: 'APP_AKA' , mapping: 'APP_AKA'},
{name: 'APP_SVCS_LEAD' , mapping: 'APP_SVCS_LEAD'},
{name: 'APP_BRS' , mapping: 'APP_BRS'},
{name: 'APP_OUTAGE_WINDOW' , mapping: 'APP_OUTAGE_WINDOW'}
]),
// turn on remote sorting
remoteSort: false
});
ds = this.ds;
dsLimit = this.dsLimit;

this.cm = new Ext.grid.ColumnModel([{
id: 'CMDB_ID',
header: "CMDB_ID",
dataIndex: 'CMDB_ID',
hidden: true,
width: 50
},{
id: 'APPLICATION', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
header: "App Name",
dataIndex: 'APPLICATION',
width: 220
},{
id: 'APP_DESCRIPTION', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
header: "Description",
dataIndex: 'APP_DESCRIPTION',
autoWidth: true
},{
id: 'APP_SCOPE',
header: "Scope/Impact",
dataIndex: 'APP_SCOPE',
width: 107
},{
id : 'APP_AKA',
header: "AKA",
dataIndex: 'APP_AKA',
width: 100
},{
id : 'APP_SVCS_LEAD',
dataIndex: "APP_SVCS_LEAD",
header: 'App Services Contact',
width: 100
},{
id: 'APP_BRS',
header: "BRS",
align: 'center',
dataIndex: 'APP_BRS',
renderer : this.appBRSRenderer,
width: 50
},{
id: 'APP_OUTAGE_WINDOW',
header: 'Outage Window(s)',
dataIndex: 'APP_OUTAGE_WINDOW',
width: 100
}]);
this.gridView = new Ext.grid.GridView({
//forceFit: true,
getRowClass : function (row, index) {
var cls = '';
var data = row.data;

if (! data.APP_DESCRIPTION) {
cls = 'appDetailsGridNoDescription';
}
return cls;
}
});

var opsMenu = new Ext.menu.Menu({
items : [
new Ext.menu.Item({
cls: 'x-btn-text-icon bmenu', // icon and text class
pressed: false,
enableToggle: false,
icon: 'img/toolbar/silk_icons/icons/database_connect.png',
pressed: false,
text: 'Edit Details for',
scope : this,
handler: function () {
this.doFormWindow(this.ctxMenuRecord);
}
}),
new Ext.menu.Item({
cls: 'x-btn-text-icon bmenu', // icon and text class
pressed: false,
enableToggle: false,
icon: 'img/toolbar/silk_icons/icons/database_connect.png',
pressed: false,
text: 'Query CMDB',
scope : this,
handler: this.doCMDBQuery
})
]

});


// add a paging toolbar to the caqGrid's footer
this.paging = new Ext.PagingToolbar({
store: this.ds,
pageSize: this.dsLimit,
displayInfo: true,
autoWidth: true,
displayMsg: 'Applications {0} - {1} of {2}',
emptyMsg: "No Applicatinos to display"
});

this.grid = new Ext.grid.GridPanel({
ds : this.ds,
cm : this.cm,
monitorResize : true,
selModel : new Ext.grid.RowSelectionModel({singleSelect:true}),
autoExpandColumn: 'APP_DESCRIPTION',
frame : false,
layout : 'fit',
stripeRows : true,
title : this.gridTitle,
loadMask : false,
tbar : this.paging,
view : this.gridView

});

var doFormWindow = this.doFormWindow;

this.grid.on('render', function () {
ds.load({params:{
start:0,
limit: dsLimit
}
});
});
this.grid.on('rowclick', this.prepareData, this);

this.grid.on('rowdblclick', function(grid, rowIndex, evt) {

if (typeof(rowIndex) == 'number') {
var record = ds.getAt(rowIndex);
if (record) {
this.globalRowIndex = rowIndex;
this.doFormWindow(record);
}
}

}, this);

this.grid.on('rowcontextmenu', function(grid, rowIndex, e) {
e.stopEvent(); // Stops the browser context menu from showing.

this.ctxMenuRow = this.grid.getView().getRow(rowIndex);
this.ctxMenuRecord = this.ds.getAt(rowIndex);

Ext.fly(this.ctxMenuRow).addClass('x-node-ctx');
opsMenu.items.items[0].setText('Edit Details: ' + this.ctxMenuRecord.json.APPLICATION);
opsMenu.items.items[1].setText('uCMDB Query: ' + this.ctxMenuRecord.json.APPLICATION);
opsMenu.showAt(e.getXY());

},this);
}

this.ds.load({
params:{
start:0,
limit:this.dsLimit
}
});
this.dataLoaded = true;
return(this.grid);
},
refreshGridFromCombo : function () {
if (pagingCombo.isValid()) {
setGridLimit(parseInt(pagingCombo.getRawValue()));
}
},
refreshGrid : function () {
//this.doGrid();
ds.load({params:{start:0, limit:dsLimit}});
},
prepareData : function (grid, rowIndex, e) {
return(false);
preDisplayId = ds.data.items[rowIndex].id;
preDisplayData = ds.getById(preDisplayId);
},
doTabForm : function (data) {
var formPanel = new Ext.FormPanel({
labelAlign: 'top',
bodyStyle:'padding:5px',
frame: true,
width: 580,
items: [
{
xtype : 'hidden'
},
new Ext.form.ComboBox({
store: new Ext.data.SimpleStore({
fields: ['brsNum', 'brsText'],
data : [
['0', 'Is NOT required for BRS'],
['1', 'IS required for BRS']
]
}),
//id : 'appBRS',
//name : 'appBRS',
width : 300,
fieldLabel : 'Select BRS Status',
displayField :'brsText',
valueField :'brsNum',
mode : 'local',
forceSelection : true,
selectOnFocus : true,
triggerAction : 'all',
emptyText : 'Please Select',
selectOnFocus : true,
allowBlank : false,
editable : false
}),{
xtype:'tabpanel',
//id : 'appDescFormWindowTabPanel',
plain:true,
activeTab: 0,
height: 250,
width: 560,
defaults:{bodyStyle:'padding:4px'},
items:[{
cls:'x-plain',
title:'Description',
deferredRender : false,
tabTip: 'This field is used to specify application description. What does this application do for Marriott?',
layout: 'fit',
items: {
xtype:'htmleditor',
enableSourceEdit: false,
enableLinks : false,
deferredRender : false,
enableAlignments: false
//id:'appDescription',
//fieldLabel:'appDescription'
}
},{
cls:'x-plain',
deferredRender : false,
title:'Scope/Impact',
layout: 'fit',
tabTip: 'This field is used to specify application scope or business service impact. Who are the customers? Is this mission critical?',
items: {
xtype:'htmleditor',
deferredRender : false,
enableSourceEdit: false,
enableLinks : false,
enableAlignments: false
}
},{
cls:'x-plain',
title:'AKA',
deferredRender : false,
tabTip: 'This field is used to specify application synonyms or acronyms. Please separate each term or name with commas. Example: "Marriott.com, dotcom, .com".',
layout:'fit',
items: {
xtype:'htmleditor',
enableSourceEdit: false,
enableLinks : false,
enableAlignments: false
}
},{
cls:'x-plain',
title:'Svcs Contact',
tabTip: 'This field specifies the Director level contact for this application. Eventually, this will be automatically populated by the 5th contact from the contacts section.',
layout:'fit',
items: {
xtype:'htmleditor',
enableSourceEdit: false,
enableLinks : false,
enableAlignments: false
}
},{
cls:'x-plain',
title:'Outage Window(s)',
tabTip: 'This field is used to specify application scheduled outage or maintenance windows. If unsure, put 8PM - 6AM Daily.',
layout:'fit',
items: {
xtype:'htmleditor',
enableSourceEdit: false,
enableLinks : false,
enableAlignments: false
}
}]
}]


});
return(formPanel);
},
doFormWindow : function (record, rowIndex, readonly) {

if (! this.appDescEditorWindow) {


if (Ext.isIE6) {
var width = 450;
}
else if (Ext.isGecko) {
var width = 470;
}
else {
var width = 480;
}

this.appFormPanel = this.doTabForm();

this.appDescEditorWindow = new Ext.Window({
animateTarget : this.grid.body.id,
layout : 'fit',
width : 600,
height : 400,
closeAction : 'hide',
plain : true,
modal : true,
items : [ this.appFormPanel ],
buttons : [{
text: 'Save',
cls:"x-btn-text-icon",
icon: 'img/toolbar/silk_icons/icons/disk.png',
scope : this,
handler: function () {
if (this.appFormPanel.form.isValid()) {
var formItems = this.appFormPanel.form.items.items;

var appDetailsAppID = formItems[0].getValue();
var appBRS = formItems[1].getValue();
var appDescription = formItems[2].getValue();
var appScopeImpact = formItems[3].getValue();
var appAKA = formItems[4].getValue();
var appSvcsContact = formItems[5].getValue();
var appOutageWindows = formItems[6].getValue();

if (appDescription.length > 1000) {
Ext.MessageBox.alert('Error', 'The description field is too long. Please reduce it\'s size to 1,024 characters or less.');
return(false);
}
if (appScopeImpact.length > 1000) {
Ext.MessageBox.alert('Error', 'The Scope/Impact field is too long. Please reduce it\'s size to 1,024 characters or less.');
return(false);
}
if (appAKA.length > 1000) {
Ext.MessageBox.alert('Error', 'The AKA field is too long. Please reduce it\'s size to 1,024 characters or less.');
return(false);
}
if (appSvcsContact.length > 1000) {
Ext.MessageBox.alert('Error', 'The Svcs Contact field is too long. Please reduce it\'s size to 1,024 characters or less.');
return(false);
}
if (appOutageWindows.length > 1000) {
Ext.MessageBox.alert('Error', 'The Outage Window(s) field is too long. Please reduce it\'s size to 1,024 characters or less.');
return(false);
}

var data = {
appDetailsAppID : appDetailsAppID,
appBRS : appBRS,
appDescription : appDescription,
appScopeImpact : appScopeImpact,
appAKA : appAKA,
appSvcsContact : appSvcsContact,
appOutageWindows : appOutageWindows
}
var urlData = Ext.urlEncode(data);

this.appFormPanel.form.submit({
url : 'cmdbAppDetails.php?action=modify&' + urlData,
scope : this,
success : function () {
var record = this.ds.getAt(this.globalRowIndex);
record.beginEdit();
record.data.APP_DESCRIPTION = data.appDescription;
record.data.APP_SCOPE = data.appScopeImpact;
record.data.APP_AKA = data.appAKA;
record.data.APP_SVCS_LEAD = data.appSvcsContact;
record.data.APP_BRS = data.appBRS;
record.data.APP_OUTAGE_WINDOW = data.appOutageWindows;

record.json.APP_DESCRIPTION = data.appDescription;
record.json.APP_SCOPE = data.appScopeImpact;
record.json.APP_AKA = data.appAKA;
record.json.APP_SVCS_LEAD = data.appSvcsContact;
record.json.APP_BRS = data.appBRS;
record.json.APP_OUTAGE_WINDOW = data.appOutageWindows;

record.commit();
this.ds.commitChanges();
this.appDescEditorWindow.hide();
},
failure : function () {
alert('failed');
}
});
}

}

},{
text: 'Cancel',
cls:"x-btn-text-icon",
icon: 'img/toolbar/silk_icons/icons/stop.png',
scope : this, // IMPORTANT
handler : function () {
this.appDescEditorWindow.hide();
}
}]
});

}
this.appDescEditorWindow.setTitle('Edit: ' + record.json.APPLICATION);

this.appDescEditorWindow.show();
var record = this.ds.getAt(this.globalRowIndex);

if (record) {
var formItems = this.appFormPanel.form.items.items;
formItems[0].setValue(record.json.CMDB_ID);
formItems[1].setValue(record.json.APP_BRS);
formItems[2].setValue(record.json.APP_DESCRIPTION);
formItems[3].setValue(record.json.APP_SCOPE);
formItems[4].setValue(record.json.APP_AKA);
formItems[5].setValue(record.json.APP_SVCS_LEAD);
formItems[6].setValue(record.json.APP_OUTAGE_WINDOW);
}
else {
console.log(this.appFormPanel);
this.appFormPanel.form.reset();
}

this.appFormPanel.items.items[2].setActiveTab(0);

if (readonly) {
this.appFormPanel.form.items.map.appBRS.disable();
this.appDescEditorWindow.buttons[0].disable();
}
else {
//this.appFormPanel.form.items.map.appAKA.enable();
//this.appDescEditorWindow.buttons[0].enable();
}

},
doCMDBQuery : function () {
//console.log(this.ctxMenuRecord);
if (! this.ds) {
Ext.MessageBox.alert('<img src="img/toolbar/silk_icons/icons/exclamation.png"> Error!', "Yikes!");
return(false);
}
bodyLayout.doCmdbQuery('application', this.ctxMenuRecord.json.APPLICATION);
},

hideWindow : function () {
this.appDescEditorWindow.hide();
}

};

independent
26 Nov 2007, 12:43 PM
djliquidice, thanks a lot...

26 Nov 2007, 12:56 PM
You're absolutely welcome. Always nice to see someone convert to EXT :)


On a side note, thaks to ext's architecture, you can add it to any panel :)

this is one block of my master code:


var details = formatHostDetailed(jsonData.hostData[0]);
var appDetailsPanel = new cmdbAppDetailsGrid(jsonData.hostData[0].CMDB_ID,'Associated Applications'); //<-here
grid24HrEvents = alarmGrid.doGrid(jsonData.hostname,'',northTabPanel)
northTabPanelItems = [
this.doNwGrid(jsonData),
this.doFSGrid(jsonData)
];
var centerTabPanelItems = [
appDetailsPanel.doGrid(), //<-- here
this.doDbGrid(jsonData),
grid24HrEvents,
doMarnnicsPanel(jsonData.hostname, jsonData.hostname)
];