I have a simple button with menu. There is a treepanel inside the menu.
Whenever user selects some node in tree, i update the container buttons text.
In treepanel's afterrender event i make a default node selection in the tree and this fire selection event and the button's text is updated.
However, when the button is rendered for the very first time, the treepanel inside the menu is not yet rendered.
How can i make menu & treepanel render silently (adding to dom but not shown to user until button is clicked) after button is rendered?
Actually there is a workaround which i hesitate to use:
btn.showMenu();
btn.hideMenu();
Any better ideas?
JsFiddle: http://jsfiddle.net/exGk3/
Code:
var selectedNodeIndex = 1;
var onItemSelect = function (selModel, node, index) {
var treePanel = selModel.view.up();
var btn = treePanel.up("button");
btn.setText(node.data.text);
};
var afterTreeRender = function (t) {
t.selModel.select(selectedNodeIndex);
}
Ext.create('Ext.Button', {
text: 'Click me',
renderTo: Ext.getBody(),
menu: {
items: {
xtype: "treepanel",
id: "tree",
indent: false,
width: 150,
height: 200,
rootVisible: false,
root: {
children: [{
text: "item 1",
leaf: true
}, {
text: "item 2",
leaf: true
}, {
text: "item 3",
leaf: true
}]
},
listeners: {
select: {
fn: onItemSelect
},
afterrender: {
fn: afterTreeRender
}
}
},
showSeparator: false
}
});
I think the easiest thing to do here is to pass along the text needed for the button. It seems that you already know which node to select in the tree, then you probably know which text corresponds to the selected index.
If that's somehow not possible or API is not changeable here is a way for you to set button text programmatically:
http://jsfiddle.net/dbrin/XSn7X/3/
The changes from what you have done are 2 fold:
Use Ext.define method to define your class with initComponent method.
The initComponet method is a hook after the constructor to setup aditional properties. The key here is that the instance of the class exists at this point and *this* context references the class instance.
Use Ext.create to create an instance of your customized button component.
In the initComponment method you just traverse the tree looking for the data you need and set the button text.
Related
Problem is probably simple but I can't find the proper answer.
I have a panel with only four buttons. Just vbox with buttons. And now I want to select and press this buttons not only with mouse click but also via keyboard. So I used Ext.KeyMap and I catch every key I want to: ENTER, TAB, DOWN and UP. But I can't find simple way to move focus betveen this buttons.
E.g. I'm focused on first button, press DOWN key and I want to be focused on the second button. No way. I tried
but1.down('button[action=next]').focus(false, 100))
but it can't work. Be so kind as to prompt please.
Well what can I say, just VERY BIG thank you – it is working obviously.
I had no idea to use KeyNav.
But it’s working in such a simple example My case is a little bit more complicated and I asked this question just simplified my situation. So this menu is the second screen in my application and it is constructed in such a way:
PANEL
Panel1
Label1
Button 1
Button 2
Button 3
Panel2
Label2
Button 4
Button 5
Panel3
Label3
Button 6
Button 7
Button 8
and every user can see (panels are hidden on the start) and use parts of this structure (e.g. Panel1, 3 and Button 8). I decide about it one step before (login step) and I show to the user menu only for him in the container defined:
Ext.define('Gromel.view.Menu', {
extend: 'Ext.container.Container',
requires:[
'Ext.tab.Panel',
'Ext.layout.container.Border',
'Ext.form.Label',
'Ext.form.Panel'
],
xtype: 'app-menu',
fullscreen: true,
layout: 'fit',
...
I place your code on the PANEL level and it's working almost properly. And I use the following default definition for above items:
defaults: {
margin: '0 0 10 0',
baseCls: 'x-btn-default-large',
cls: 'cap-btn',
style: 'font-size:18px;text-align: center',
height: 40,
width: '50%',
// yours:
handler: function () {
this.up('panel').activeButton = this.activeIndex;
}
}
so I modified your cls change method to:
button[method]('x-focus x-btn-focus x-btn-default-large-focus')
and your procedure is working.
Problems I can't manage now are:
as you see on the same level as buttons I have labels and I don't know how to bypass them;
more important - I want to run this procedure only on menu panel not in login panel and the rest (deeper in my structure) but this is global, so if I press ENTER on login panel I see the effect on next, menu panel; I replaced ENTER effect in the following way (I want to press ENTER on every button in menu and run different presses events):
case e.ENTER: butt.fireEvent('click', butt); break;
So if it isn’t to much for you be so kind and prompt me more please.
Try to use ExtJS KeyNav.
KeyNav provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind navigation keys to function calls that will get called when the keys are pressed, providing an easy way to implement custom navigation schemes for any UI component.
As you said
I have a panel with only four buttons.
I have work around that, I have created an small sencha fiddle demo. It will show you how is working. I hope this will help you to solve your problem.
You can also refer this Key Navigation Sample
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
title: 'Button Example with keyNav',
margin: 10,
bodyStyle: {
'border-width': '2px'
},
layout: {
type: 'vbox',
align: 'center'
},
defaults: {
xtype: 'button',
height: 50,
width: '70%',
margin: '20 0',
handler: function () {
this.up('panel').activeButton = this.activeIndex;
}
},
items: [{
text: 'My button 1',
activeIndex: 0
}, {
text: 'My button 2',
activeIndex: 1
}, {
text: 'My button 3',
activeIndex: 2
}, {
text: 'My button 4',
activeIndex: 3
}],
listeners: {
afterrender: function () {
var panel = this;
panel.keynav = Ext.create('Ext.util.KeyNav', {
target: Ext.getBody(),
scope: panel,
up: panel.doFocusOnButton,
down: panel.doFocusOnButton,
enter: panel.doFocusOnButton,
tab: panel.doFocusOnButton
});
//Remove cls on panel click
panel.el.on('click', function () {
this.doAddRemoveCls('removeCls');
}, panel)
panel.focus();
}
},
/*
* Common event will fire on key : ENTER, TAB, UP, DOWN
* #param {Ext.EventObject} e Just as Ext.Element wraps around a native DOM node
*/
doFocusOnButton: function (e) { //{ http://docs.sencha.com/extjs/4.2.5/#!/api/Ext.EventObject }
var panel = this,
button = '',
totalItem = panel.items.length - 1;
if (Ext.isDefined(panel.activeButton) == false) {
panel.activeButton = 0;
} else {
this.doAddRemoveCls('removeCls');
switch (e.getKey()) {
case e.ENTER:
case e.DOWN:
case e.TAB:
panel.activeButton++;
if (panel.activeButton > totalItem) {
panel.activeButton = 0;
}
break;
case e.UP:
panel.activeButton--;
if (panel.activeButton < 0) {
panel.activeButton = totalItem;
}
break;
}
}
this.doAddRemoveCls('addCls');
},
//This function will add or remove cls..
doAddRemoveCls: function (method) {
var panel = this,
index = panel.activeButton,
button = Ext.isDefined(index) ? panel.down('[activeIndex=' + index + ']') : null;
if (button) {
button[method]('x-focus x-btn-focus x-btn-default-small-focus')
}
}
});
I have a panel which have 2 items, a start button and a save button.
the start button is at the bottom left corner
the save button is at the bottom right corner
the save button is hidden, when shown using show() the save button appears on top of the start button. If all these hide and show calls are removed the buttons rendered in the correct location, both of them.
Anyone know why this maybe ?
It is a straight up panel with items: [startbutton, spacer, savebutton]
Oh god I really hate this one framework..
You're probably confused about the layout management in ExtJS (which is actually quite nice once you understand how it works). Also you want to make sure that you perform a doLayout after you've toggled an element's visibility to make sure that everything gets placed properly.
Look at this jsfiddle: http://jsfiddle.net/LVKyM/
Ext.onReady(function(){
var pnl = new Ext.Panel({
renderTo: 'ctn-panel',
width: 300,
cls: 'my-pnl',
bodyBorder: false,
border: false,
layout: 'hbox',
layoutConfig: {
padding: 5
},
items: [
startBtn = new Ext.Button({
text: 'start',
width: 100,
hidden: true
}), {
xtype: 'spacer',
flex: 1,
}, {
xtype: 'button',
text: 'save',
width: 100
}
]
});
new Ext.Button({
renderTo: 'button-container',
text: 'Show/hide',
handler: function(){
startBtn.show();
pnl.doLayout();
}
});
});
I need to show a refresh button on a specific card only, the title bar to which is defined in some parent Panel. I have tried in the following way:
Parent Panel:
config:
{
layout : 'fit',
items:[
{
xtype:'titlebar',
docked:'top',
title:'Directory',
items:[
{
xtype: 'button', //First Button-visible in all cards
docked: 'left',
iconCls: 'arrow_left',
action: 'back'
},
{
xtype: 'button', //Target button-to be visible in one card only
docked: 'right',
iconCls: 'refresh',
action: 'reset',
hidden: true //hiding this button
}
]
},
{
xtype:'tabpanel',
tabBarPosition:'top',
items:[
{
title: 'Tab1',
xtype: 'Card1'
},
{
title: 'Tab2',
xtype: 'Card2'
}
]
}
]
}
I have a hidden property set to true for refresh button in above panel, which i want to set false for a card.
The target card is set active on a button click. I am changing hidden property to false in the buttonTapListener, and then setting the target card as active. But the refresh button do not get visible. Here is the controller code:
onButtonTap: function()
{
...
var getParentPanelRef = this.getParentPanel();
var parentPanelItems = getParentPanelRef.getItems();
console.log(parentPanelItems.items[0].config.items[1].hidden); //Prints true
directoryMainContainerItems.items[0].config.items[1].hidden=false;
console.log(parentPanelItems.items[0].config.items[1].hidden); //Prints false
var directorySearchMainUIRef = this.getSomeOtherParentPanel();
directorySearchMainUIRef.setActiveItem(1); //Switches to target card
}
The value of hidden gets changed, but button doesn't come up. Please suggest an alternative if so. Thanks in advance.
Instead of hiding/showing the button you could add/destroy the button.
I had a similar problem a while a ago and it seems that sencha not always detects when it should redraw components.
Maybe your parent component'width is out of you browser and your button is docked right so that you can's see it.
I try to add a text filed and a button to the grid panel in extjs with following code:
var shopIdInput = new Ext.form.TextField({
emptyText: "请输入商户Id",
width: 200
});
var deleteOneShopCacheBtn = new Ext.Button({
text : '删除商户缓存',
handler: deleteOneShopCache,
minWidth : 100,
cls: "delBtn"
});
......
var grid = new Ext.grid.GridPanel({
store: store,
columns: columns,
bbar: [shopIdInput, deleteOneShopCacheBtn],
buttons: [clearRedressWordCacheBtn, clearSplitWordCacheBtn, clearRegionCacheBtn, clearCategoryCacheBtn, runCommandBtn],
items: [commandForm],
buttonAlign: 'center',
stripeRows: true,
autoExpandColumn: 'serverUrl',
//title: '批量执行指令',
sm: checkboxSelect,
frame: true,
autoHeight: true,
enableColumnHide: false,
renderTo : 'serverInfoList'
});
But the button deleteOneShopCacheBtn in bbar doesn't look like a common button as button clearRedressWordCacheBtn in buttons. It changes to a button when the mouse is on it. I have tried to fix the problem by set the property cls and fail, so what can I do?
I usually just add an icon to the button which helps it stand out. so just set a value for
iconCls: 'mybuttonicon'
and in your css
.mybuttonicon { background-image: url(../path/to/icon) !important;}
the cls config allows you to specify additional classes to which to apply to your renderable object (in your case a button) but does NOT do anything with making it change based on the mouse hovering over it, etc.
What you need is a listener on deleteOneShopCacheBtn and listen to the mouseover event(also see Sencha docs for the list of events a button responds to). You can fire off a function and make your button look like whatever you want. I am currently at work. If you still have this question when I get home tonight I can post some code.
Also see following example:
Button click event Ext JS
}
I've been trying to learn Sencha Touch and I'm stuck on something that is probably pretty obvious. I'm trying to update a tabPanel with a button event. I'd like for a tap on the first button to load 'maptestPanel' in the same panel. This is a map loaded from its own js file.
The map panel looks ok by itself:
maptestPanel = new Ext.Panel({
layout: 'fit',
fullscreen: true,
items: [map]
});
But I'm not seeing how to properly place it in the tabPanel
The code is:
Ext.setup({
icon: 'icon.png',
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
glossOnIcon: false,
onReady: function() {
var navBar = new Ext.Toolbar({
dock : 'top',
title: 'Some App Name',
});
var topPanel = new Ext.Panel({
dockedItems: [navBar],
fullscreen : true,
//html: 'Test Panel'
});
var tapHandler = function(button, event) {
btnPanel.update(maptestPanel); //I'm sure part of the problem is here
}
var SomeDate1 = new Ext.Button({
text:"Some date",
minWidth:200,
height: 45,
cls:"listButtonTop",
handler:tapHandler
});
var SomeDate2 = new Ext.Button({
text:"Another Date",
minWidth:200,
height: 45,
cls:"listButton"
});
var SomeDate3 = new Ext.Button({
text:"And Another Date",
minWidth:200,
height: 45,
cls:"listButtonBottom"
});
var btnPanel = new Ext.Panel ({
id: 'date',
items: [SomeDate1,SomeDate2,SomeDate3],
});
var tabpanel = new Ext.TabPanel({
layout: 'card',
tabBar: {
dock: 'bottom',
layout: {
pack: 'center'
}
},
fullscreen: true,
ui: 'dark',
cardSwitchAnimation: {
type: 'slide',
cover: true
},
defaults: {
scroll: 'vertical'
},
items: [{
title: 'Maps',
//html: '<h1>Place holder</h1>',
iconCls: 'maps',
cls: 'card1',
items: [btnPanel]
}, {
title: 'Favs',
html: '<h1>Place holder</h1>',
iconCls: 'favorites',
cls: 'card2',
badgeText: '4',
layout: 'fit'
//items: [SomeList, SomeOtherList, AnotherList]
}, {
title: 'Info',
html: '<h1>Place holder</h1>',
cls: 'card4',
iconCls: 'info'
}]
});
}
});
Thanks for any advice or a steer in the right direction.
There's several things you need to do to fix up that code:
1) 'Maps' has no layout. Since it has a single child item, layout: 'fit' would be appropriate here.
2) Only use fullscreen on the outermost item, you don't want the other items to be fullscreen since they are child items of other containers.
3) To dynamically add items to a container, use the add() method on container. You'll also need to call doLayout() to trigger a layout for the container.
btnPanel.add(maptestpanel);
btnPanel.doLayout();
However, in this case I don't see why you're adding the map to a panel, it doesn't give you any extra functionality. Instead, I would add the map directly to the btnPanel.
4) The btnPanel has no layout either, so you'll need to choose an appropriate layout there as well, possibly the vbox layout.
I only know "classic" sencha, but this should work the same way : So you could just add the mapPanel (but hidden) to your tabPanel, and in the button handler show it while hiding the button panel.
Besides, speaking of layouts, I don't think you need to precise layout:'card' in tabPanel since it uses a card layout by definition