I have a grid panel named "Teilgewerke". I am able to use it as an item of a panel like
{
xtype:'panel',
layout: {
type: 'hbox',
align: 'stretch'
},
items:[
{
//xtype: 'teilgewerkegrid',
id:'feinplanungPanelTeilgewerkeGrid',
flex: 2
},
{
xtype: 'panel',
flex: 1
}
]
}
But now when I try to use it inside another panel, it throws following error:
Uncaught TypeError: Cannot read property 'isComponent' of undefined
I found this question on Stackoverflow which is pointing to exact same problem. I tried the solution given in above link, by putting items as
initComponent: function() {
this.items = [
{
xtype:'panel',
flex: 5,
border: false,
padding: '0 20 0 20',
items:[
{
xtype: 'text',
text: 'Teilgewerke für Aufbau an beteiligte Gruppen senden.',
}
]
},
Ext.create('PfalzkomApp.view.TeilgewerkeGrid', {
padding: '0 20 0 20',
id:'aufbauTabTeilgewerkeGrid',
flex: 90
}),
{
xtype: 'panel',
border: false,
padding: '0 20 0 20',
flex: 5
}
]
this.callParent();
}
But I still have same issue. Can someone point out my mistake?
The issue you have should be that there is no xtype:'text' predefined in Sencha ExtJS. Please select one of textfield, label, container.
Please do strictly enforce correct indentation throughout your code, or else it will be unreadable soon. Furthermore use the most readable approach for component instantiation, as described below:
If you want to instantiate a custom component, you do it like you instantiate a Sencha component: Using xtype.
In the component you define, you give the component an xtype name:
Ext.define('My.custom.Component',{
xtype:'teilgewerke'
and when you create it, you require the component (so the file is loaded and the xtype is registered with ComponentManager), and then use that very xtype in your items definition:
Ext.define('MyApp.view.Component',{
extend:'Ext.panel.Panel',
requires:['My.custom.Component'],
initComponent: function() {
var me = this;
Ext.apply(me,{
items:[{
xtype:'teilgewerke'
}]
});
me.callParent(arguments);
}
});
Please be aware that all custom components you want to instantiate more than once should NEVER contain any absolute id; only the relative itemId; and they should not use absolute getCmp, only relative down(), up(), nextSibling(), previousSibling().
Solution to this problem which I found was to dynamically insert my custom component into the item array of the view(in which I wanted to add).
So in the after render of my view(in which I want to add my custom component), I did this:
var view = Ext.getCmp('aufbauTab');
view.insert(
view.items.length,
{
xtype: 'teilgewerkegrid',
padding: '0 20 0 20',
id:'aufbauTabTeilgewerkeGrid',
flex: 90
}
);
And it worked perfectly fine.
Related
I am attempting to create a reusable title bar for our grids. This will require a couple of properties which can be set when the grid title bar is used. The problem I am running into is that the property is undefined when I attempt to use it.
I looked at how ExtJS appears to do this and saw that they set up their properties in the config block. So I tried that with no luck. I have also tried removing the config block and adding the property with the same result.
Ext.define('ERM.view.mastersite.GridTitleBar', {
extend: 'Ext.TitleBar',
xtype: 'gridtitlebar',
margin: '0 0 20 0',
shadow: true,
cls: 'x-big',
style: {
border: 'solid lightgrey 2px'
},
config: {
addNewToolTip: 'test',
},
items: [{
xtype: 'button',
iconCls: 'md-icon-add-circle',
text: 'Add',
align: 'right',
tooltip: this.parent.addNewToolTip,
}],
});
I'm expecting the tool tip to show "test" by default, or if the default is overridden, I'm expecting it to show the overridden string.
Edit
Second attempt based on the answers below.
Ext.define('ERM.view.mastersite.GridTitleBar', {
extend: 'Ext.TitleBar',
xtype: 'gridtitlebar',
margin: '0 0 20 0',
shadow: true,
cls: 'x-big',
style: {
border: 'solid lightgrey 2px'
},
config: {
addNewToolTip: 'test',
},
initialize: function () {
const me = this;
me.items = [{
xtype: 'button',
text: 'Add',
iconCls: 'md-icon-add-circle',
tooltip: me.getAddNewToolTip(),
}];
this.callParent();
},
});
if you are using modern toolkit use initialize method instead of initComponent
You're correctly defining the property. Your problem is the way you are accessing it.
At the time of building the items construct, the this context is whatever has loaded the file - probably the boot loader. Strangely enough, that won't have your new property.
In order to access properties of your new class/object, you need to define the items construct after the object is created. One good location for that is in the initComponent method.
Ext.define('ERM.view.mastersite.GridTitleBar', {
// in here, the 'this' context is whatever loaded the file.
...
config: {
addNewToolTip: 'test',
},
...
initComponent: function() {
// In here, like most methods in ExtJS, the 'this' context is the owning instance.
this.items = [{
xtype: 'button',
...
// Oh, and it's a good idea to use the accessors for config variables
tooltip: this.getAddNewToolTip()
}]
// don't forget to call the parent.
this.callParent(arguments);
});
I have container
items: [{
xtype: 'container',
layout: 'card',
flex: 1,
itemId: 'tab-container',
deferredRender: false,
items: [ {
xtype: 'panel',
layout: 'fit',
dockedItems: [routessearch],
items: [routes]
}, {
xtype: 'panel',
layout: 'fit',
forceLayout: true,
dockedItems: [routessearch],
items: [routesSubs]
}]
}]
When page loaded I can get first tab because it is already active. But I can't get second tab because it hasn't been created.
I tried to use deferredRender:false and forceLayout:true (like in code sample), but it doesn't working.
In ExtJs you should interact with components and not with the dom directly.
So when you replace var elements = document.querySelectorAll(query); with Ext.ComponentQuery.query(query); you get an array of the matching components and you can interact with them.
From the Sencha documentation of Ext.ComponentQuery:
Provides searching of Components within Ext.ComponentManager
(globally) or a specific Ext.container.Container on the document with
a similar syntax to a CSS selector. Returns Array of matching
Components, or empty Array.
So after the component query Ext.ComponentQuery.query('#tab-container > panel') you have all inner panels.
With second = components[1] you have a reference to the second.
Now you can interact with the component.
But when you need also access to the dom of the component you get it by second.getEl().dom.
So the complete code looks like.
Ext.create('Ext.container.Container', {
renderTo: Ext.getBody(),
width: 200,
height: 200,
layout: 'card',
itemId: 'tab-container',
deferredRender: false,
items: [{
title: 'P1'
}, {
title: 'P2'
}],
listeners: {
boxready: function () {
var components = Ext.ComponentQuery.query('#tab-container > panel');
var second = components[1];
var el = second.getEl();
var dom = el.dom;
// code to interact with the component or with the dom
}
}
});
See the code in action in the Sencha Fiddle.
I was trying to develop a base container by extending Ext.Container, which have some default items in it. A subclass should add the items to the child component of the base class and not directly to the container instead. How to do this?
May i override the setItems/applyItems method to add the items to navigationView.add(items); ?? I'm unsure about how this works. Since i'm new to ExtJs, unable to identify which is the way to do it generically so that it won't affect my subclass to add n number of items to it either using inline or add(item) method.
AbstractClass
Ext.define('MyApp.container.AbstractMainContainer', {
extend: 'Ext.Container',
xtype: 'abstractmaincontainer',
requires: [
'MyApp.container.NavigationView',
'MyApp.control.NavigationBar'
],
config: {
layout: {
type: 'vbox',
pack: 'start',
align: 'stretch'
},
flex: 1,
height: '100%',
width: '100%'
},
controller: 'maincontroller',
items: [{
xtype: 'navbar',
itemId: 'navbar'
}, {
xtype: 'navigationview',
itemId: 'navigationview',
reference: 'navigationview',
navigationBar: false,
layout: {
pack: 'start',
align: 'stretch'
},
flex: 1,
height: '100%',
items: [
// new item should added here
]
}],
/**
* #method getContentView add the items to this rather than directly
* #return {void}
*/
getContentView: function() {
return this.down('#navigationview');
},
});
SubClass
Ext.define('MyApp.main.view.MainContainer', {
extend: 'MyApp.container.AbstractMainContainer',
requires: [
'MyApp.container.AbstractMainContainer'
],
config: {
},
items: [{
// we should not directly add items here this will remove the navbar and navigation view
// HOW TO ADD THIS IN A GENERIC WAY??
xtype: 'container',
layout:{
type:'card'
},
items: [{
xtype: 'button',
role: 'nav',
title: 'Card 1',
text: 'go to next',
handler: function() {
}
}, {
itemId: 'myCard',
title: 'Card 2',
html: '<h1>Card 2</h1>'
}],
}],
});
AFAIK, there's no "automatic" way to do it.
I can suggest some approaches:
First of all, check if you really need to do this: for example, you could move the navbar to the dockedItems config and move the navigationview one level up.
So your AbstractContainer will extend navigationview, navbar will be a dockedItem, and you will be able to use the items config as usual.
Otherwise, you could use a different config (let's say "extraItems" or "navItems"), and merge them overriding the abstract class initComponent function.
There, after a callParent that actually initialize the navigationview, you could do something like
this.down('navigationview').add(this.extraItems);
My panel with border layout looks like this:
var oSplitPanel = Ext.create('Ext.panel.Panel', {
lid : 'splitpanel',
layout: 'border',
border: 0,
style: { border: 0 }
height: 150,
items: [{
split: true,
flex: 1,
region: 'west',
xtype: 'panel',
lid: 'panelwest',
layout: 'fit',
minWidth: 200
}]
});
Then another panel gets added to this west region panel:
oSplitPanel.query('[lid=panelwest]')[0].add(oExplorerPanel);
Then this split panel gets added to my main view:
that.getView().add(oSplitPanel);
Then in another function, I add the center panel:
var oAddPanelRight = {
split: true,
flex: 3,
region: 'center',
xtype: 'panel',
lid: 'panelcenter',
layout: 'fit',
border: 0
};
oSplitPanel.add(oAddPanelRight);
Problem:
Everything works perfect this way, however I want to change (limit) the splitter's own width (this splitter is in between west and center panels to resize their width).
What I tried:
Try to change the width of splitters:
listeners: {
afterrender: function() {
// error following, 'splitters' does not exist
oSplitPanel.layout.splitters.west.setWidth(1);
oSplitPanel.doLayout();
}
}
Adding a negative margin to the center panel:
// Tried this:
margin: '0 0 0 -4'
// And that:
style: {
border: 0,
marginLeft: '-3px'
}
Or use event "add"
listeners: {
add: function (me, item) {
if (item.xtype == 'bordersplitter') item.width = 2;
}
},
Demo here http://ext4all.com/post/extjs-4-border-layout-splitter-width
Your oSplitPanel object/instance does not have the split param set to true and has therefor no splitter applied. The splitter get applied to oAddPanelRight object/instance and the nested panel of the oSplitPanel, maybe also to the panel you add later. Can't tell that.
So you just looked at the wrong class.
Btw. to get a splitter for the class itself you don't need look at oSplitPanel.layout.splitters Just look at the splitter prop of the class.
panel({}) and all its contents like grid, form and want to render that exact clone to another panel is there a way to do it..is it possible to do it with panel.getEl() or is there any other way...please help
The sra's answer is incorrect. Ext's cloneConfig does exactly what you want it to. http://docs.sencha.com/ext-js/4-1/#!/api/Ext.Component-method-cloneConfig
The following code renders two of the "same" panels to the body.
var panel = Ext.create('Ext.Panel', {
width: 500,
height: 300,
title: "HBoxLayout Panel",
layout: {
type: 'hbox',
align: 'stretch'
},
renderTo: document.body,
items: [{
xtype: 'panel',
title: 'Inner Panel One',
flex: 2
},{
xtype: 'panel',
title: 'Inner Panel Two',
flex: 1
},{
xtype: 'panel',
title: 'Inner Panel Three',
flex: 1
}]
});
var clone = panel.cloneConfig();
I must admit that the old answer was not entirely correct. Cloning of Componments is available since ExtJS2 and can be done via cloneConfig(overrides) which is a instance-method.
This will return a clone of the current instance with the applied overrides (if set). A clean clone will require you to use correct configurations, meaning no instances are created within the config. Here are some information bout this For more details read the Sencha guides
Old answer (only valid if the components to clone configs contains instances instead of plain configurations)
No, there is no buildin way to do this. And you should not try it. Consider to wrap the panel in a function that returns a instance of it (a simple sort of factory).
Edit
Something like this:
Factory.Panel = function (config) {
var defaults = {
labelWidth: 80,
labelAlign: 'left',
layout: 'form',
width: 720,
autoHeight: true,
header: false,
bodyStyle: 'padding:10px 15px;'
};
var cfg = Ext.apply({}, config, defaults);
var cmp = new Panel(cfg);
return cmp;
}
You can add as much function params as you like. This would be a clean way to do it. You just can clone simple object like a record. Note that Factory is a Namespace!