I extended a tabpanel and registered it like such:
DVI.DviDashboard = Ext.extend(Ext.TabPanel, {
initComponent: function(){
Ext.apply(this, {
activeTab: 0,
items: [item1, item2]
});
DVI.DviDashboard.superclass.initComponent.call(this);
}
});
Ext.reg('dviDashboard', DVI.DviDashboard);
When rendered, I have a tabpanel with two tabs, item1 and item2. I would like to programatically add new tabs through the TabPanel's add() method. I am unclear how to access the tabpanel's methods however after extending.
(Stolen #amol's answer)
It'll be as simple as calling .add on the instance.
In the following example, you may want to check out how I access the instance through this from the change of scope. You may want to read up more about the event handling by checking out this manual
Example code: jsfiddle
var DVI = {};
DVI.DviDashboard = Ext.extend(Ext.TabPanel, {
initComponent: function() {
Ext.apply(this, {
activeTab: 0,
items: [{
title: 'Tab 1',
html: 'Tab 1'
}, {
title: 'Tab 2',
html: 'Tab 2'
}],
buttons: [{
text: 'Add Tab',
handler: function() {
var content = 'Tab '+(this.items.getCount()+1);
this.add(new Ext.Panel({
title: content,
html: content
}));
this.setActiveTab(this.items.getCount()-1);
},
//This 'this' is referring to your tabpanel, and by doing so,
//the 'this' in your button's handler function is in fact the object
//that you've set here, which is, the tabpabel itself.
scope: this
}]
});
DVI.DviDashboard.superclass.initComponent.call(this);
}
});
Ext.reg('dviDashboard', DVI.DviDashboard);
var dviDashboard = new DVI.DviDashboard({
renderTo: Ext.getBody()
});
Your instance of DVI.DviDashboard is a TabPanel, so you can treat it as such:
var dashboard = new DVI.DviDashboard();
dashboard.add(otherTab);
UPDATE:
Make sure you call tabPanel.doLayout() after adding a new tab, so that the tab gets rendered and laid out. Ext waits for you to call doLayout() in case you want to add tabs in batch fashion.
This is the code used to add the tab:
function buildDecisionMatrix() {
var db = new DVI.DviDashboard();
db.add({
title: 'New Tab',
xtype: 'grid',
iconCls: 'tabs',
html: 'Tab Body',
closable: true
}).show();
db.doLayout();
}
When I execute the function, the DOM shows the tab created but the tab is not displayed. Perhaps I am calling the doLayout() method on the wrong thing?
I was creating the DviDashboard using xtype like this:
tabPanel = {xtype: dviDashboard}
The function I wrote to add tabs to this panel originally looked like this:
function buildDecisionMatrix() {
var db = new DVI.DviDashboard();
db.add({
title: 'New Tab',
xtype: 'grid',
iconCls: 'tabs',
html: 'Tab Body',
closable: true
});
db.doLayout();
}
Problem was doLayout() was not rebuilding the panel with the tab. So I modified the creation of the tabPanel with an id:
tabPanel = {xtype: dviDashboard, id: 'dviDashboard'}
So I was able to get the tabPanel as a component. Then the function I build to add the tab was modified like so:
function buildDecisionMatrix() {
//var db = new DVI.DviDashboard();
var db = Ext.getCmp('dviDashboard')
var newDb = db.add({
title: 'New Tab',
xtype: 'grid',
iconCls: 'tabs',
html: 'Tab Body',
closable: true
});
db.doLayout();
dv.setActiveTab(newDb);
}
And this worked. Thanks to all that responded.
Related
Here's a description of my Fiddle
I have defined a Window and a Form Panel
I have created instances of the Window and the Form panel defined above
Added the Form panel to the Window
Called the .show() on the Window to show the window (which
now also includes the form)
The form Panel declaration includes the buttons. But now the buttons do not show up.
Ext.application({
name: 'My Window',
launch: function () {
Ext.define('MyWindow', {
extend: 'Ext.window.Window',
title: 'My Window'//,
// renderTo: Ext.getBody()
});
Ext.define('MyForm', {
extend: 'Ext.form.Panel',
bodyPadding: 5,
width: 350,
// The form will submit an AJAX request to this URL when submitted
url: '',
// Fields will be arranged vertically, stretched to full width
layout: 'anchor',
defaults: {
anchor: '100%'
},
// The fields
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank: false
}, {
fieldLabel: 'Last Name',
name: 'last',
allowBlank: false
}],
// Reset and Submit buttons
buttons: [{
text: 'Reset',
handler: function () {
this.up('form').getForm().reset();
}
}, {
text: 'Submit',
formBind: true, //only enabled once the form is valid
disabled: true,
handler: function () {
var form = this.up('form').getForm();
if (form.isValid()) {
form.submit({
success: function (form, action) {
Ext.Msg.alert('Success', action.result.msg);
},
failure: function (form, action) {
Ext.Msg.alert('Failed', action.result.msg);
}
});
}
}
}]
});
var myWindow = new MyWindow();
var myForm = new MyForm();
myWindow.items.add(myForm);
myWindow.show();
// var myForm = new MyForm();
}
});
Here's the fiddle
This must be related to some documented behavior of the Form or the Window. What could that be?
Also, architecturally, I would like to define these components separately and use them as needed. So is there a design pattern that is better than this?
Any component that is going to contain other components will generally need to have a layout specified. Add layout: 'fit' to your MyWindow config and it should work.
Google ExtJS MVC for guidelines on the recommended way to design ExtJS applications. I also find that the ExtJS 6 examples page can be quite useful. The KitchenSink one is nice because it contains a ton of different examples of small applications built using the MVC design pattern. (Pick an example from that link and then expand the Details pane on the right.)
I want to add a button into a panel to the exact position where I clicked.
SO I have tried like as follows, this the structure of my Ext.widget element
Ext.widget({
xtype : 'mz-form-widget',
itemId: 'shopableImage',
anchor: "100%",
defaults: {
xtype: 'textfield',
listeners: {
controller: '',
change: function (cmp) {
controller = cmp;
cmp.up('#shopableImage').updatePreview();
}
}
},
items: [
{
xtype: "tacofilefield",
itemId: "imageUploadButton",
text: "Upload images"
},
{
xtype: 'panel',
width: 350,
height: 350,
itemId:'container',
id:'container',
bodyStyle:{"background":"url('http://www.easyvectors.com/assets/images/vectors/vmvectors/jeans-girl-vector-27.jpg')","border":"1px solid #eee"},
listeners: {
click: {
element: 'el', //bind to the underlying el property on the panel
fn: function(a,b,c,d){
console.log(a.browserEvent.clientX - b.offsetLeft);
console.log(a.browserEvent.clientY - b.offsetTop);
console.log(c);
this.down('#container').addItem({"xtype":"button","text":"+"});
}
},
dblclick: {
element: 'body', //bind to the underlying body property on the panel
fn: function(){ console.log('dblclick body'); }
}
}
}
The following line throwing me error.
this.down('#container').addItem({"xtype":"button","text":"+"});
UPDATE
this.down('#container')
is returning null.
Please give me your suggestions regarding this?
There are two problems here, one is causing the error and another is a potential time bomb:
addItem does not exist, the correct method name is add
You use id's on components and that is a very bad practice, however, it does not the immediate cause of the error
In my code, I create a panel object like below:
var grid = Ext.create('Ext.grid.Panel', {});
Then I am trying to define a widget which should contain the above panel as one of it's items.
I got the definition of my widget working fine. But how can I include the above grid object so that it is rendered as part of the widget:
Ext.define('Ext.simplegridwidget.GridTest', {
extend: 'Ext.panel.Panel',
alias: 'widget.gridtest',
title: 'User Management'
});
An even better approach so that everything related to my widget stays within the class definition...
Ext.define('Ext.simplegridwidget.GridTest', {
extend: 'Ext.panel.Panel',
alias: 'widget.gridtest',
title: 'User Management',
initComponent: function() {
var grid = Ext.create('Ext.grid.Panel', {});
Ext.apply(this, {
items: [ grid, details]
});
return this.callParent(arguments);
}
});
Ok.. figured it out. Not too difficult after all...
var grid = Ext.create('Ext.grid.Panel', {});
Ext.define('Ext.simplegridwidget.GridTest', {
extend: 'Ext.panel.Panel',
alias: 'widget.gridtest',
title: 'User Management',
items: [grid]
});
I'm going to ask another newbie question. I have come across multiple ways for a child to reference functions and data defined at the parent class level, but I'm not sure what is the recommended way. Below is an example that I am dealing with, but this topic is generally important for me since I do not have a good understanding of reference and scope of parents and children. How can I reference functions and data of a parent from a child of a child element?
As usual, any help will be highly appreciated.
Mohammad
San Jose, CA
/******
This is a floating panel with a formpanel inside it, that has an email field and a button to process the email.
When the button is tapped, I want to call the processEmails() function from the button.
******/
Ext.define('myapp.view.ForwardPanel', {
extend : 'Ext.Panel',
xtype : 'forwardPanel',
initialize: function() {
this.callParent(arguments);
var btn = {
xtype: 'button',
ui: 'action',
text: 'Send',
listeners: {
tap: function(){
processEmails(); //<- **How can I reference and call this function?**
// This function is defined at the parent class level
// (indicated at the bottom of the code listing)
}}
};
var form = {
items: [{
xtype: 'fieldset',
instructions: 'Enter multiple emails separated by commas',
title: 'Forward this message.',
items: [ {
xtype: 'emailfield',
name: 'email',
label: 'Email(s)'
},btn] // The button is added to the form here
}]
};
this.add(form);
},
// this is the parent level function I want to call upon button tap.
processEmails: function(){
console.log('Processing email...');
}
});
I'm not sure about a "right" way to do it, but this is what I would do, and what I see most of the time in the Sencha forum and in their own code:
Ext.define('myapp.view.ForwardPanel', {
...
initialize: function() {
this.callParent(arguments);
var me = this; // <---- reference to the "ForwardPanel" instance
var btn = {
xtype: 'button',
ui: 'action',
text: 'Send',
listeners: {
tap: function(){
me.processEmails(); // <-- notice the "me" in front
}
}
};
...
},
// this is the parent level function I want to call upon button tap.
processEmails: function(){
console.log('Processing email...');
}
});
You can make use of prototype to achieve it:
myapp.view.MyView.prototype.processEmails.call(this);
Here is a working fiddle: http://www.senchafiddle.com/#MvABI
I've got a few different cards in my app, and I'm trying to activate one of my sub cards from my homepage screen.
Here is the pertinent information.
Setup
Ext.setup({
id: 'Ext-setup',
onReady: function () {
rpc.main.init();
}
});
Main
rpc.main = {
init: function () {
var rootPanel = new Ext.TabPanel({
id: 'rpc-rootPanel',
fullscreen: true,
layout: 'card',
region: 'center',
items: [
rpc.controllers.HomeController,
rpc.controllers.VimeoController,
]
});
}
};
HomeController
rpc.controllers.HomeController = new Ext.Panel({
id: 'rpc-controllers-homecontroller',
layout: 'card',
items: [rpc.views.Home.index],
listeners: {
activate: function () {
if (rpc.stores.HomeStore.getCount() === 0) {
// This store uses the rpc.templates.AboutDetails XTemplate
rpc.stores.HomeStore.load();
}
}
}
});
Home Index View
rpc.views.Home.index = new Ext.DataView({
id: 'rpc-views-home-index',
itemSelector: 'div.home-index',
tpl: rpc.templates.AboutDetails,
store: rpc.stores.HomeStore,
fullscreen: true,
});
Vimeo Controller
rpc.controllers.VimeoController = new Ext.Panel({
id: 'rpc-controllers-VimeoController',
layout: 'card',
fullscreen: true,
items: [rpc.views.Vimeo.index,
rpc.views.Vimeo.Details]
});
Vimeo Index View
rpc.views.Vimeo.index = new Ext.Panel({
id: 'rpc-views-Vimeo-index',
layout: 'fit',
dockedItems: [{xtype: 'toolbar', title: 'Videos'}]
// stuff left out to keep it clean
});
The Template I'm using to try and activate the card This is where you'll see the javascript call javascript:goToCard();
rpc.templates.AboutDetails = new Ext.XTemplate(
' <tpl for=".">',
' <div class="padded">',
' <div class="rounded-div">',
' <h1>RockPointe Church</h1>',
' <span class="rpc-sub">One church meeting in multiple locations.</span>',
' </div>',
' <div>',
' <div id="quick-nav">',
' <ul>',
' <li><span onclick="javascript:goToCard(\'rpc-controllers-VimeoController\',\'rpc-views-Vimeo-index\');">Videos</span></li>',
' <li><span onclick="javascript:goToCard()">Events</span></li>',
' <li><span onclick="javascript:goToCard()">Sites</span></li>',
' </ul>',
' <br clear="left">',
' </div>',
' </tpl>'
And finally, the goToCard(); method
function goToCard(panelId, cardId) {
Ext.getCmp(panelId).setActiveItem(cardId);
}
The problem is simple... nothing happens when I click on the
<span onclick="javascript:goToCard(\'rpc-controllers-VimeoController\',\'rpc-views-Vimeo-index\');">Videos</span>
If I run the code directly in my console
Ext.getCmp('rpc-controllers-VimeoController').setActiveItem('rpc-views-Vimeo-index');
I get the following output.
subclass
additionalCls: Array[0]
autoRender: true
body: El.Ext.Element.Ext.extend.constructor
cardSwitchAnimation: "slide"
componentCls: "x-panel"
componentLayout: subclass
container: El.Ext.Element.Ext.extend.constructor
dockedItems: Ext.util.MixedCollection
el: El.Ext.Element.Ext.extend.constructor
events: Object
fullscreen: true
getTargetEl: function () {
height: 306
hidden: true
hiddenOwnerCt: false
iconCls: "tv"
id: "rpc-controllers-VimeoController"
initialConfig: Object
items: Ext.util.MixedCollection
layout: subclass
layoutOnShow: Ext.util.MixedCollection
monitorOrientation: true
mons: Array[0]
needsLayout: false
originalGetTargetEl: function () {
ownerCt: subclass
renderData: Object
renderSelectors: Object
renderTo: null
rendered: true
scroll: "vertical"
scrollEl: El.Ext.Element.Ext.extend.constructor
scroller: Ext.util.Scroller.Ext.extend.constructor
tab: subclass
title: "Video"
width: 798
proto: F
But nothing actually happens :-(
Basically, I don't get an error, nor does the appropriate view load.
I also tried
Ext.getCmp('rpc-controllers-VimeoController').layout.setActiveItem('rpc-views-Vimeo-index');
But the response was even less...
False
If I just run
Ext.getCmp('rpc-controllers-VimeoController');
I can see the 'rpc-views-Vimeo-index' ID within the items array.
This is because your whole application structure is fairly bizarre. You're creating panels and calling them controllers for some reason and then nesting these panels.
All that aside-- the reason you're not seeing anything is because while you are setting the active item on the 'rpc-controllers-VimeoController' panel you never tell it to change the active item of the panel being displayed-- which from the looks of your nesting madness is 'rpc-rootPanel'. So you'd need to set the active item of 'rpc-rootPanel' to your 'rpc-controllers-VimeoController' and then set the active item of 'rpc-controllers-VimeoController' to rpc-views-Vimeo-index. /facepalm
Despite the bad design practices to answer your question you can most likely just do this:
function goToCard(panelId, cardId) {
Ext.getCmp('rpc-rootPanel').setActiveItem(1);
Ext.getCmp(panelId).setActiveItem(cardId);
}
You'll need to have some if-thens in there to check what panelId your link is for and set the root panel active item accordingly. The above is specific for your referenced link...