I have a form panel in a border layout as follows:
{
xtype: 'form',
region: 'north',
split: true,
labelAlign: 'top',
height: 130,
autoScroll: true,
collapsible: true,
listeners: {
'collapse': function () {
Ext.getCmp('slider').setTitle('Filter Events By Time');
// this is not working either
}
},
//collapsed: true,
id: 'slider',
title: 'Filter Events By Time',
border: true,
html: {
tag: 'div',
style: '',
children: [{
tag: 'div',
cls: 'slider_div',
style: 'margin-right:50px;position:relative;float:left'
}, {
tag: 'div',
cls: 'slider_unit',
style: 'margin-top:10px'
}, {
tag: 'div',
style: 'clear:left'
}, {
tag: 'div',
cls: 'startDate',
style: 'margin-right:30px;float:left'
}, {
tag: 'div',
cls: 'endDate',
style: ''
}, {
tag: 'div',
style: 'clear:left'
}]
}
}
Now, when I collapse it using following code, the collapsed panel does not have a title. I can see the title if I expand the panel.
Ext.getCmp('slider').collapse(true);
How can I get title on a collapsed form panel?
There are two small things you need to fix:
1 Method collapse, does not take argument bool, but collapse( [direction], [animate] ), all optional.
2 Use itemId instead of id:
An itemId can be used as an alternative way to get a reference to a
component when no object reference is available. Instead of using an
id with Ext.getCmp, use itemId with
Ext.container.Container.getComponent which will retrieve itemId's or
id's. Since itemId's are an index to the container's internal
MixedCollection, the itemId is scoped locally to the container --
avoiding potential conflicts with Ext.ComponentManager which requires
a unique id.
3 Fetch component reference using this inside of internal scope and use ComponentQuery outside of it. Like this:
this.setTitle('Filter Events By Tim Collapsede');
and/or
Ext.ComponentQuery.query('#slider')[0].collapse();
and also please create your components using Ext.define, and then call them in your border layout using alias/xtype. :-)
Here is a example on fiddle
Related
I know nothing about Ext.js but I am being tasked with enhancing some of our front end JavaScript that uses it. I have the following code:
xtype: 'fieldset',
docked: 'bottom',
flex: 1,
defaults: {
xtype: 'button',
style: 'margin: .5em',
flex: 1,
},
layout: {
type: 'hbox',
},
items: [{
text: 'Submit',
ui: 'plain',
itemId: 'shareOutButton',
cls: 'btn btn-primary',
action: 'submitShareListing',
},
{
text: 'Done',
ui: 'plain',
itemId: 'doneButton',
cls: 'btn btn-primary',
handler: function () {
this.up('ShareOutWindow').close();
},
}],
When the user clicks on the doneButton - I simply want to close the current panel (it has the ID of ShareOutWindow') that is displayed. I have tried several things .close(), .hide() etc. I am able to get a reference to an object using the this..... but I cannot figure out how to close or hide the panel once I get a reference to it.
I have also tried this function -- but the panel does not go away and I don't get an error message.
handler: function () {
this.up('ShareOutWindow').close;
},
Any help would be greatly appreciated
Good day all.
In EXTjs, probably 4.x version, I have a menu with a couple of levels of sub-menus
I'd like to add a data attribute to some of those sub-menus and actually I can do this with no problems with:
Ext.getCmp("notificationMenu").getEl().set({"data-notifynumber": 4});
but this is working only for the first element of the menu (to be clear, the element that is shown upon loading.
For any other element of the menu, first of all I have to click the menu to show all the sub-menu and only at that time I can use the getEl() function, otherwise this error is shown:
Uncaught TypeError: Cannot read property 'set' of undefined
I understand that I'd need to... show? render? well, "do something" to those sub elements in order to have them in the dom properly... I attach part of the code:
this is part of the menu I create:
xtype: 'button',
id:"notificationMenu",
hidden: false,
reference: 'userType',
style: 'color: #ffffff;width:58px;height:58px;',
glyph: 0xf0f3,
menu:{
border:0,
menuAlign: 'tr-br?',
bodyStyle: {
background: '#3e4752',
},
items:[
{
text:"TASKS",
disabled:true
},
{
text:"Campaigns",
data_id:"me_campaigns",
glyph:0xf0c1,
id:"notification_me_campaigns_root",
hidden:true,
menu:{
border:0,
menuAlign: 'tr-br?',
bodyStyle: {
background: '#3e4752',
},
items:[
{
text:"Approval",...
in this example, if I make after Render:
Ext.getCmp("notificationMenu").getEl().set({"data-notifynumber": 10})
but if I use
Ext.getCmp("notification_me_campaigns_root").getEl().set({"data-notifynumber": 4})
the error above is shown. please do you have some advice? may I call a "force render" somehow?
Try to use afterrender to get dom element.
ExtJs getEl() Retrieves the top level element representing this component but work when dom is prepared without dom creation it will return null.
I have created an Sencha Fiddle demo hope this will help you to achieve you requirement/solution.
var panel = new Ext.panel.Panel({
renderTo: document.body,
title: 'A Panel',
width: 200,
tools: [{
xtype: 'button',
text: 'Foo',
menu: {
defaults: {
handler: function () {
Ext.Msg.alert('Successs', 'You have click on <b>data-notifynumber</> ' + this.up('menu').getEl().getAttribute('data-notifynumber'))
}
},
items: [{
text: 'Item 1'
}, {
text: 'Item 2',
menu: {
listeners: {
afterrender: function () {
this.getEl().set({
"data-notifynumber": 20//only for example you can put as basis of your requirement
});
}
},
defaults: {
handler: function () {
Ext.Msg.alert('Successs', 'You have click on <b>data-notifynumber</> ' + this.up('menu').getEl().getAttribute('data-notifynumber'))
}
},
items: [{
text: 'Sub Item 1',
}, {
text: 'Sub Item 2'
}]
}
}],
listeners: {
afterrender: function () {
this.getEl().set({
"data-notifynumber": 10//only for example you can put as basis of your requirement
});
}
}
}
}]
});
I use Ext5 and I have a question. Is it possible to remove text and add items into panel header after the panel collapsed?
Belows the code, the east panel is collapsible. I want to remove text and add items into header after it collapsed.
Ext.create('Ext.container.Viewport', {
layout: 'border',
items: [{
region: 'east',
title: 'East Panel',
collapsible: true,
split: true,
width: 150
}, {
region: 'center',
xtype: 'tabpanel', // TabPanel itself has no title
activeTab: 0, // First tab active by default
items: {
title: 'Default Tab',
html: 'The first tab\'s content. Others may be added dynamically'
}
}]
});
UPDATE
In this case, I add buttons into header but when the panel is collapsed the button disappeared. Is there any way to show or add components into header when panel is collapsed?
{
region: 'east',
title: 'East Panel',
collapsible: true,
split: true,
width: 150,
header: {
items: [{
xtype: 'button'
}, {
xtype: 'button'
}]
}
}
here is the fiddle
Thanks
Please refer to "placeholder" related configs in Ext.panel.Panel class. Below is your code from fiddle modified.
Ext.create('Ext.container.Viewport', {
layout: 'border',
items: [{
region: 'east',
title: 'East Panel',
collapsible: true,
collapseMode:'placeholder',// set collapseMode to placeholder
split: true,
width: 300,
placeholder:{ // Try different components and layout configs
width:100,
items:[{
xtype:'button',
text:'Button 1'
}]
}
/*header: {
items: [{
xtype: 'button'
}, {
xtype: 'button'
}]
}*/
}, {
region: 'center',
xtype: 'tabpanel', // TabPanel itself has no title
activeTab: 0, // First tab active by default
items: {
title: 'Default Tab',
html: 'The first tab\'s content. Others may be added dynamically'
}
}]
});
The header you see collapsed is actually another instance of Ext.panel.Header created just for this purpose. I tried to find some configs to customize it, but the Ext.panel.Panel was not created having it in mind.
So you'll have to override the method which creates this reader, which I found out is called createReExpander. It's a big method hard to override without having to rewrite a lot of stuff, but it can be done.
I tried adding buttons to the header and the result was not visually nice, but at least they were created!
So I would suggest you use tools instead of buttons if you don't need text on them.
I am trying to mod the Portlet example and port it into our program. The code looks like this:
Ext.create('Ext.container.Viewport',{
id: 'app-viewport', //creates viewport
layout: {
type: 'border',
padding: '0 5 5 5' // pad the layout from the window edges
},
onPortletClose: function(portlet) {
this.showMsg('"' + portlet.title + '" was removed');
},
showMsg: function(msg) {
var el = Ext.get('app-msg'),
msgId = Ext.id();
this.msgId = msgId;
el.update(msg).show();
Ext.defer(this.clearMsg, 3000, this, [msgId]);
},
clearMsg: function(msgId) {
if (msgId === this.msgId) {
Ext.get('app-msg').hide();
}
},
items: [{
id: 'app-header',
xtype: 'box',
region: 'north',
height: 40,
html: 'Ext Welcome'
},{
xtype: 'container',
region: 'center',
layout: 'border',
items: [{
id: 'app-options', //Creates the Options panel on the left
title: 'Options',
region: 'west',
animCollapse: true,
width: 200,
minWidth: 150,
maxWidth: 400,
split: true,
collapsible: true,
layout:{
type: 'accordion',
animate: true
},
items: [{
html: content,
title:'Navigation',
autoScroll: true,
border: false,
iconCls: 'nav'
},{
title:'Settings',
html: content,
border: false,
autoScroll: true,
iconCls: 'settings'
}]
},{
id: 'app-portal', //Creates the panel where the portal drop zones are.
xtype: 'mainpanel',
region: 'center',
items: [{
id: 'col-1', //Each column represents a drop zone column. If we add more there are more created and width gets adjusted accordingly
items: [{
id: 'portlet-1',
title: 'Portlet 1',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
},{
id: 'portlet-2',
title: 'Portlet 2',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
},{
id: 'col-2',
items: [{
id: 'portlet-3',
title: 'Portlet 3',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
},{
id: 'col-3',
items: [{
id: 'portlet-4',
title: 'Portlet 4',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
}]
}]
}]
});
The problem is that Ext.bind cannot read the onPortletClose function and the browser gives me a:
Uncaught TypeError: Cannot read property 'apply' of undefined error. I checked the stack and essentially in the Ext.bind(fn,scope) the fn is undefined and thus it cannot read the handler function. The difference between my application and in the example is that I add this directly into a JSP's Ext.onReady() whereas in the example all of this is added through a Ext.apply(this, {...}). I'm really confused. I tried all kinds of gimmicks to force the scope on the viewport but it seems that whatever is inside Ext.bind() loses contact with outside or something. I've used Ext.bind() before and it went fine although it was inside an initComponent configuration. Is that mandatory? If no then what is the problem?
It is important to understand the meaning of this here (or in general when working with JavaScript or ExtJS).
In a global context, this refers to the global object, also known as the global window variable. This is the case inside your Ext.onReady function:
Ext.onReady(function() {
console.log(this === window);
// -> true
// because this is the global object
});
In an object context, by default this refers to the owner object of the function (there are ways around it and actually this is exactly want you want do achieve using Ext.bind):
var obj = {
prop: 'My text property',
fn: function() {
console.log(this.prop);
// -> My text property
// because "this" refers to our object "obj"
}
};
Now, this is exactly what makes the difference between your case and the one from the examples.
When using the approach with Ext.onReady this - as pointed out above - will refer to the global object, which of course does not have a function onPortletClose.
When using the approach from the examples, this is accessed from inside of initComponent, which is a member function of your derived viewport class, and therefore this refers to the component instance (= the owning object), which allows you to access your function.
Ext.define('MyViewport', {
extend: 'Ext.container.Viewport',
onPortletClose: function(portlet) {
this.showMsg('"' + portlet.title + '" was removed');
},
initComponent: function() {
console.log(this);
// -> the instance of your viewport class
Ext.apply(this, {
items:[{
xtype: 'panel',
title: 'Portlet 1',
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
});
this.callParent();
}
});
Side notes
Ext.apply
Ext.apply really just copies all properties from one object to another, so in this case it is just a convenient way of applying all attributes of that object to this with one function call. You could as well just use:
this.items = [...];
Changing the scope of your listeners
You do not need to use Ext.bind when adding listeners to a component, you can simply provide a scope configuration in your listeners object:
listeners: {
close: function() {...},
scope: this
}
External sources
If you want to dive in a little deeper (which I would recommend), you might want to read more about this at the MDN (Mozilla Developer Network).
I am developing a simple JavaScript-based plugin architecture which allows for any JavaScript control from any framework (jQueryUI, ExtJS, etc). to be plugged into and reused on any web page. My plugins below happen to use ExtJS 4.
The first plugin renders fine in the first tab. However, since the second tab hasn't yet rendered when the page loads, the second plugin (also a grid) is first rendering to the document body, and then it renders properly (the HTMLElement/div is moved) inside the tab when the tab is selected. I'd like the plugin content to be hidden prior to rendering inside the tab. Also, when it it does render [when the tab is selected], horizontal scrollbars don't show unless I resize a column.
Any ideas how to fix this?
Ideas: use something other than contentEl; leverage various ExtJS config options; change my architecture.
Here is the plugin code:
(function(MyNamespace) {
var gridDataStore = ...
MyNamespace.Plugin.Chart = MyNamespace.Plugin.extend({
return {
initialize: function() {
// ...
},
render: function() {
var stockGrid = Ext.create('Ext.grid.Panel', {
autoRender: true,
autoShow: true,
store: gridDataStore,
header: false,
stateId: 'stateGrid',
columns: [
{text: 'Symbol', width: 75, sortable: true, dataIndex: 'symbol'},
{text: 'Description', width: 200, sortable: true, dataIndex: 'description'},
{text: 'Quantity', width: 75, sortable: true, dataIndex: 'quantity'},
{text: 'Last Price', width: 85, sortable: true, dataIndex: 'last_price'}
],
viewConfig: {
stripeRows: true,
enableTextSelection: true
}
});
return stockGrid.getEl().dom;
}
};
}
})(MyNamespace);
And here's code using the plugin:
var chart = new MyNamespace.Plugin.Chart();
var anotherPlugin = new MyNamespace.Plugin.Another();
var stocksWindow = Ext.create('Ext.Window', {
title: 'Stocks',
width: 600,
height: 450,
layout: 'fit',
items: [
Ext.create('Ext.tab.Panel', {
activeTab: 0,
items: [{
title: 'Chart',
autoScroll: true,
contentEl: chartPlugin.render() // RENDER FIRST PLUGIN IN FIRST TAB
},{
title: 'Something Else',
autoScroll: true,
contentEl: anotherPlugin.render() // RENDER SECOND PLUGIN IN SECOND TAB
}]
})
]
});
I can add it to an invisible container, but it feels dirty doing so:
var container = document.createElement('div');
document.getElementsByTagName('body')[0].appendChild(container);
container.style.visibility = 'hidden';
var stockGrid = Ext.create('Ext.grid.Panel', {
...
renderTo: container
...
});
Here's an example
Here are a few problems with your code.
What you are calling plugins are not plugins, they are just subclasses of Ext.grid.Panel. A plugin is something that adds functionality to an Ext.Component, but that is not what Stocks is doing. It's just what we call a preconfigured class.
Here's what I would do, just make MyNamespace.Plugin.Stocks be a subclass of Ext.grid.Panel, you can now easily pass those as the items of a Ext.tab.Panel. Make sure you rename it, it's not a plugin.
By giving your widget subclasses the alias: 'widget.stock-grid', you can create them using just an object definition, without having to instantiate them, the framework will take care of rendering it only when needed (the tab is activated)
Ext.create('Ext.tab.Panel', {
activeTab: 0,
items: [{
title: 'Stocks',
autoScroll: true,
xtype: 'stock-grid'
},{
title: 'Orders',
autoScroll: true,
xtype: 'stock-grid'
}]
})
When using managed layouts, you cannot just simply copy a node into another container, because the node you copied in there won't have a managed layout.
Here's a modified version of your code that is written more like Ext-JS intended it. http://jsfiddle.net/NVfRH/10/
You can look into the generated HTML and you'll notice that the grid under orders only renders when you activate that tab.
You should also notice that your grids weren't properly sizing themselves to fill the window, my code fixes that since they are correctly placed in the layout pipeline and obey the fit layout.
Remaining Problems
Your grids are sharing a store, notice that when you sort one, the other gets sorted, so you can't have them with different sorting.
You were using a stateId, but then you were creating two instances with the same stateId, all stateIds must be unique
And lastly, I must ask, were you really relieved when Chad Johnson changed his name to Chad Ochocinco? :)