extjs how to parametrize a component - extjs

I'm trying to pass two parameters oneOfAll and twoOfAll into a container. From the initComponent function I do:
initComponent: function () {
this.callParent(arguments);
console.log('Results', this.oneOfAll, this.twoOfAll);
}
and the browser's console prints the correct data, but when:
items: [
{
xtype: 'button',
text: 'Other click',
id: 'buttonClick',
handler: function(item) {
Ext.Msg.alert('Other Click', '!!!' + this.oneOfAll);
}
},
{
xtype: 'button',
text: 'CLICK',
id: 'buttonClick_2',
handler: function(item) {
Ext.Msg.alert('Other Click', '!!!' + this.twoOfAll);
}
}
]
these values are not seen by the container config, both times undefined is returned.
I have this fiddle: https://fiddle.sencha.com/#view/editor&fiddle/2sk3
How can I pass these parameters into the container and be seen by it?

You can set reference to current component in initComponent method and use them in child component.
Take a look on example:
https://fiddle.sencha.com/#view/editor&fiddle/2skh

Inside the handler, this refers to the item object, not your component.
To fix this, you could try accessing the component by ID, and get its property directly.
For example (using your mypanel id from your fiddle):
{
xtype: 'button',
text: 'Other click',
id: 'buttonClick',
handler: function (item) {
var cmp = Ext.getCmp('mypanel');
Ext.Msg.alert('Other Click', '~~!!' + cmp.oneOfAll);
}
},

Your handler has a different scope and configs which you set are in different.
In order to fetch the values, get the reference of that component first and then try to access.
handler: function(item) {
Ext.Msg.alert('Other Click', '!!!' + item.up().oneOfAll);
Ext.Msg.alert('Other Click', '!!!' + item.up().twoOfAll);
}

Related

How to count a global variable?

LoginController:
var AppConstants = Ext.widget("AppConstants"); AppConstants.setGLOBAL_id_user(id_user);
App:
var AppConstants = Ext.widget("AppConstants"); console.log(AppConstants.getGLOBAL_id_user());
Console: (an empty string)
How to count a global variable?
Ext.widget() creates a new instance of a certain class every time you call it.
What you want is something that does not create new instances.
For minimal change to your code, you could do Ext.AppConstants = Ext.widget('Appconstants') in Application.init() and then access Ext.AppConstants wherever you use Ext.widget('Appconstants') right now.
The best way you could use singleton class in ExtJS. Using a singleton class you can access all the variable in throughout application whenever you required.
In this FIDDLE, I have created a demo using singleton class. Hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//{singleton: true,} When set to true, the class will be instantiated as singleton.
Ext.define('AppConstants', {
alternateClassName: 'AppConstants',
singleton: true,
config: {
GLOBAL_id_user: 'Demo_123'
},
constructor: function (config) {
this.initConfig(config);
}
});
Ext.create({
xtype: 'panel',
title: 'Demo',
bodyPadding: 15,
items: [{
xtype: 'button',
text: 'Set value',
margin: '0 15',
handler: function () {
//we set value using setter of singleton.
Ext.Msg.prompt('Set GLOBAL_id_user', 'Please enter GLOBAL_id_user value', function (btn, text) {
if (btn == 'ok') {
AppConstants.setGLOBAL_id_user(text);
}
});
}
}, {
xtype: 'button',
text: 'Get value',
handler: function () {
//we get value using getter of singleton.
Ext.Msg.alert('GLOBAL_id_user value is ', AppConstants.getGLOBAL_id_user());
}
}],
renderTo: Ext.getBody()
});
}
});
Just create a global singleton
Ext.define("MyApp.globals", {
singleton: true,
id_user: 0
});
Then access it using MyApp.globals.id_user
http://docs.sencha.com/extjs/6.5.3/classic/Ext.Class.html#cfg-singleton

extjs - How to create listener for child component's custom event

I am using a panel (say parentPanel) having another child panel (say childPanel). How can i fire a custom event from childPanel that will be caught by parentPanel?
Like so:
Ext.define('Ext.ux.form.Panel', {
extend: 'Ext.form.Panel',
title: 'Simple Form',
bodyPadding: 5,
width: 350,
layout: 'anchor',
defaults: {
anchor: '100%'
},
defaultType: 'textfield',
initComponent: function() {
var me = this;
me.items = [{
fieldLabel: 'First Name',
name: 'first',
allowBlank: false
}];
me.callParent(arguments);
},
afterRender: function() {
var me = this;
me.callParent(arguments);
// in case of a form you can also use the findField() method
// I used down() because it will work with all sort of containers
me.down('textfield[name=first]').on('change',me.onFirstnameChange,me);
},
onFirstnameChange: function(field) {
// custom handler
}
});
Doing this just on single instances work the same way expect that you will need to use the afterrender event instead of the static template method.
Note:
I this doesn't fit your needs you will need to post a more detailed question (with example code) for a more detailed answer.
Edit:
Adding a custom event to a new component:
initComponent: function() {
// ...
me.addEvents('customeventname');
// ...
}
you can now register listeners to this events on instances of this component and fire the event by calling fireEvent('customeventname', args) where args are the arguments you want to call each listeners with.

In Extjs 4, why is my firing of custom event om image el not working?

Update 2: This confirms the cpuchartclicked event is being fired, because the alert('hello') works. What I need is to be able to respond to that event in my controller.
items: [
{
xtype: 'image',
itemId: 'graphiteChartCPU',
src: '',
listeners:{
'afterrender':function (comp) {
comp.getEl().on('click', function (el) {
this.fireEvent('cpuchartclicked');
}, this);
},
'cpuchartclicked':function () {
alert('hello');
}
}
}
]
Update: With the following, I am setting the scope for the on click handler. fireEvent() seems to be working now, but still not hearing the event in controller.
items: [
{
xtype: 'image',
itemId: 'graphiteChartCPU',
src: '',
listeners:{
'afterrender':function (comp) {
comp.getEl().on('click', function (el) {
alert('on click handler');
this.fireEvent('cpuchartclicked');
}, this);
}
}
}
]
// Listen Application Event
me.application.on({
cpuchartclicked: me.onChartClicked,
scope: me
});
I'm trying to fire a custom event on an image el so when the image is clicked the controller hears the event.
But I get an error cmp.fireEvent() is not a function?
items: [{
xtype: 'image',
itemId: 'graphiteChartCPU',
src: '',
listeners:{
'afterrender':function (comp) {
comp.getEl().on('click', function (el) {
el.fireEvent('cpuchartclicked');
});
}
}
}]
me.application.on({
cpuchartclicked: this.onChartClicked,
scope: this
});
You are confusing Components and Elements. The afterrender event listener is set on the Image Component, and receives the Component itself as the first argument (that you named el instead, incorrectly).
Then, in the afterrender listener, you retrieve the main DOM element for that Component, which happens to be an <img> tag, and set click listener on the element object, which is an instance of Ext.dom.Element.
The click event signature is not what you expect; the first argument is an Ext.util.Event object that does not have a fireEvent method. Hence the error.
I would suggest looking up event signatures in the docs before using them. Also try to add a debugger statement before the line that blows up, and see what variables are passed in and what is going on. Using Chrome or Firefox debugger can be immensely helpful here.
Solved it, though I am wondering if this is the best way to do it.
I fire the custom event via the image, and then listen for that event on the image as well in the controller.
items: [
{
xtype: 'image',
itemId: 'graphiteChartCPU',
src: '',
listeners:{
'afterrender':function (comp) {
comp.getEl().on('click', function (el) {
this.fireEvent('cpuchartclicked');
}, this);
}
}
}
]
'myContainer image':
{
'cpuchartclicked': me.onChartClicked
}
you must bind to the image element like that:
{
xtype: 'image',
itemId: 'graphiteChartCPU',
src: '',
listeners: {
el: {
click: function() {
console.log("Click");
}
}
}
}
it solve my problem in ext5

How to call an action of controller from grids action column

I have an action column in my grid which is needed to perform lots of non-trivial operations after click on it. I don't want to use the handler method only to avoid duplicity in my code. I want to handle the click event from the controller method which can be called from more sides.
Here is my definition of action column:
{
header: translator.translate('actions'),
xtype: 'actioncolumn',
width: 50,
items:[{
id : 'detailContactPerson',
icon : '/resources/images/pencil.png',
tooltip: translator.translate('show_detail')
}]
},
But now I don't know how to write the Component query definition to set up listener.
init: function() {
this.control({
'detailContactPerson': {
click: function(obj) {
var contactPerson = obj.up('container').contactPerson;
this.detail(contactPerson);
}
},
Second way I've tried is to call the method of controller directly from handler method. It looks like this:
{
header: translator.translate('actions'),
xtype: 'actioncolumn',
width: 50,
items:[{
id : 'detailContactPerson',
icon : '/resources/images/pencil.png',
handler: function(contactPerson){
Project.controller.contactPerson.detail(contactPerson);
},
tooltip: translator.translate('show_detail')
}
But unfortunately it isn't supported way to call controller method (No method exception raised).
Could someone help me to construct working Component query, or show some example how to call controller method from outside?
try actioncolumn#detailContactPerson
or you can listene to actioncolumn 's click event
see this: http://www.sencha.com/forum/showthread.php?131299-FIXED-EXTJSIV-1767-B3-ActionColumn-bug-and-issues
init: function() {
this.control({
'contact button[action=add]':{
click: this.addRecord
},
'contact button[action=delete]':{
click: function(){this.deleteRecord()}
},
'contact actioncolumn':{
click: this.onAction
}
});
},
onAction: function(view,cell,row,col,e){
//console.log(this.getActioncolumn(),arguments, e.getTarget())
var m = e.getTarget().className.match(/\bicon-(\w+)\b/)
if(m){
//选择该列
this.getGrid().getView().getSelectionModel().select(row,false)
switch(m[1]){
case 'edit':
this.getGrid().getPlugin('rowediting').startEdit({colIdx:col,rowIdx:row})
break;
case 'delete':
var record = this.getGrid().store.getAt(row)
this.deleteRecord([record])
break;
}
}
}
BTW.I prefer to use these to instead of AcionColumn
Ext.ux.grid.column.ActionButtonColumn
Ext.ux.grid.RowActions
I have a better way: add new events on your view where are presents the actioncolumns:
{
xtype:'actioncolumn',
align:'center',
items:[
{
tooltip:'info',
handler:function (grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
//this is the view now
this.fireEvent('edit', this, rec);
},
scope:me
},
....
me.callParent(arguments);
me.addEvents('edit')
then on your controller:
.....
this.control({
'cmp_elenco':{
'edit':function(view,record){//your operations here}
....
I too wanted to handle logic for the actioncolumn in a controller. I am not certain if this is better or worse than simply using one of the other plugins mentioned, however this is how I was able to get it to work.
Things to note:
the id config property in the items array of the actioncolumn
does nothing at all, the icons will still receive a generated id
the items are NOT components, they are simply img elements
you can add an id to the actioncolumn itself to target a specific instance of actioncolumn
each icon (or item in the actioncolumn) is given a class of x-action-col-# where # is an index beginning with 0.
For example, in the columns definition of my grid I have:
header: 'ACTION',
xtype: 'actioncolumn',
id: 'myActionId',
width: 50,
items: [{
icon: 'resources/icons/doThisIcon.png',
tooltip: 'Do THIS'
},{
icon: 'resources/icons/doThatIcon.png',
tooltip: 'Do THAT'
}
]
and in the controller:
init: function(){
this.control({
'actioncolumn#myActionId': {
click: function(grid,cell,row,col,e){
var rec = grid.getStore().getAt(row);
var action = e.target.getAttribute('class');
if (action.indexOf("x-action-col-0") != -1) {
console.log('You chose to do THIS to ' + rec.get('id')); //where id is the name of a dataIndex
}
else if (action.indexOf("x-action-col-1") != -1) {
console.log('You chose to do THAT to ' + rec.get('id'));
}
}
}
}
Using this method, you can place all logic for any given action column in the controller.
Here is a way to avoid declaring the handler (no need to use addEvents, ExtJS 4.1.1) :
Ext.grid.column.Action override :
Ext.grid.column.Action.override({
constructor: function () {
this.callParent(arguments);
Ext.each(this.items, function () {
var handler;
if (this.action) {
handler = this.handler; // save configured handler
this.handler = function (view, rowIdx, colIdx, item, e, record) {
view.up('grid').fireEvent(item.action, record);
handler && handler.apply(this, arguments);
};
}
});
}
});
Action column config :
{
xtype: 'actioncolumn',
items: [{
icon: 'edit.png',
action: 'edit'
}]
}
Controller :
this.control({
'grid': {
edit: function (record) {}
}
});
You can also follow this example http://onephuong.wordpress.com/2011/09/15/data-grid-action-column-in-extjs-4/.

Extjs How to initialize new elements when extending - without losing scope

I am trying to get better at extending the classes of Extjs, and my evolvement have lead me to this problem:
I have extended an Ext.Panel and I want my extension to have a bottom toolbar with one button as default.
myPanel = Ext.extend(Ext.Panel, {
method: function () {
return 'response!';
},
bbar: new Ext.Toolbar({
items:
[
{
xtype: 'button',
text: 'Hit me!',
handler: function (button, event) {
alert(this.method());
},
scope: this
}
]
})
});
What I haven't learnt yet is why this is not allowed. this is pointing at the global scope and not my extended panel - thus .method() is undefined inside the handler function.
You're defining the bbar on the prototype rather than on a specific object.
Override initComponent and move the bbar definition inside it.
myPanel = Ext.extend(Ext.Panel, {
method: function () {
return 'response!';
},
initComponent: function() {
var bbar = new Ext.Toolbar({
items:
[
{
xtype: 'button',
text: 'Hit me!',
handler: function (button, event) {
alert(this.method());
},
scope: this
}
]
});
// Config object has already been applied to 'this' so properties can
// be overriden here or new properties (e.g. items, tools, buttons)
// can be added, eg:
Ext.apply(this, {
bbar: bbar
});
// Call parent (required)
myPanel.superclass.initComponent.apply(this, arguments);
// After parent code
// e.g. install event handlers on rendered component
}
});
See http://www.sencha.com/learn/Manual:Component:Extending_Ext_Components for a template you can use when extending components
You have to keep in mind that the anonymous object that is the first element of the items array is created in the same scope as the one in which Ext.extend(... is executed.
If you had this:
var o = { 'a': a, 'b': b, scope: this };
you would expect that o.a, o.b, and o.scope would have the same values as a, b, and this in the current scope. Here, it's a little more complex because you are creating an object while creating an array while creating an object, etc., but the reasoning is the same.
What you should do instead is define this.bbar inside the constructor:
myPanel = Ext.extend(Ext.Panel, {
method: function () {
return 'response!';
},
constructor: function(config) {
this.bbar = new Ext.Toolbar({
items:
[
{
xtype: 'button',
text: 'Hit me!',
handler: function (button, event) {
alert(this.method());
},
scope: this
}
]
});
myPanel.superclass.constructor.apply(this, arguments);
}
});

Resources