ExtJS 4.1 : issue in establishing a reference to an object - javascript

Good day everybody,
I have a recurrent problem when I work with ExtJS 4.1: I do a lot of effort every time I have to establish a reference to an object and often, when I call up a method on an object, I get an error like this:
Uncaught TypeError: Cannot call method 'destroy' of undefined
For instance, consider the following situation where I have a fieldset which contains two items: a fieldcontainer and a button.
My purpose is writing a proper handler function for the button, so that when I hit the button the fieldcontainer will be destroyed. To do that, I need to establish a correct reference to the fieldcontainer.
Here's my code:
xtype: 'fieldset',
id: 'product_fieldset',
title: 'Prodotti tempi e quantita',
defaultType: 'textfield',
layout: 'anchor',
items: [{
xtype: 'fieldcontainer',
layout: 'hbox',
defaultType: 'textfield',
defaults: {
labelAlign: 'top'
},
items: [{
xtype: 'combo',
name: 'product',
fieldLabel: 'Product',
forceSelection: true,
editable: false,
store: products,
queryMode: 'local',
displayField: 'name',
valueField: 'name',
allowBlank: false,
afterLabelTextTpl: required
},{
xtype: 'numberfield',
name: 'p_on_weight',
fieldLabel: '% on weight',
value: 0,
minValue: 0,
allowBlank: false,
afterLabelTextTpl: required,
hideTrigger: true,
keyNavEnabled: false,
mouseWheelEnabled: false
},{
xtype: 'numberfield',
name: 'time',
fieldLabel: 'Time (minutes)',
value: 0,
minValue: 0,
allowBlank: false,
afterLabelTextTpl: required,
hideTrigger: true,
keyNavEnabled: false,
mouseWheelEnabled: false
},{
xtype: 'numberfield',
name: 'ph',
fieldLabel: 'Ph',
minValue: 0,
allowBlank: false,
afterLabelTextTpl: required,
hideTrigger: true,
keyNavEnabled: false,
mouseWheelEnabled: false
},{
xtype: 'textareafield',
name: 'remarks',
fieldLabel: 'Remarks'
}]
},{
xtype: 'button',
text: 'Delete this product',
handler: function() {
proper_reference_to_fieldcontainer.destroy();
//need help for previous line
}
}]
Well, Can anyone suggest me a way to refer to fieldcontainer, possibly without using fieldcontainer's id ? (Sencha architects suggest not to use id to establish references).
Thanks in advance.
Enrico.

You can define the container as a standalone object:
var myFieldContainer = Ext.Create('Ext.form.FieldContainer', {
layout: 'hbox',
defaultType: 'textfield',
defaults: {
labelAlign: 'top'
},
items: [{
xtype: 'combo',
(...)
});
...and then use it in your button's configuration:
{
xtype: 'button',
text: 'Delete this product',
handler: function () {
myFieldContainer.destroy();
}
}

Use first define an id value for fieldcontainer,
xtype: 'fieldcontainer',
id: 'my_id',
layout: 'hbox',
Now use Ext.getCmp('my_id') to retrieve a reference to it.

Related

Extjs fieldLabel in Ext.tree.Panel

I would like to have a "welcome text" before the directory tree in my Ext.tree.Panel, so something like that:
I wrote this code, but it doesn't work:
Ext.define('MyProject.view.permissions.Example', {
extend: 'Ext.tree.Panel',
requires: [
'MyProject.view.permissions.ExampleController'
],
controller: 'example',
xtype: 'exampleWindow',
store: 'examplePermissionTree',
rootVisible: false,
rowLines: false,
//headerPosition: 'left',
lines: false,
autoLoad: false,
autoExpand: false,
items :[{
xtype: 'displayfield',
fieldLabel: 'welcome text',
name: 'welcome',
}],
columns: {
items: [ {
xtype: 'treecolumn',
dataIndex: 'text',
flex: 1
}, {
xtype: 'booleancolumn',
flex: 0.3,
dataIndex: 'granted',
trueText: Strings.permissionGranted,
falseText: Strings.permissionNotGranted
}, {
xtype: 'widgetcolumn',
flex: 0.2,
widget: {
xtype: 'button',
handler: 'onGroupClick',
text: Strings.permissionGrant
}
}
]
}
});
My problem is that the text doesn't appear. It appears only the directory tree.
How Could I fix it? Should I use another approach?
1. Use Tools instead of items
Using tools instead of items can solve the problem. An array of Ext.panel.Tool configs/instances to be added to the header tool area. The code should be like
tools :[{
xtype: 'displayfield',
fieldLabel: 'welcome text',
name: 'welcome',
}],
2. Use label in lieu of displayfield
tools :[{
xtype: 'label',
fieldLabel: 'welcome text',
name: 'welcome',
}],

TypeError: p is undefined when using xtype: 'treepicker'. Extjs6

In the record editing window, I need to use the tree selector, for this, the file Ext.ux.TreePicker is included in the app.js file, which is located in the app folder on the same level as the app.js file.
Ext.Loader.setConfig({enabled:true});
Ext.Loader.setPath('Ext.ux', 'app');
Ext.application({
extend: 'Ext.app.Application',
name: 'App',
appFolder: 'app',
requires: ['Ext.ux.TreePicker'],
...
In the record editing window, set the xtype: 'treepicker' field:
Ext.define('App.view.OperationEdit', {
extend: 'Ext.window.Window',
xtype: 'operation-edit',
alias: 'widget.operationedit',
controller: 'operation_controller',
viewModel: {
type: 'operation_model'
},
defaults: {
xtype: 'textfield',
margin: 10,
labelAlign: 'top'
},
closable: true,
items: [{
xtype: 'form',
items: [
{
xtype: 'treepicker',
store: Ext.data.StoreManager.get('StorageStore'),
fieldLabel: "Mesto_hraneniya",
valueField: 'id',
displayField: 'text',
selectChildren: true,
canSelectFolders: true,
name: 'mesto_hraneniya'
},
......
When I open the edit window, I get an error:
TypeError: p is undefined
Example link Fiddle
Why does an error appear? How to display the treepicker field correctly?
thank
The problem in your code, at least in your fiddle is that you defined the "edit form" as fully json, which will be parsed and executed on load time. Since, there is no StorageStore at load time, store parameter of treepicker will be null and that is the reason you get an error. Proper way would be to set form items on object instantiaton as follows, and the working fiddle is here.
Ext.define('App.view.TestEdit', {
extend: 'Ext.window.Window',
xtype: 'test-edit',
alias: 'widget.testedit',
requires: ['App.store.StorageStore'],
controller: 'app_view_testgrid',
defaults: {
xtype: 'textfield',
margin: 10,
labelAlign: 'top'
},
closable: true,
items: [],
initConfig: function(config){
config = config || {};
config.items = [
{
xtype: 'form',
items: [{
xtype: 'combobox',
store: {
type: 'type-store'
},
fieldLabel: 'Type',
displayField: 'name',
valueField: 'id',
name: 'id_type',
reference: 'mycombo',
}, {
xtype: 'textfield',
fieldLabel: 'My field',
name: 'mytextfield'
}, {
xtype: 'treepicker',
store: Ext.data.StoreManager.get("StorageStore"),
fieldLabel: "Mesto_hraneniya",
valueField: 'id',
displayField: 'text',
selectChildren: true,
canSelectFolders: true,
name: 'mesto_hraneniya'
}, {
xtype: 'button',
minWidth: 70,
text: 'Save',
listeners: {
click: 'saveRecord'
}
}]
}
];
this.callParent(arguments);
}
});

Tab/Vbox layout

I have an app that uses a Tab layout with the same grid panel shared as an xtype widget between each form panel bound to each tab.
My Main tab layout is as follows:
Ext.define('cardioCatalogQT.view.main.Main', {
extend: 'Ext.tab.Panel',
xtype: 'main-view',
controller: 'main-view',
requires: [
'cardioCatalogQT.view.main.MainController',
'cardioCatalogQT.view.main.MainModel',
'Ext.ux.form.ItemSelector',
'Ext.tip.QuickTipManager',
'Ext.layout.container.Card'
],
style: 'background-color:#dfe8f5;',
width: '100%',
height: 400,
layout: 'vbox',
defaults: {
bodyPadding: 5
},
items: [{
title:'Main',
region: 'south',
xtype: 'form',
itemId: 'Ajax',
flex: 1,
styleHtmlContent: true,
items:[{
xtype: 'image',
src: 'resources/images/R3D3.png',
height: 50,
width: 280
},{
title: 'Ad Hoc Sandbox for Cohort Discovery'
}] ,
lbar:[{
text: 'Initiate advanced request',
xtype: 'button',
handler: function(button){
var url = 'https://url_here';
//cardioCatalogQT.service.UtilityService.http_auth(button);
window.open(url);
}
}]
},
/*{
xtype: 'resultsGrid'
//disabled: true
},*/
/*{
xtype: 'searchGrid'
//disabled: true
},*/
{
xtype: 'demographicGrid'
//disabled: true
},
{
xtype: 'vitalGrid'
//disabled: true
},
{
xtype: 'labGrid'
//disabled: true
},
{
xtype: 'diagnosisGrid'
//disabled: true
},
{
xtype: 'medicationGrid'
//disabled: true
},
{
xtype: 'procedureGrid'
//disabled: true
},
{
xtype: 'queryGrid'
//disabled: true
}
]
});
The individual tabs that share the same grid widget (specifically, demographicGrid, vitalGrid, labGrid, diagnosisGrid, procedureGrid and medicationGrid, each referenced by xtype in the main view) look like:
/**
* Widget with template to render to Main view
*/
Ext.define('cardioCatalogQT.view.grid.DemographicGrid', {
extend: 'Ext.form.Panel',
alias: 'widget.demographicGrid',
itemId: 'demographicGrid',
store: 'Payload',
requires: [
'cardioCatalogQT.view.main.MainController'
],
config: {
variableHeights: false,
title: 'Demographics',
xtype: 'form',
width: 200,
bodyPadding: 10,
defaults: {
anchor: '100%',
labelWidth: 100
},
// inline buttons
dockedItems: [ {
xtype: 'toolbar',
height: 100,
items: [{
xtype: 'button',
text: 'Constrain sex',
itemId: 'showSex',
hidden: false,
listeners: {
click: function (button) {
button.up('grid').down('#sexValue').show();
button.up('grid').down('#hideSex').show();
button.up('grid').down('#showSex').hide();
}
}
}, {
xtype: 'button',
text: 'Hide sex constraint',
itemId: 'hideSex',
hidden: true,
listeners: {
click: function (button) {
button.up('grid').down('#sexValue').hide();
button.up('grid').down('#sexValue').setValue('');
button.up('grid').down('#hideSex').hide();
button.up('grid').down('#showSex').show();
}
}
},{ // Sex
xtype: 'combo',
itemId: 'sexValue',
queryMode: 'local',
editable: false,
value: 'eq',
triggerAction: 'all',
forceSelection: true,
fieldLabel: 'Select sex',
displayField: 'name',
valueField: 'value',
hidden: true,
store: {
fields: ['name', 'value'],
data: [
{name: 'female', value: 'f'},
{name: 'male', value: 'm'}
]
}
}, {
xtype: 'button',
text: 'Constrain age',
itemId: 'showAge',
hidden: false,
listeners: {
click: function (button) {
button.up('grid').down('#ageComparator').show();
button.up('grid').down('#ageValue').show();
button.up('grid').down('#hideAge').show();
button.up('grid').down('#showAge').hide();
}
}
}, {
xtype: 'button',
text: 'Hide age',
itemId: 'hideAge',
hidden: true,
listeners: {
click: function (button) {
button.up('grid').down('#ageComparator').hide();
button.up('grid').down('#ageValue').hide();
button.up('grid').down('#upperAgeValue').hide();
button.up('grid').down('#ageComparator').setValue('');
button.up('grid').down('#ageValue').setValue('');
button.up('grid').down('#upperAgeValue').setValue('');
button.up('grid').down('#hideAge').hide();
button.up('grid').down('#showAge').show();
}
}
}, { // Age
xtype: 'combo',
itemId: 'ageComparator',
queryMode: 'local',
editable: false,
value: '',
triggerAction: 'all',
forceSelection: true,
fieldLabel: 'Select age that is',
displayField: 'name',
valueField: 'value',
hidden: true,
store: {
fields: ['name', 'value'],
data: [
{name: '=', value: 'eq'},
{name: '<', value: 'lt'},
{name: '<=', value: 'le'},
{name: '>', value: 'gt'},
{name: '>=', value: 'ge'},
{name: 'between', value: 'bt'}
]
},
listeners: {
change: function(combo, value) {
// use component query to toggle the hidden state of upper value
if (value === 'bt') {
combo.up('grid').down('#upperAgeValue').show();
} else {
combo.up('grid').down('#upperAgeValue').hide();
}
}
}
},{
xtype: 'numberfield',
itemId: 'ageValue',
fieldLabel: 'value of',
value: '',
hidden: true
},{
xtype: 'numberfield',
itemId: 'upperAgeValue',
fieldLabel: 'and',
hidden: true
},{
xtype: 'button',
text: 'Constrain race/ethnicity',
itemId: 'showRace',
hidden: false,
listeners: {
click: function (button) {
button.up('grid').down('#raceValue').show();
button.up('grid').down('#hideRace').show();
button.up('grid').down('#showRace').hide();
}
}
}, {
xtype: 'button',
text: 'Hide race/ethnicity constraint',
itemId: 'hideRace',
hidden: true,
listeners: {
click: function (button) {
button.up('grid').down('#raceValue').hide();
button.up('grid').down('#raceValue').setValue('');
button.up('grid').down('#hideRace').hide();
button.up('grid').down('#showRace').show();
}
}
},{ // Race
xtype: 'combo',
itemId: 'raceValue',
queryMode: 'local',
editable: false,
value: 'eq',
triggerAction: 'all',
forceSelection: true,
fieldLabel: 'Select race',
displayField: 'name',
valueField: 'value',
hidden: true,
store: {
fields: ['name', 'value'],
data: [
{name: 'female', value: 'f'},
{name: 'male', value: 'm'}
]
}
},{
//minWidth: 80,
text: 'Add to search',
xtype: 'button',
itemId: 'searchClick',
handler: 'onSubmitDemographics'
}]
},
{
xtype:'searchGrid'
}
]
}
});
The only difference between each of the form panels in the tabs are the item components. Each of these form panels references an xtype of 'searchGrid' and renders it like in the attached image:
The problem is that I have 6-instances of this same grid. This works for the most part, but it is causing some issues related to getting control of the checkboxes in my grid along with some bizarre grid store load behaviors, and honestly, keeping track of components using this anti-pattern is a PITA.
I would like to somehow have a single instance of my searchGrid in a lower vertical panel, while an upper vertical panel has the item components I need to change according to the requirements for each tab. An example of how the item controls vary is
My desired behavior is that when I click on a tab, the upper item components would take me to a different form panel, while the lower panel stay fixed on the search grid.
However, I currently have the searchGrid bound to each tab's form panel, since that is the only way I could get this to work.
The searchGrid grid panel looks like:
Ext.define('cardioCatalogQT.view.grid.Search', {
extend: 'Ext.grid.Panel',
xtype: 'framing-buttons',
store: 'Payload',
itemId: 'searchGrid',
requires: [
'cardioCatalogQT.view.main.MainController'
],
columns: [
{text: "ID", width: 50, sortable: true, dataIndex: 'id'},
{text: "Type", width: 120, sortable: true, dataIndex: 'type'},
{text: "Key", flex: 1, sortable: true, dataIndex: 'key'},
{text: "Criteria", flex: 1, sortable: true, dataIndex: 'criteria'},
{text: "DateOperator", flex: 1, sortable: true, dataIndex: 'dateComparatorSymbol'},
{text: "When", flex: 1, sortable: true, dataIndex: 'dateValue'},
{text: "Count", flex: 1, sortable: true, dataIndex: 'n'}
],
columnLines: true,
selModel: {
type: 'checkboxmodel',
listeners: {
selectionchange: 'onSelectionChange'
}
},
// When true, this view acts as the default listener scope for listeners declared within it.
// For example the selectionModel's selectionchange listener resolves to this.
defaultListenerScope: false,
// This view acts as a reference holder for all components below it which have a reference config
// For example the onSelectionChange listener accesses a button using its reference
//referenceHolder: true,
// inline buttons
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
ui: 'footer',
layout: {
pack: 'center'
}
}, {
xtype: 'toolbar',
items: [{
//reference: 'andButton',
text: 'AND',
itemId: 'andButton',
tooltip: 'Add the selected criteria as AND',
iconCls: 'and',
disabled: true,
handler: 'onCriterionAnd'
},'-',{
//reference: 'orButton',
text: 'OR',
itemId: 'orButton',
tooltip: 'Add the selected criteria as OR',
iconCls: 'or',
disabled: true,
handler: 'onCriterionOr'
},'-',{
//reference: 'notButton',
text: 'NOT',
itemId: 'notButton',
tooltip: 'Add the selected criteria as NOT',
iconCls: 'not',
disabled: true,
handler: 'onCriterionNot'
},'-',{
//reference: 'removeButton', // The referenceHolder can access this button by this name
text: 'Remove',
itemId: 'removeButton',
tooltip: 'Remove the selected item',
iconCls: 'remove',
disabled: true,
handler: 'onCriterionRemove'
},'-', { // SaveQuery
//reference: 'SaveQuery',
text: 'Save',
itemId: 'saveQuery',
tooltip: 'save the current filter',
iconCls: 'save',
disabled: true,
handler: 'onFilterSave'
}]
}],
height: 1000,
frame: true,
iconCls: 'icon-grid',
alias: 'widget.searchGrid',
title: 'Search',
initComponent: function() {
this.width = 750;
this.callParent();
}
});
I messed around with using a Vbox layout to get my desired behavior, but was rather unsuccessful. This does not seem like that uncommon of a use case to have an upper Vbox panel change to different form panels based on a Tab click, while the lower Vbox panel remains fixed. Any insight would be most welcome.
If I understand correctly, this small test of mine should do exactly what you want, using a border layout with regions north and center.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="ext-theme-gray.css">
<title>Test app</title>
<script type="text/javascript" src="ext-all-dev.js"></script>
<script>
Ext.onReady(function() {
var Viewport = Ext.create('Ext.container.Viewport',{
layout:'border',
items:[{
xtype:'tabpanel',
region:'north',
items:[{
xtype:'panel',
title:'A',
items:[{xtype:'button',text:'Clickme'}]
},{
xtype:'panel',
title:'B',
items:[{xtype:'textfield'}]
}]
},{
xtype:'gridpanel',
title:'center',
region:'center',
columns:[{
dataIndex:'A',
text:'A'
},{
dataIndex:'B',
text:'B'
}]
}]
})
Ext.create('Ext.app.Application',{
name:'TestApp',
autoCreateViewport: true,
views:[
Viewport
]
});
});
</script>
</head>
<body>
</body>
</html>
PS: I used ExtJS 4.2.2, but it should work in other Ext versions as well.

extjs 3.4 add tool tip in from field

Hi I have some form fields and I'm trying to add tool tip. But it is not working. This is my fields,
var importForm = new Ext.form.FormPanel({
//html: "<p>Imgae source: <b>img</b> folder in root directory</p>",
url: '/plugin/ImageImport/admin/import',
monitorValid: true,
labelWidth: 175,
frame: true,
title: 'Image Import',
width: 250,
defaultType: 'textfield',
defaults: { allowBlank: false },
items:[
{ fieldLabel: 'Source Folder Path', name: 'imgSourcePath', id:'imgSourcePath' },
{
xtype: 'combo',
name: 'folderId',
fieldLabel: 'Target Folder',
mode: 'local',
store: valuesDir,
displayField:'key',
valueField: 'id',
width: 'auto',
triggerAction: 'all',
emptyText:'Select Folder...',
id:'folderId',
selectOnFocus:true,
allowBlank: false,
editable: false,
},
{
xtype: 'combo',
name: 'transformation',
fieldLabel: 'Image Transformations',
mode: 'local',
store: values,
displayField:'name',
valueField: 'name',
width: 'auto',
triggerAction: 'all',
emptyText:'Select Transformation...',
id:'transformation',
selectOnFocus:true,
allowBlank: false,
editable: false,
},
],
And at the end of my code I'm trying to add tool tip,
Ext.onReady(function(){
new Ext.ToolTip({
target: 'imgSourcePath',
html: 'A very simple tooltip'
});
new Ext.ToolTip({
target: 'folderId',
html: 'A very simple tooltip'
});
new Ext.ToolTip({
target: 'transformation',
html: 'A very simple tooltip'
});
Ext.QuickTips.init();
});
I tried qtip as well but that also not working.like,
{ fieldLabel: 'Source Folder Path', name: 'imgSourcePath', id:'imgSourcePath', qtip: 'This is tool tip' },
Please help me someone ...
Take a look on this issue to know how to put it on comboBox ExtJs 3.4 : Set tool tip for combo box
Hope this help.

destroy() or close() actually doesn't destroy the object? (Ext-JS 4.1.1a)

Here is my window and form inside of it:
Ext.define('App.view.Users.Update', {
extend: 'Ext.window.Window',
title: 'User',
width: 250,
id: 'UpdateWindowUsers',
defaultType: 'textfield',
items: [{
xtype: 'UpdateFormUsers'
}],
buttons: [
{ text: 'Save', id: 'submitUpdateFormButtonUsers'},
{ text: 'Cancel', id: 'cancelUpdateFormButtonUsers'},
]
});
Ext.define('App.view.Users.UpdateForm', {
extend: 'Ext.form.Panel',
alias: 'widget.UpdateFormUsers',
layout: 'form',
id: 'UpdateFormUsers',
bodyPadding: 5,
defaultType: 'textfield',
items: [{
fieldLabel: 'Id',
name: 'id',
hidden: true
},{
fieldLabel: 'username',
name: 'username',
allowBlank: false,
},{
fieldLabel: 'password',
name: 'password',
minLength : 5,
allowBlank: false
},{
fieldLabel: 'Email',
name: 'email',
minLength : 5,
vtype: 'email',
allowBlank: false
},{
fieldLabel: 'first name',
name: 'first_name',
allowBlank: false
},{
fieldLabel: 'last name',
name: 'last_name',
allowBlank: false
}],
});
It's in one file: "App/view/Users/Update.js".
So, I'm creating an object with:
var win = Ext.create('App.view.Users.Update');
It's created with a button. But when I close the window with win.close() and when I close the "tab" inside my "border" layout and when I press the button for creating the same window again, it says (in my console) that I'm recreating an object with the same "id" again. It's already registered in Ext.AbstractManager.
How can I fully destroy the object? Maybe with Ext.AbstractManager.unregister(win); something?
If you need more code, no problem. :) Thank you.
P. S.
I'm getting a reference to my window with:
var window = Ext.ComponentQuery.query('#UpdateWindowUsers')[0];
window.close();
Does window.close() actually destroys the panel inside of it?
Solved it.
this == Controller
if(this.isCreated){
this.control(listeners);
}
I've put isCreated property inside Controller.

Categories

Resources