Here is an example of the code I'm using, I'm creating my own component from a panel and loading with the require property
Ext.define("VMPWorld.view.Navbar.MainNavbar", {
xtype: 'MainNavbar',
extend: 'Ext.Panel',
requires: [
'VMPWorld.view.Navbar.NavbarContainer'
],
config: {
layout: {
type: 'vbox',
align: 'stretch'
},
ui: 'none',
items: [{
xtype: 'NavbarContainer',
height: 700
}]
},
initialize: function() {
this.callParent();
console.log("Called");
}
});
I've never seen such template function. If you want to call it automatically, consider initComponent or handler of some event such as render. Anyway, you should provide some additional information on how you expect the function to be called.
Related
Suppose we have defined a component (e.g. FieldSet) that we'd like to reuse in the single app (e.g. display/use it in 2 different modal windows.) This FieldSet has a reference, which we use to access it. The goal is to have these 2 windows contain independent fieldsets, so we can control and collect the inputs from each one separately.
Here's the sample fiddle that demonstrates the problem. As soon as any function triggers any lookupReference(...) call, Sencha issues the warning for "Duplicate reference" for the fieldset. It correctly creates two distinct fieldset components (by assigning different ids) on each window, but fails to properly assign/locate the references. As a result, any actions on one of these windows' fieldsets would be performed on the "unknown" one (probably on the first created one), messing up the UI behavior.
I see how it is a problem for Sencha to understand which component to use when operating on the reference, but there should be a way to reuse the same component multiple times without confusing the instances. Any help is greatly appreciated.
According to the docs on ViewController:
A view controller is a controller that can be attached to a specific view instance so it can manage the view and its child components. Each instance of the view will have a new view controller, so the instances are isolated.
This means that your use of singleton on your ViewController isn't correct, as it must be tied to a single view instance.
To fix this, I'd recommend making some modifications to your Fiddle, mainly removing the singleton: true from your VC class, accessing the views through lookup, and getting their VC's through getController to access your func method.
Ext.application({
name: 'Fiddle',
launch: function () {
/**
* #thread https://stackoverflow.com/questions/67462770
*/
Ext.define('fsContainerHandler', {
extend: 'Ext.app.ViewController',
alias: 'controller.fsContainerHandler',
// TOOK OUT singleton: true
func: function () {
var x = this.lookupReference('fsRef');
alert(x);
}
});
Ext.define('fsContainer', {
extend: 'Ext.container.Container',
xtype: 'xFSContainer',
controller: 'fsContainerHandler',
items: [{
xtype: 'fieldset',
title: 'myFieldset',
reference: 'fsRef'
}]
});
Ext.define('mainContainerHandler', {
extend: 'Ext.app.ViewController',
alias: 'controller.mainContainerHandler',
singleton: true,
onButton1Click: function () {
var win = this.getView().window1;
win.show();
// CHANGED LOGIC
win.lookup('theContainer').getController().func();
},
onButton2Click: function () {
var win = this.getView().window2;
win.show();
// CHANGED LOGIC
win.lookup('theContainer').getController().func();
}
});
Ext.define('mainContainer', {
extend: 'Ext.container.Container',
width: 400,
controller: 'mainContainerHandler',
window1: null,
window2: null,
initComponent: function () {
this.window1 = Ext.create('window1');
this.window2 = Ext.create('window2');
this.callParent(arguments);
},
items: [{
xtype: 'button',
text: 'Window 1',
reference: 'btn1',
handler: mainContainerHandler.onButton1Click,
scope: mainContainerHandler
}, {
xtype: 'button',
text: 'Window 2',
reference: 'btn2',
handler: mainContainerHandler.onButton2Click,
scope: mainContainerHandler
}]
});
Ext.define('window1', {
extend: 'Ext.window.Window',
title: 'Window1',
modal: true,
width: 100,
height: 100,
closeAction: 'hide',
// ADDED referenceHolder
referenceHolder: true,
items: [{
xtype: 'xFSContainer',
// ADDED reference
reference: 'theContainer'
}]
});
Ext.define('window2', {
extend: 'Ext.window.Window',
title: 'Window2',
modal: true,
width: 100,
height: 100,
closeAction: 'hide',
// ADDED referenceHolder
referenceHolder: true,
items: [{
xtype: 'xFSContainer',
// ADDED reference
reference: 'theContainer'
}]
});
Ext.create('mainContainer', {
renderTo: document.body
});
}
});
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'm trying to use controller in my program.Controller name is "Main" and code is given below.
refs: [
{
ref: 'navigation',
selector: 'navigation'
},
{
ref: 'ContentPanel',
selector: 'ContentPanel'
},
{
ref: 'viewport',
selector: 'viewport'
}
]
and i have a view port with following code.
Ext.define('MyApp.view.MyViewport', {
extend: 'Ext.container.Viewport',
requires: [
'MyApp.view.Header',
'MyApp.view.Navigation',
'MyApp.view.ContentPanel'
],
layout: {
type: 'border'
},
initComponent: function() {
var me = this;
Ext.applyIf(me, {
items: [
{
xtype: 'header',
height: 136,
region: 'north'
},
{
xtype: 'navigation',
width: 207,
region: 'west'
},
{
xtype: 'ContentPanel',
width: 431,
flex: 2,
region: 'center'
}
]
});
now my problem is i have to get an object of ContentPanel when i click on naviagation(tree panel). i tried using
var content= this.getContentPanel();
i have one more form panel add i want to add that to the controller. and i want to get the instance of the form and put it inside the content panel and display.
var form= this.getMyform();// i didnt add Myform to the controller yet because i dont know to add reference properly
content.add(form);
My main problem is that i cant instantiate the content panel and form in ItemClick event of navigation(tree panel)
thank you
A ref should start with a lower case letter. The same is valid for xtypes. ref: 'contentPanel' will define a getter getContentPanel. Since contentPanelis different from ContentPanel, I'm not sure, if in your case the getter is created or not.
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