Extjs: Add Link to container - extjs

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.

Related

extjs contextmenu click error - method not found... but looking in wrong controller

how do I point this menu item click to launch a method in a controller.
The item click is being hit successfully but the error message states No method named "onDownloadTopdayRecapContextButton" on ExtApplication4.view.main.MainController. That is the problem, you can see the view's controller is portalRealtime-portalRealtime.
So somehow its pointing to the wrong controller. Can someone show me what I am doing wrong?
menu code
var contextMenuTopday = Ext.create('Ext.menu.Menu', {
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
grid menu is held in
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
extend: 'Ext.panel.Panel',
xtype: 'app-portalRealtime',
itemId: 'portalRealtimeItemID',
requires: [
'ExtApplication4.view.portalRealtime.PortalRealtimeController',
'Ext.form.action.StandardSubmit'
],
controller: 'portalRealtime-portalRealtime',
title: 'Main Portal',
layout: {
type: 'vbox'
},
items: [
//i deleted some grid code here
collapsible: true,
collapseDirection: 'left',
listeners: {
itemcontextmenu: function (view, rec, node, index, e) {
e.stopEvent();
contextMenuTopday.showAt(e.getXY());
return false;
}
{
You are creating the context menu outside of your view, so it does not inherit your controller.
Before using the below code please scroll to the bottom of the answer for a better solution, but this hopefully shows what is the cause of your issue.
If this doesn't solve your issue, please comment and provide a more complete code example, and I will update my answer
In these cases you can pass a controller manually, but you need to pass as a parent, as you get all kinds of problems if you re-use the same controller on multiple components (when you destroy one for example, it destroys the controller, leaving the other without)
So you could create from within your view like so:
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
initComponent:function(){
this.callParent(arguments);
this.contextMenuTopday = Ext.create('Ext.menu.Menu', {
controller:{
parent: this.getController()
},
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
}]
});
}
Then rather than use a variable to access the context menu you can access the contextMenuTopday property, as you are within a child item you may need to traverse to your actual view, the simplest way of doing this is via the up method available on components, you would need to make sure you include an xtype to do this:
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
xtype:'portalrealtime'
Then from within the context menu you can do:
itemcontextmenu: function (view, rec, node, index, e) {
this.up('portalrealtime').contextMenuTopday.showAt(e.getXY());
}
A better way
Best illustrated looking at this fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1qpn
Define your menu as its own class:
Ext.define('Example.ContextMenu', {
xtype:'testmenu',
extend:'Ext.menu.Menu',
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
}]
});
Use a method on your controller for the itemcontextmenu event (This is good anyway as it provides a better separation of concerns):
itemcontextmenu: 'showContextMenu'
Then add a a few new methods to your portalRealtime-portalRealtime controller:
getContextMenu:function(){
if(!this.contextMenu){
this.contextMenu = this.getView().add({xtype:'testmenu'});
}
return this.contextMenu;
},
showContextMenu:function (view, rec, node, index, e) {
// we can't use showAt now we have added this to our view, as it would be positioned relatively.
this.getContextMenu().show().setPagePosition(e.getXY());
}
What we are doing here is adding the context menu to the view, so it inherits the controller (and a viewmodel if provided).
The best way to call methods on your controller for listeners/button handlers etc is to just specify the method name as a string i.e.:
listeners:{
itemcontextmenu: 'showContextMenu'
}
This will automatically look up the responsible controller and use the correct method.
If you need to call from within a component you will find that this.getController() fails unless you call on the actual component the controller is attached to - i.e. you are calling from a child component. In these cases you can use this.lookupController() to find the inherited/responsible controller and then call any methods from here e.g. this.lookupController().myMethod()

change listener doesnt work in extjs

I have a dynamic form and i want to add a listener when change a field value, but i couldnt achive to do that. I added a click listener but when i change it to the change it doesnt work.
thanks in advance.
here is the code below :
panel = Ext.define('MyApp.view.dynamicform.Form', {
extend: 'Ext.form.Panel',
alias: 'widget.dynamicformform',
title: title,
id: 'dynamicform.Form',
bodyPadding: 5,
autoScroll: true,
layout: 'auto',
defaults: {
anchor: '100%'
},
dockedItems: [],
items : genItems(storeData),
listeners: {
afterrender: function (comp) {
var element = comp.getEl();
element.on('change', function(e,el) {
alert('blabla')
});
}
},
initComponent : function() {
this.callParent(arguments);
}
});
when i write click instead of change it works perfectly. I dont get what iam doing wrong.
The afterrender event you have added the listener for is purely for the panel component alone. Therefore trying to attach a change event wont work, since you are trying to do this on the panel:
afterrender: function (comp) {
var element = comp.getEl();
//element is the panel here, not child items such as spinners...
element.on('change', function(e,el) {
alert('blabla')
});
}
You say the click is working, but I think that's just because you are clicking anywhere on the panel including on the child items you are rendering. Instead, the child items coming back in the genItems() need to contain change event listener configs.
EDIT
You could loop through the child items on comp in your afterrender event and for any that are spinners, etc, add the change events that way.

ExtJS 4.2.1 - Cannot get View instance from the controller

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!

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

Resources