I have a basic grid panel where I render custom <span> element inside one of the columns. I am trying to catch the click events on this element and handle them in a controller.
The problem is that inside the listener this refers to Window, so I can't even fire an event.
Ext.define('MyList', {
extend: 'Ext.grid.Panel',
xtype: 'mylist',
controller: 'mylist',
listeners: {
body: {
click: function(e, el){
//this.fireEvent('onTagClick');
},
delegate: 'span.tag',
scope: this
},
},
columns: [
{
text: 'Name',
dataIndex: 'name',
renderer: function(value, metaData, record){
return '<span class="tag">tag</span>' + value;
}
},
]
});
I can fire a global event with Ext.GlobalEvents.fireEvent() but running into some strange issues or bugs with duplicate event invocations after the grid gets reloaded. I want to see if there is a way to avoid global events.
Found one solution by attaching the listener directly from the controller, this would refer to the controller then:
Ext.define('MyListController', {
alias: 'controller.mylist',
init: function(){
this.getView().on({
body: {
click: function(e, el){
this.onTagClick(el);
},
delegate: 'span.tag',
scope: this
},
});
},
onTagClick: function(el) {
console.log("clicked", el);
},
});
Related
I want to detect clicks on my toolbar, alternatively focus of toolbar.
The use-case has been extracted from a LiveSearchGrid which has a toolbar, the one seen in the code. The code provided renders fine, but no detect of click, focus, or anything else. Just nothing.
See below:
<div id="toolbar"></div>
<script type="text/javascript">
Ext.create('Ext.toolbar.Toolbar', {
renderTo: 'toolbar',
name: 'searchBar',
focusEl: 'toolbar',
listeners: {
focusenter: function () {
console.log('focusenter')
},
focus: function () {
console.log('focus')
}
},
items: [
{
xtype: 'tbtext',
html: 'Search',
listeners: {
focusenter: function () {
console.log('focusenter')
}
}
},
'Case Sensitive'
]
})
</script>
The following is plain JavaScript which solves my problem.
document.getElementById('toolbar').onclick = function () {
console.log('hello world');
}
What am I doing wrong?
You can set a DOM listener on the underlying Ext.Element using the element property of the listener config
Ext.create('Ext.toolbar.Toolbar', {
renderTo: 'toolbar',
name: 'searchBar',
focusEl: 'toolbar',
listeners: {
click: {
element: 'element', // bind to the underlying element
fn: function() {
console.log('Toolbar element was clicked!');
}
},
focusenter: {
element: 'element', // bind to the underlying element
fn: function() {
console.log('Toolbar element was focused!');
}
}
},
items: []
});
That property can be set to element or bodyElement
what's the best place to create / bind KeyMaps to a Viewport ?
Given a very simple Viewport like this :
Ext.define('EmptyTemplate.view.Viewport', {
extend: 'Ext.container.Viewport',
requires:[
'Ext.layout.container.Fit',
'EmptyTemplate.view.Main'
],
layout: {
type: 'fit'
},
items: [{
xtype: 'app-main'
}],
listeners: {
afterrender: {
fn: function(){
// map one key by key code
this.keyMap = Ext.create('Ext.util.KeyMap', this.el, {
scope: this,
key: Ext.EventObject.ENTER,
fn: function () {
console.log("enter pressed");
}
});
}
}
}
});
Whats the proper way to create KeyMaps?
First some best practice advises:
If you need to setup your component use
the [initComponent][1] (you should read this for detailed information),
the other provided template methods and
in some rare cases the constructor.
In you case I would use the template method afterRender
Ext.define('EmptyTemplate.view.Viewport', {
extend: 'Ext.container.Viewport',
requires:[
'Ext.layout.container.Fit',
'EmptyTemplate.view.Main'
],
layout: {
type: 'fit'
},
items: [{
xtype: 'app-main'
}],
afterRender: {
this.callParent(arguments); // always!!
this.bindKeyMap();
},
bindKeyMap: function() {
var me = this; // use 'me' if 'this' occurs more then 3 times
if(me.keyMap) {
me.keyMap.enable();
return;
}
// map one key by key code
me.keyMap = Ext.create('Ext.util.KeyMap', me.el, {
scope: me,
key: Ext.EventObject.ENTER,
fn: me.onEnter
});
},
unbindKeyMap: function() {
this.keyMap.disable();
},
onDisable: function() {
this.unbindKeyMap();
this.callParent(arguments); // always!!
},
onEnable: function() {
this.callParent(arguments); // always!!
this.bindKeyMap();
},
onEnter: function(){
// i am executed in the scope of the class instance
}
});
Note that the example above handles the whole keymap but you can also add / remove single keys from the map.
Note that this is untested prototype code, but it should work this way.
How to find template methods:
Go to the docs
Show protected member
Look for the mark
This post about overriding might also be a good reading
I am trying to add listeners of the itemtap event in a list view, however, when the list shows up correctly (ie loads from the store), and I tap an item of the list, the listener function is not triggered
Is this because I can't define the listeners inside config: in Ext.define()?
Thanks
Ext.define('Volt.view.FeedView', {
extend: 'Ext.Panel',
xtype: 'feedViewCard',
config: {
iconCls: 'home',
title: 'FeedView',
layout: {
type: 'vbox'
},
items: [
{
xtype: 'list',
itemTpl: '<div class="list-item-title">{title}</div> <div class="list-item-narrative">{narrative}</div>',
flex: 1,
listeners: {
itemtap: function(list, index, target, record, e, eOpts ){
console.log('List tapped , xtype = ' , list.getXTypes() );
debugger;
} //however when the list shows up and I tap the items, this function is not triggered
},
initialize: function(){
console.log('listview initialize');
console.log('XType = ',this.getXTypes(),'id = ',this.getId());
//console.log('XType = ',list.getXTypes());
//debugger;
this.setStore(Ext.getStore('Feeds'));
}
}
]
},
});
My ExtJS button's handler is not invoked after clicking. Now the code looks like this.
Ext.define('EDS.view.selector.Container', {
extend: 'Ext.form.Panel',
alias : 'widget.selectorcontainer',
title: 'Selector_V2',
renderTo: 'input-div',
layout: 'fit',
height: '100%',
items: [
{
xtype: 'tabpanel',
defaults: {
bodyPadding: 10
},
}
],
buttons: [
{
text: 'Reset',
handler: function(){
console.log("Reset");
this.up('form').getForm().reset();
}
},
{
text: 'Add to constrain',
handler: this.addConstrain,
}
],
/*
* Logic for button "Add to constrain"
*
* Adds an entry into the constrain list describing a person, cost center or an application
*/
addConstrain: function(button, event){
console.log('Add_to_constrain clicked');
}
});
Originally this 'selectorcontainer' was put diretly in my app.js. But I extracted it into a stand-alone view. Before the extraction, it works perfect but now it is not working.
BTW, I've two buttons and the first "reset" works fine. So I'm wondering if there's anything wrong with "this.addConstrain" related to scoping.
You're right, it is a scoping issue - this is not the class you're defining; it's the scope at the time the Ext.define function is called (likely window). There are a few ways to handle this. The easiest (in my opinion) is to change your handler to work similarly to your reset handler:
{
text: 'Add to constrain',
handler: function(btn, e) {
//'this' is now the button
this.up('selectorcontainer').addConstrain(btn, e);
}
}
You could also add the buttons as part of the initComponent function instead of defining them as part of the Ext.define config.
initComponent: function() {
//'this' is now the selector container
this.buttons = [{
text: 'Reset',
handler: function(){
console.log("Reset");
this.up('form').getForm().reset();
}
}, {
text: 'Add to constrain',
handler: this.addConstrain
}];
this.callParent();
}
The proper way to design your class is like this. You apply your config settings to the object before you do the callParent.
Ext.define('EDS.view.selector.Container', {
extend: 'Ext.form.Panel',
alias : 'widget.selectorcontainer',
title: 'Selector_V2',
renderTo: 'input-div',
layout: 'fit',
height: '100%',
initComponent: function() {
Ext.applyIf(this, {
items: [
{
xtype: 'tabpanel',
defaults: {
bodyPadding: 10
}
}
],
buttons: [
{
text: 'Reset',
scope: this, // <--- scope to form panel
handler: function(){
console.log("Reset");
this.getForm().reset();
}
},
{
text: 'Add to constrain',
scope : this, // <--- scope to form panel
handler: this.addConstrain
}
]
});
this.callParent(arguments);
}
/*
* Logic for button "Add to constrain"
*
* Adds an entry into the constrain list describing a person, cost center or an application
*/
addConstrain: function(button, event){
console.log('Add_to_constrain clicked');
}
});
I am trying to create a component and access it inside controller. But while accessing the component by id, it is not returning the component. It always returns undefined. Please find below the code.
enter code here
//Component creation in view layer as below
Ext.define('MyApp.view.performance.grid.IFrameGridCmp', {
extend: 'Ext.panel.Panel',
alias: 'widget.crMainPanel',
id:'mainPanelId',
layout: {
align: 'stretch',
type: 'vbox'
},
border:0,
resizable: false,
forceFit: true,
autoWidth: true,
initComponent: function() {
Ext.apply(this, {
items: [
{
xtype:'panel',
flex:.02,
border:0
},
{
xtype:'crHeaderPanel',
flex:.05
},
{
xtype: 'crUpperPanel',
flex: 0.93
},
Ext.create('Ext.Component', {
autoEl: {
tag: 'iframe',
cls: 'x-hidden',
src: Ext.SSL_SECURE_URL
},
id:'FileDownloader',
height:0,
listeners: {
afterrender: function () {
this.getEl().on('load', function () {
console.log('loaded download frame');
});
}
},
load: function(config){
var e = this.getEl();
e.dom.src = config.url + (config.params ? '?' + Ext.urlEncode(config.params) : '');
e.dom.onload = function() {
Ext.getBody().unmask();
if(e.dom.contentDocument.body.childNodes[0].wholeText == '404') {
Ext.Msg.show({
title: 'Attachment missing',
msg: 'The document you are after can not be found on the server.',
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
}
};
}
})
]
});
this.callParent(arguments);
}
});
========================================
enter code here
//Accessing the controller as below in controller
views: ['performance.grid.IFrameGridCmp'],
//The below line gives error
var downloader = Ext.getCmp('FileDownloader');
downloader.load({
url: '/APXUI/data/json/xls?exportData='+Ext.JSON.encode(records)
});
Well, the view is not created at the time you are calling Ext.getCmp()
Note that views: ['performance.grid.IFrameGridCmp'], is only a sort of binding that view to the controller, which means the controller will create a getter for you, nothing more. You still need to instantiate the view by calling .create(); or Ext.widget('crMainPanel')
In you controller use control for example to handle it:
me.control({
'crMainPanel #FileDownloader': {
afterrender: me.addDownloader
}
});
Don't use Ext.getCmp() it is really slow and you will have many issues with that.
Don't use id - better use itemId.
Why you need to call this from controller?