Related
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);
I am using the lastest sencha cmd for the build with ext-5.0.1.
Everythings look good during the development status (http://www.imageupload.co.uk/5Med) but after the build.
All the textfields collapsed like shown (http://www.imageupload.co.uk/5MeQ), and have no response to the changes in width, minWidth, flex... etc.
And also the properties y and x are not functioning.
If someone had had similar situation before, please help, thx
My cmd is v5.0.3.324
Here are part of my code:
In my Main.js:
Ext.define('ExtTest2.view.main.Main', {
extend: 'Ext.container.Container',
requires: [
'ExtTest2.view.main.MainController',
'ExtTest2.view.main.MainModel'
],
xtype: 'app-main',
controller: 'main',
viewModel: {
type: 'main'
},
layout: {
type: 'fit'
},
itemId:'Stage'
});
MainController.js:
Ext.define('ExtTest2.view.main.MainController', {
extend: 'Ext.app.ViewController',
requires: [
],
alias: 'controller.main',
init: function(){
this.Start();
},
Start: function(){
var data = {
itemId: "Page_Login",
xtype: "panel",
items: [
{
padding: 30,
layout:{
type: 'vbox',
align: 'center'
},
xtype: "fieldset",
y: "30%",
height: 150,
items: [
{
xtype: "textfield",
itemId: "Textfield_Username",
fieldLabel: "用戶名稱",
labelStyle: "color:#FFFFFF"
},
{
fieldLabel: "密碼",
itemId: "Textfield_Password",
labelStyle: "color:#FFFFFF",
xtype: "textfield"
},
{
itemId: "Button_Login",
text: "登入",
width: 100,
xtype: "button"
}
]
}
]
};
var container = Ext.ComponentQuery.query('#Stage')[0];
container.removeAll();
container.add(data);
container.updateLayout();
}
});
It is overnested because you add unnecessary container to app-main containing the fields.
It is very unusual to manipulate views from view controller like that - create a class for the fieldset, give it an alias (xtype) and simply instantiate that. Cramming controller handlers together with view definitions shall inevitably lead to Spaghetti Code.
You use vbox layout, without any flex or height to hold form fields. Form fields behave best in anchor layout that is the default for Ext.form.Panel.
I have got the tabpanel - it's the main form (view).
In this tabpanel I define the different tabs - xtype:'panel'.
So, I have one main(controller) , main view and some tabs views.
The tab's views are referenced in main view.
I want to define listener of activate event of some child's panel in main controller.
How can I do that?
the main controller :
Ext.define('KP.controller.account.apartment.Main', {
extend: 'Ext.app.Controller',
views: ['account.apartment.Main',
'account.apartment.Requisites'
],
models: ['account.apartment.Requisites'
],
stores: ['account.apartment.Requisites'
],
init: function () {
}
});
The main view:
Ext.define('KP.view.account.apartment.Main', {
extend: 'Ext.window.Window',
alias: 'widget.ApartmentData',
height: 566,
width: 950,
activeItem: 0,
layout: {
type: 'fit'
},
autoShow: false,
initComponent: function() {
var me = this;
Ext.applyIf(me, {
items: [
{
xtype: 'tabpanel',
activeTab: 0,
deferredRender: true,
items: [
{
xtype: 'RequisitesApartment'
}
]
}
]
});
me.callParent(arguments);
}
});
The child panel RequisitesApartment (view):
Ext.define('KP.view.account.apartment.Requisites', {
extend: 'Ext.panel.Panel',
alias: 'widget.RequisitesApartment',
id: 'panel_accountrequisites',
height: 350,
width: 1124,
autoScroll: true,
layout: {
type: 'fit'
},
listeners: {
activate: function () {
....load data....
...this listeners I want to push in 'main' controller...
}
},
initComponent: function () {
var me = this;
var grid_store = Ext.create('KP.store.account.apartment.Requisites');
Ext.applyIf(me, {
dockedItems: [
{
xtype: 'gridpanel',
height: 260,
autoScroll: true,
dock: 'bottom',
store: grid_store,
id: 'r_gridFlatParams',
forceFit: true,
columns: [
...some columns....
],
viewConfig: {
}
}
]
});
me.callParent(arguments);
}
});
Register it directly as control within the responsible controller
Here is a example with a working query. For sure you just will need the query, but I think it's a good example. The custom cfg property ident make it easy find each tab. As in the example below you will have specify a tabConfig within each panel and define the ident there.
Ext.create('Ext.tab.Panel', {
width: 400,
height: 400,
renderTo: document.body,
items: [{
title: 'Foo',
tabConfig: {
ident: 'foo'
},
}, {
title: 'Bar',
tabConfig: {
ident: 'bar',
title: 'Custom Title',
tooltip: 'A button tooltip'
}
}]
});
console.log(Ext.ComponentQuery.query('tabpanel tabbar tab[ident=foo]')[0]);
console.log(Ext.ComponentQuery.query('tabpanel tabbar tab[ident=bar]')[0]);
Another way is to use css id's which can be queried like '#my-name' but I recommend to use a custom one as in the example above
Well, I should put this code in 'main'(controller):
this.control({
'ApartmentData tabpanel RequisitesApartment': {
activate: function () {
console.log('hello!');
}
}
});
The problem was in wrong selector , that I used.
The correct selector is :
'ApartmentData tabpanel RequisitesApartment'
There 'ApartmentData'(define like a alias: 'widget.ApartmentData') - is the 'window' xtype -the main form.
tabpanel - panel with tabs in 'window', and 'apartServList'(define like alias: 'widget.RequisitesApartment') - the some panel.
Thanks for sra!
the correct thing to do is to pass a config object to the member function control into controller init function. From Sencha documentation : The control function makes it easy to listen to events on your view classes and take some action with a handler function.
A quick example straight from extjs docs:
Ext.define('MyApp.controller.Users', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'viewport > panel': {
render: this.onPanelRendered
}
});
},
onPanelRendered: function() {
console.log('The panel was rendered');
}
});
Hope this helps.
Cheers
I am trying to create a form embedded inside a Panel and trying to retrieve the contents of the form fields from within the controller.
Below is my view and controller code.
Ext.define('MyApp.view.SignIn', {
extend: 'Ext.Container',
requires: ['Ext.Button','Ext.form.Panel'],
xtype: 'loginPage',
config : {
fullscreen: true,
items: [
{
docked: 'top',
xtype: 'titlebar',
html:'<img src="resources/icons/logo.png" />',
items: {
iconMask: true,
align: 'left',
text: 'Sign In',
handler: function(){
var panel = Ext.create('Ext.Panel', {
left: 0,
padding: 10,
xtype: 'loginPage',
url: 'contact.php',
layout: 'vbox',
id: 'signinform',
items: [
{
xtype: 'fieldset',
title : 'Enter Login Information:',
instructions: 'All fields are required',
layout: {
type: 'vbox'
},
items: [
{
xtype: 'emailfield',
name: 'Email',
label: 'Email',
placeHolder: 'Valid email'
},
{
xtype: 'passwordfield',
name: 'Password',
label: 'Password',
placeHolder: '6 characters'
}]
},
{
layout: 'hbox',
items: [
{
xtype: 'button',
text: 'Login',
ui:'confirm',
id:'Login-btn',
width: '100px',
flex: 1
}, {
width: '100px'
}, {
xtype: 'button',
text: 'Register',
ui: 'decline',
width: '100px',
flex: 1,
handler: function(){
this.getParent().getParent().destroy();
}
}]//Buttons array
}//Form completion
]
}).showBy(this); //Panel created
}//Function complete
}
},
{
layout: {
type: 'vbox',
pack:'center',
align: 'center'
},
items:[{
html:'<h2>My tool</h2><h3 style="color:#F47621">Simple, intuitive and powerful data management tool.</h3>',
styleHtmlContent: true,
}
]
},
]
},
initialize: function() {
this.callParent(arguments);
},
});
And here is my controller code. I just checked the controller code it seemed to be fine with a simpler form view. So I guess the issue is with the view.
Ext.define("MyApp.controller.SignIn", {
extend : 'Ext.app.Controller',
config : {
refs : {
home : '#homePage',
login : '#loginPage',
SignIn : '#signinform'
},
control : {
'#Login-btn': {
tap : 'onLoginButtonTap'
}
}
},
onLoginButtonTap: function() {
var formValues = this.getSignIn().getValues();
console.log(formValues.username);
console.log(formValues.password);
}
});
]
},
initialize: function() {
this.callParent(arguments);
},
});
What is wrong with the form creation in the View page. Why is the form coming as undefined. Experts please help
Here:
var panel = Ext.create('Ext.Panel', {
...
You are instantiating a simple panel not a form panel. May be you want to say:
var panel = Ext.create('Ext.form.Panel', {
...
I believe the reason you are getting undefined is because those components don't exist when the view is created.
Instead of creating the panel in your view (Ext.create('Ext.Panel'...) with a handler function you should consider defining it as an item in your xtype:loginpage container with hidden : true. Then via a listener from the controller call show() on the hidden component.
I find that if I keep event listeners/handlers in my controllers, and layout/display logic in my views my application becomes much more managable.
I also try to avoid calling Ext.create(Ext.SomeCmpt) and instead use the hidden attribute.
Hope this helps.
in a Extjs application I have a Grid and a Tabs line over it. Content of the Grid depends on the selected Tab.
Say tabs has Jan-Feb-Mar-... values. Clicking of the Tab I would reload grid's store
Question: is it possible to avoid duplicating of the 12 grid components in favor to have one shared instance?
Thanks
Disclaimer: searching at the sencha's forum, google, stackoverflow was not successful :(
It is, but it would require more effort than it is worth. Just create a prototype for your component, so that you can create new instances really quickly.
I haven't tried this myself, but I imagine that you could create a TabPanel with empty tabs and size the TabPanel so that only the tab strip is visible. Under that (using the appropriate layout, border, vbox, etc.) create your GridPanel and use the TabPanel's activate event to reload the grid based on the currently-active tab.
Hope the following implementation meet your needs
1. Create your custom grid and register it
2. place it tab panel
As the grid is created using xtype, it would not create 12 instances when you change tabs.
Application.PersonnelGrid = Ext.extend(Ext.grid.GridPanel, {
border:false
,initComponent:function() {
Ext.apply(this, {
store:new Ext.data.Store({...})
,columns:[{...}, {...}]
,plugins:[...]
,viewConfig:{forceFit:true}
,tbar:[...]
,bbar:[...]
});
Application.PersonnelGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent
,onRender:function() {
this.store.load();
Application.PersonnelGrid.superclass.onRender.apply(this, arguments);
} // eo function onRender
});
Ext.reg('personnelgrid', Application.PersonnelGrid);
var panel = new Ext.TabPanel({
items:[{
title:'Jan',
items: [{xtype:'personnelgrid'}]
}, {
title: 'Feb',
items: [{xtype:'personnelgrid'}]
}
....
{
title: 'Dec',
items: [{xtype:'personnelgrid'}]
}]
})
Since this is the only place discussed about this until now, I share what I just found.
The trick is use dockedItems in ExtJs 4 (Not sure either grid can be added into tbar in ExtJs 3)
When changing the active tab, only body will be change but not the docked item. Just set the grid height equal to the body during boxready and resize so that we can't see the body anymore.
This is the code for ExtJs 4.2 MVC that also make use of refs.
Ext.define('app.controller.Notification', {
extend: 'Ext.app.Controller',
views: ['notification.List'],
stores: ['Notification'],
models: ['Notification'],
refs: [{
ref: 'pnlNotif',
selector: 'pnlNotif'
}, {
ref: 'notifList',
selector: 'notifList'
}],
init: function () {
this.control({
'dbPnlNotif': {
added: this.pnlNotifAdded,
boxready: this.calcNotifListSize,
resize: this.calcNotifListSize,
tabchange: this.pnlNotifTabChange
}
});
},
pnlNotifAdded: function (pnlNotif) {
pnlNotif.add({ title: '1', html: '1' });
pnlNotif.add({ title: '2', html: '2' });
pnlNotif.add({ title: '3', html: '3' });
},
calcNotifListSize: function (pnlNotif) {
// calc the notification list height to make sure it use the whole body
// This way we can use only one instance of list to display for each tabs
// because the list is rendered as dockedItems
var height = pnlNotif.getHeight();
var headerHeight = pnlNotif.getDockedItems()[0].getHeight();
var tabBarHeight = pnlNotif.getDockedItems()[1].getHeight();
height = height - headerHeight - tabBarHeight;
if (this.getNotifList().getHeight() !== height) {
this.getNotifList().setHeight(height - 1);// - 1 to include border bottom
}
},
pnlNotifTabChange: function (pnlNotif, newTab) {
// do something to filter the list based on selected tab.
}
});
Ext.define('ML.view.Notification', {
extend: 'Ext.tab.Panel',
alias: ['widget.pnlNotif'],
title: 'Notification',
dockedItems: [{
xtype: 'notifList'
}]
});
Ext.define('ML.view.notification.List', {
extend: 'Ext.grid.Panel',
alias: 'widget.notifList',
dock: 'top',
store: 'Notification',
initComponent: function () {
this.columns = [
...
];
this.callParent(arguments);
}
});
Try this
var gridJanName = Ext.create('Ext.grid.Panel', {
enableColumnHide: false,
autoScroll:true,
store: storeJanNameGroup,
border:true,
stripeRows: true,
columnLines:false,
loadMask: true,
tbar:tbgridTools,
margin: '1 1 1 1',
pageSize: 100,
maxWidth:700,
features: [groupFeature],
selModel: {
mode: 'MULTI'
},
columns: [
{xtype:'rownumberer',width:50},
{dataIndex:'id', hidden:true},
//etc
]
});
var gridFebName = Ext.create('Ext.grid.Panel', {
enableColumnHide: false,
autoScroll:true,
store: storeJanNameGroup,
border:true,
stripeRows: true,
columnLines:false,
loadMask: true,
tbar:tbgridTools,
margin: '1 1 1 1',
pageSize: 100,
maxWidth:700,
features: [groupFeature],
selModel: {
mode: 'MULTI'
},
columns: [
{xtype:'rownumberer',width:50},
{dataIndex:'id', hidden:true},
//etc
]
});
//
//etc grid
//
var JanPanel = Ext.create('Ext.panel.Panel', {
title:'Jan',
bodyPadding: 5,
Width:780,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [gridJanName]
});
var FebPanel = Ext.create('Ext.panel.Panel', {
title:'Feb',
bodyPadding: 5,
Width:780,
layout: {
type: 'hbox',
align: 'stretch'
}
//,items: [gridFebName]
});
var MarPanel = Ext.create('Ext.panel.Panel', {
title:'Mar',
bodyPadding: 5,
Width:780,
layout: {
type: 'hbox',
align: 'stretch'
}
//,items: [gridMarName]
});
//etc
var eachMonthstabs = Ext.create('Ext.tab.Panel', {
minTabWidth: 130,
tabWidth:150,
//Width:750,
scroll:false,
autoHeight: true,
id:'timestabs',
enableTabScroll:true,
items: [
{
xtype:JanPanel
},
{
xtype:FebPanel
},
{
xtype:MarPanel
}
///etc
]
});
For me good solution was to use a left toolbar called lbar with list of buttons and a single grid instead of tabpanel