ExtJS 4.2.1 - Cannot get View instance from the controller - extjs

In my app I have the viewport with one item, a main view, which it is a simple class extending from Ext.container.Container.
I have a main controller too, and I'm trying to get the view instance, so dynamically I can push the corresponding items if the user is logged or not.
I've tried using views: ['MainView'], refs[ { selector: 'thextype' }], etc with no luck.
I was using the reference (ref) in sencha touch to do this kind of things, can you help me with Extjs v4.2 ?
Just for clarification, I'm not trying to get the DOM element, I'm trying to get the view instance with the associated methods.
Thanks in advance,

Define xtype of your view:
xtype: 'mainview'
and then in your controller:
requires: ['...'] // your view class
// ...
refs: [{
ref: 'mainView',
selector: 'mainview' // your xtype
}]
and then you can get the instance of your view in the controller with this.getMainView()

I've tried that without good results.
What I'm trying to do is something like. Based on your response should work
Ext.define('MyApp.view.MainView', {
extend: 'Ext.container.Container',
alias: 'widget.mainContainer',
cls: ['mainContainer'],
items: [
{
xtype: 'panel',
items: [
{
html: "my view"
}
]
}
]});
Ext.define('MyApp.controller.MainController', {
extend: 'MyApp.controller.BaseController',
refs: [
{
ref: 'mainContainer',
selector: 'mainContainer'
}
],
init: function() {
this.getApplication().on({
openDashboard: this.onOpenDashboard
});
},
onOpenDashboard: function() {
var mainContainerView = this.getMainContainer();
mainContainerView.showSomething(); //mainContainerView should be an instance of the view.
}});
Where, openDashboard event is fired if after a login success.

After some time debugging, it seems the problem was the context where it was being called the function.
I've added in the init method a line like:
var openCrmDashboardFn = Ext.Function.bind(this.onOpenCrmDashboard, this);
and it worked.
Thank you!

Related

How to query all ExtJS components which have some config option set

I've specified showCondition custom property for some items inside view config. How can I query all such components?
I've tried Ext.ComponentQuery.query(). The problem is, that query() returns to me correct number of elements, but there are not 'real' components, that is, when I try to do elements[0].hide(), is makes no effect.
I noticed, that when I get the same element using ref in controller class, hide() works perfectly.
After that I've console.log-ed results of both ways of getting the element and noticed strange things. First, returned element have different html id attributes (textfield-1115 and textfield-1089). Second, the element which is returned by query() method already has hidden=true property (that's why hide() has no effect). Both elements are textfield components.
Below are related code parts. The important is in onAfterRenderForm().
In view:
Ext.define('MyApp.view.Test', {
extend: 'Ext.container.Container',
alias: 'widget.test',
layout: 'fit',
initComponent: function() {
Ext.apply(this, {
items: [
{
title: 'form',
itemId: 'myForm',
xtype: 'form',
items: [
{
xtype: 'textfield',
fieldLabel: 'code',
showCondition: 'is-root',
allowBlank: false,
vtype: 'alphanum'
}
]
}
]
});
this.callParent(arguments);
}
});
In controller:
Ext.define('MyApp.controller.Test', {
extend: 'Ext.app.Controller',
requires: [
'MyApp.view.Test'
],
refs: [
{
ref: 'codeField', selector: '[showCondition]'
}
],
init: function() {
this.control(
{
'#myForm': {
afterrender: this.onAfterRenderForm
}
);
},
onAfterRenderForm: function(oForm) {
var elements = oForm.query('[showCondition]');
console.log(elements[0]);
console.log(this.getCodeField());
if(elements[0].id == this.getCodeField().id)
alert('Elements are not the same!!!');
}
});
This:
refs: [{
ref: 'codeField', selector: '[showCondition']
}]
is subtly different from oForm.query('[showCondition]')[0].
For the ref you a grabbing the first component found with a defined showCondition value. In oForm.query, you are grabbing the first component found that is a child of oForm which has a defined showCondition value.
That means that if you have other fields in any view within your app that have showCondition defined on them, the call to the generated getter for the ref could return any one of those fields. It depends on what order Ext decides to put them in.
It sounds to me like a couple things are happening
You have other fields in your app that have showCondition defined but are not on the form your controller is looking at.
Your view is being rendered in the hidden state. Is is being added as an item in a card layout or something like that?

extjs change panel title on an event

I have a grid panel like this
Ext.define('sCon.view.SalesGrid',{
extend: 'Ext.grid.GridPanel',
title: 'Sales Data',
//other params
initComponent: function(){
this.callParent(arguments);
}
});
On a click event, I want to change the title of this panel. My code inside the controller looks like this.
Ext.define('sCon.controller.SalesGridController', {
extend: 'Ext.app.Controller',
views: ['SalesGrid'],
// other handlers
changeTitle: function(newTitle){
this.getView('SalesGrid').setTitle('title_changed');
}
Currently it says that it does not have a function as setTitle(). But the docs say that grid panel has setTitle() function. I also tried changing the title using the 'title' variable like
changeTitle: function(newTitle){
this.getView('SalesGrid').title = 'title_changed';
Neither works.. Please help.
UPD: Here is some refs docs from Sencha for ExtJS 4.1.
Use refs property of your controller to get references to any Components.
In your example:
Ext.define('sCon.view.SalesGrid',{
extend: 'Ext.grid.GridPanel',
title: 'Sales Data',
alias: 'widget.salesgrid',
//other params
initComponent: function(){
this.callParent(arguments);
}
});
In Controller add:
refs: [
{ ref: 'salesGrid', selector: 'salesgrid', },
]
Then you can access your SalesGrid view from anywhere in your controller like this.getSalesGrid(); method.
In Your case:
changeTitle: function(newTitle){
this.getSalesGrid().setTitle('title_changed');
}
Note
In the decribed case webbandit answer is the best for accessing a view instance, this one
stays for clarification on the use of autogenerated getters.
The selector Method you use just gives you the class and not an instance of it!
You should do it this way
this.getView('SalesGrid').create().setTitle('title_changed');
See API

How to send data from a list view to a detail view with Sencha?

I have a generic class that extends Ext.dataview.List, and it is currently listing out a set of blogs that I have:
Ext.define('Blog.view.BlogList',{
extend: 'Ext.dataview.List',
xtype: 'blogList',
config: {
cls: 'blogList',
emptyText: 'No blogs found...',
itemCls: 'blogListItem',
itemTpl: [
'<div class="blogThumb"><img src="{image.medium}" /></div>',
'<div class="blogTitle">{title}</div>',
].join(''),
loadingText: 'Loading blogs...'
}
});
When someone taps on one of the items in the list, my controller currently runs the method, showBlog. Here is my current controller:
Ext.define('Blog.controller.Main',{
extend: 'Ext.app.Controller',
config: {
refs: {
blogContainer: 'blogContainer',
blogList: 'blogList'
},
control: {
blogList: {
itemtap: 'showBlog'
}
}
},
slideLeftTransition: { type: 'slide', direction: 'left'},
init: function() {
console.log('Blog.controller.Main init');
},
launch: function() {
console.log('Blog.controller.Main launch');
},
showBlog: function(list, index, element, record) {
console.log('showing blog #'+record.data.id);
var blogContainer = this.getBlogContainer();
blogContainer.setData(record.data);
Ext.Viewport.animateActiveItem(blogContainer, this.slideLeftTransition);
}
});
So far, everything works really well, however, I can't figure out how to update all the components in my blogContainer with the new information from the tapped record?
I can't use the simple concept of creating a panel, because when a blog is tapped, I would like a fairly complex new container to appear...with sub components, etc.
How do I tell this new container which blog to show the details of, and then update its info?
You could try this. Commented out lines are another example of how to access the data and set its value to a component.
showBlog: function(view, record, item, index, e) {
console.log('showing blog #'+index.data.id);
// console.log('showing blog #'+index.data.example);
var blogContainer = this.getBlogContainer();
blogContainer.setData(index.data.id);
// Ext.getCmp('idoftextfield').setValue(index.data.example);
Ext.Viewport.animateActiveItem(blogContainer, this.slideLeftTransition);
Hope that helps

Extjs: Add Link to container

I'm trying to create a specialized class which should contain, among other things, a link and a image.
I have something like:
Ext.define('Macros.app.ribbonAction', {
extend: 'Ext.Component',
//extend: 'Ext.panel.Panel',
alias: 'widget.ribbonAction',
initComponent: function () {
Ext.apply(this, {
items:[
{}
]
}
);
this.callParent(arguments);
}
});
What's the best way to add a link (bound to a javascript function) to the items collection?
The closest I can find is a button, but I'd really prefer a good old-fashioned link.
(I'm using ExtJs 4)
How about standard box?
{
xtype: 'box',
id: 'myLinkId',
autoEl: 'Link'
}
And add this to the container.
The only problem is that you need to assign event handler for 'click' event and you can do this only after element has been rendered.

Using more than one controller with ExtJS 4 MVC

Let's say I have a main controller, then my application has a controller for each "module". This main controller contains the viewport, then a header (with a menu) + a "centered" container, which is empty at the beginning.
A click in the menu will change the current module/controller and the adhoc view (which belongs to this controller) will be displayed in the centered container.
I think it's a very simple scenario, but strangely I didn't find the proper way to do it. Any ideas? Thanks a lot!
Here is what I do: I have a toolbar on top, a left navigation and the center location is work area (basically a tab panel) like you mentioned. Lets take each part fo the application and explain.First, here is how my viewport look like:
Ext.define('App.view.Viewport',{
extend: 'Ext.container.Viewport',
layout: 'border',
requires: [
'App.view.menu.NavigationPane',
'App.view.CenterPane',
'App.view.menu.Toolbar'
],
initComponent: function() {
Ext.apply(this, {
items: [{
region: 'north',
xtype: 'panel',
height: 24,
tbar: Ext.create('App.view.menu.Toolbar')
},{
title: 'Navigation Pane',
region: 'west',
width: 200,
layout: 'fit',
collapsible: true,
collapsed: true,
items: Ext.create('App.view.menu.NavigationPane')
},{
region: 'center',
xtype: 'centerpane'
}]
});
this.callParent(arguments);
}
});
You can see that I have a toolbar (App.view.menu.Toolbar) with menu and left navigation (App.view.menu.NavigationPane). These two, components make up my main menu or gateway to other modules. Users select the menu item and appropriate module views (like form, grid, charts etc) get loaded into the 'centerpane'. The centerpane is nothing but a derived class of Ext.tab.Panel.
Like you said, I have a main controller that handles all the requests from the toolbar and navigation pane. It handled only the toolbar and navigation pane's click actions. Here is my AppController:
Ext.define('CRM.controller.AppController',{
extend: 'Ext.app.Controller',
init: function() {
this.control({
'apptoolbar button[action="actionA"]' : {
click : function(butt,evt) {
this.application.getController('Controller1').displayList();
}
},
.
. // Add all your toolbar actions & navigation pane's actions...
.
'apptoolbar button[action="actionB"]' : {
click : function(butt,evt) {
this.application.getController('Controller2').NewRequest();
}
}
});
}
});
Look at one of my button's handler. I get hold of the controller through the 'application' property:
this.application.getController('Controller2').NewRequest();
With the help of getController method, I get the instance of the controller and then call any method inside my controller. Now lets have a look at the skeleton of my module's controller:
Ext.define('CRM.controller.Controller2',{
extend: 'Ext.app.Controller',
refs: [
{ref:'cp',selector: 'centerpane'}, // reference to the center pane
// other references for the controller
],
views: ['c2.CreateForm','c2.EditForm','c2.SearchForm','c2.SearchForm'],
init: function() {
this.control({
'newform button[action="save"]' : {
// Do save action for new item
},
'editform button[action="save"]' : {
// update the record...
},
'c2gridx click' : {
// oh! an item was click in grid view
}
});
},
NewRequest: function() {
var view = Ext.widget('newform');
var cp = this.getCp(); // Get hold of the center pane...
cp.add(view);
cp.setActiveTab(view);
},
displayList: function() {
// Create grid view and display...
}
});
My module's controller have only the actions related to that module (a module's grid, forms etc). This should help you get started with rolling in right direction.
In main controller add child controller in the click event handler of menu
Ext.define('MyAPP.controller.MainController',{
...
init:function()
{
this.control({
'menulink':
{
click:this.populateCenterPanel
}
});
},
populateCenterPanel:function()
{
this.getController('ChildController');
}
});
In launch function add listener to controller add event like this -
Ext.application({
...
launch:function(){
this.controllers.addListener('add',this.newControllerAdded,this);
},
newControllerAdded:function(idx, ctrlr, token){
ctrlr.init();
}
});
Now put code for dynamically embedding views in the viewport in init method of ChildController.
Ext.define('MyAPP.controller.ChildController',{
...
refs: [
{ref:'displayPanel',selector:'panel[itemId=EmbedHere]'}
]
init:function(){
var panel=this.getDisplayPanel();
panel.removeAll();
panel.add({
xtype:'mycustomview',
flex:1,
autoHeight:true,
...
});
}
});
HTH :)

Resources