handleClick() is not a function with Sencha CMD and Extjs 5.1 - javascript

I created a MyApp application with Sencha CMD and ExtJS 5.1. Now im changing the Main.js and MainController.js files. Only i want to update the center region tabs clicking in one section of the treepanel in the west region.
To do this i use a listener who calls the function handleClick() in MainController.js but not recognize this function. in MainController.js exists anothers function, i created a button to execute the onClickButton() function and works correctly. What im doing wrong?
Main.js
/**
* This class is the main view for the application. It is specified in app.js as the
* "autoCreateViewport" property. That setting automatically applies the "viewport"
* plugin to promote that instance of this class to the body element.
*
* TODO - Replace this content of this view to suite the needs of your application.
*/
Ext.define('MyApp.view.main.Main', {
extend : 'Ext.container.Container',
requires : [
'MyApp.view.main.MainController',
'MyApp.view.main.MainModel'
],
xtype : 'app-main',
controller : 'main',
viewModel : {
type : 'main'
},
layout : {
type : 'border'
},
items : [{
xtype : 'treepanel',
bind : {
title : 'Menu'
},
region : 'west',
root : {
text : 'Raiz',
expanded : true,
children : [{
text : 'Opcion 1',
leaf : false,
children: [{
text : 'Opcion 1-1',
leaf : true
}]
}, {
text : 'Opcion 2',
leaf : true
}, {
text : 'Opcion 3',
leaf : true
}
],
},
listeners: {
itemclick: function (node, rec){
var id = rec.get("id");
var name=rec.get('text');
console.log('id'+id+' texto: ' + name);
this.handleClick(name);
}},
scope: 'controller',
width : 250,
split : true,
}, {
region : 'center',
xtype : 'tabpanel',
items : [{
title : 'Tab 1',
html : '<h2>Content appropriate for the current navigation.</h2>'
},
{
title : 'Tab 2',
html : '<h2>Content appropriate for the current navigation.</h2>'
},
{
title : 'Tab 3',
html : '<h2>Content appropriate for the current navigation.</h2>'
}
]
}
]
});
MainController.js
/**
* This class is the main view for the application. It is specified in app.js as the
* "autoCreateViewport" property. That setting automatically applies the "viewport"
* plugin to promote that instance of this class to the body element.
*
* TODO - Replace this content of this view to suite the needs of your application.
*/
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
requires : [
'Ext.window.MessageBox'
],
alias : 'controller.main',
onClickButton : function () {
Ext.Msg.confirm('Confirm', 'Are you sure?', 'onConfirm', this);
},
onConfirm : function (choice) {
if (choice === 'yes') {
//
}
},
handleClick : function (name) {
var tab = Ext.ComponentQuery.query('tabpanel')[0];
var num = 0;
switch (name.trim()) {
case "Opcion 1":
num = 0;
break;
case "Opcion 2":
num = 1;
break;
case "Opcion 3":
num = 2;
break;
default:
break;
}
tab.setActiveTab(num);
}
});
When i update MainController.js Sencha CMD show this:
[INF] -----------------------
[INF] Waiting for changes...
[INF] -----------------------
[INF] Appending content to C:\xampp\htdocs\MyApp/bootstrap.js
[INF] Writing content to C:\xampp\htdocs\MyApp/bootstrap.json
[INF] merging 219 input resources into C:\xampp\htdocs\MyApp\build\development\MyApp\resources
[INF] merged 0 resources into C:\xampp\htdocs\MyApp\build\development\MyApp\resources
[INF] merging 0 input resources into C:\xampp\htdocs\MyApp\build\development\MyApp
[INF] merged 0 resources into C:\xampp\htdocs\MyApp\build\development\MyApp
[INF] writing sass content to C:\xampp\htdocs\MyApp/build/temp/development/MyApp/sass/MyApp-all.scss.tmp
[INF] appending sass content to C:\xampp\htdocs\MyApp/build/temp/development/MyApp/sass/MyApp-all.scss.tmp
[INF] appending sass content to C:\xampp\htdocs\MyApp/build/temp/development/MyApp/sass/MyApp-all.scss.tmp
[INF] executing compass using system installed ruby runtime unchanged MyApp-all.scss
[INF] Refresh complete in 4 sec. at 11:23:13 AM
[INF] -----------------------
[INF] Waiting for changes...

Instead of:
listeners: {
itemclick: function (node, rec){
var id = rec.get("id");
var name=rec.get('text');
console.log('id'+id+' texto: ' + name);
this.handleClick(name);
}},
scope: 'controller',
write:
listeners: {
itemclick: function (node, rec) {
var id = rec.get("id");
var name=rec.get('text');
console.log('id'+id+' texto: ' + name);
this.handleClick(name);
},
scope: 'controller'
},

Instead of:
listeners: {
itemclick: function (node, rec) {
var id = rec.get("id");
var name=rec.get('text');
console.log('id'+id+' texto: ' + name);
this.handleClick(name);
},
scope: 'controller'
},
write this in your view:
listeners: {
itemclick: 'handleClick'
},
and in your viewController:
...
handleClick : function (node, rec) {
var view = this.getView();
var id = rec.get("id");
var name = rec.get('text');
var tabPanel = view.down('tabpanel');
var tab = tabPanel.items[0]; // items is property of tabpanel
var num = 0;
switch (name.trim()) {
case "Opcion 1":
num = 0;
break;
...

Related

ExtJs 3.4 - how to ToolTip a content of a textField component that was pre-loaded

This is the component where I'm trying to put a Tooltip:
this.textFieldStreet = new Ext.form.TextField({
id : 'idTextFieldStreet',
fieldLabel : 'Street',
autoCreate : limitChar(30,30),
listeners : {
render : function(c){
Ext.QuickTips.register({
target : c.getEl(),
html : '' + Ext.getCmp('idTextFieldStreet').getValue()
}
});
}
}
});
In another .js I created the function that define every component like you see before and invoke the function as you see forward:
var componentFormCustomer = new ComponentFormCustomer();
Then I set value like:
componentFormCustomer.textFieldStreet.setValue('Some street info')
Now, here's the problem, I was looking for some ideas to do that and found nothing, I don't know if this is the right way to accomplish the tooltip. Help!
Solution:
Define show listener for created tooltip. In this listener get the value of textfield and update tooltip.
With this approach, the tooltip's content will change dynamically and will show the content of tooltip's target.
Ext.onReady(function(){
Ext.QuickTips.init();
var textFieldStreet = new Ext.form.TextField({
renderTo : Ext.getBody(),
id : 'idTextFieldStreet',
fieldLabel : 'Street',
value : 'Initial value',
bodyCfg : {
tag: 'center',
cls: 'x-panel-body',
html: 'Message'
},
listeners : {
render : function(c) {
new Ext.ToolTip({
target : c.getEl(),
listeners: {
'show': function (t) {
var value = t.target.getValue();
t.update(value);
}
}
});
}
}
});
var button = new Ext.Button({
renderTo : Ext.getBody(),
text : 'Change Tooltip',
handler : function () {
textFieldStreet.setValue('New value');
}
});
});
Notes:
Tested with ExtJS 3.4.1.

Extjs add a button to Desktop TaskBar QuickStart

I need to add a button to the taskbar quickstart, but i do not want to open a module window, for example a logout button that will show a confirm messagebox, i have tried like this:
getTaskbarConfig: function () {
var ret = this.callParent();
me = this;
return Ext.apply(ret, {
quickStart: [
{ name: 'Window', iconCls: 'icon-window', module: 'ext-win' },
{ name: 'Logout', iconCls:'logout', handler: me.onLogout}
]
});
},
onLogout: function () {
Ext.Msg.confirm('Logout', 'Are you sure you want to logout?');
},
And i changed the getQuickStart function of the TaskBar.js file to this:
getQuickStart: function () {
var me = this, ret = {
minWidth: 20,
width: Ext.themeName === 'neptune' ? 70 : 60,
items: [],
enableOverflow: true
};
Ext.each(this.quickStart, function (item) {
ret.items.push({
tooltip: { text: item.name, align: 'bl-tl' },
overflowText: item.name,
iconCls: item.iconCls,
module: item.module,
//handler: me.onQuickStartClick, **original code**
handler: item.handler == undefined ? me.onQuickStartClick : item.handler,
scope: me
});
});
return ret;
}
But it does not work, is there a way to add a simple button to the taskbar quickstart?
Thanks for your reply. I have solved the issue. In the TaskBar.js file i changed this line:
handler: item.handler == undefined ? me.onQuickStartClick : item.handler
for this one:
handler: item.handler ? item.handler : me.onQuickStartClick
Actually, for me, both do the same, but for any weird reason the code works with that change.

Combobox store load after updating form with Model data

I noticed that there are a lot of ways to populate a form with data.
I want to do it the ExtJS4 MVC style.
However I now see something unwanted happening.
My form has a combobox tied to a store.
The store is filled after populating the form with the model data.
My view / form
Ext.define('WWT.view.settings.Form', {
extend : 'Ext.form.Panel',
alias : 'widget.settingsform',
title : 'WWT Instellingen',
bodyPadding : 5,
defaultType : 'textfield',
initComponent : function() {
var me = this;
me.dockedItems = me.buildToolbars();
me.items = me.buildItems();
me.callParent();
},
buildItems : function() {
var lovEdities = Ext.create('WWT.store.lov.Edities');
return [{
fieldLabel : 'Huidige Editie',
xtype : 'combo',
emptyText : 'Kies een Editie',
name : 'huidige_editie_id',
store : lovEdities,
queryMode : 'local',
displayField : 'naam',
valueField : 'id',
forceSelection : true
}, {fieldLabel : 'Scorebord Slogan',
name : 'scorebord_slogan_regel',
width: 200,
maxLength : 10
}, {
fieldLabel : 'Tijd Offset Scorebord',
name : 'scorebord_tijdoffset'
}];
},
buildToolbars : function() {
return [{
xtype : 'toolbar',
docked : 'top',
items : [{ xtype:'button',
text : 'Save',
iconCls : 'save-icon',
action : 'save'
}]
}];
}
});
My Controller
Ext.define('WWT.controller.settings.Settings', {
extend : 'Ext.app.Controller',
models : ['secretariaat.Settings'],
views : ['settings.Form'],
init : function() {
var me = this;
me.control({
'#settingsId button[action=save]' : {
click : me.save
},
'settingsform' : {
afterrender : function(view) {
Ext.ModelMgr
.getModel('WWT.model.secretariaat.Settings')
.load(1, {
success : function(record) {
view.loadRecord(record);
}
});
}
}
});
},
save : function() {
var form = this.container.down('form');
var model = this.getModel('settings.Settings').set(form.getForm()
.getValues());
model.save();
},
addContent : function() {
this.container.add({
id : 'settingsIDQ',
xtype : 'settingsform',
itemId : 'settingsId'
});
}
});
In my Chrome Network window, I can see that the store request is fired later.
Any thoughts on how to load the store before updating the form ?
I thought of doing it in the afterRender too, but I think that even then the order is not guaranteed.
Seemed that there was nothing wrongs with the (load) mechanism.
There was an issue in the data type of the ID field of the Combobox and the field which was part of the settings. Int vs String.
This caused the issue.
I get around the form loading issue in a few different ways.
If the store is used a lot throughout the application, I load the store early in the loading of the application by looking it up with Ext.getStore('my store name here') and then calling .load() during startup. If you want the store or stores to load only when you reach the form itself, I would hook the component's initialization in initComponent and then you can get the form's fields and with a for-loop can walk through the fields and initialize all stores with .load() before the form component accesses server data.
Here are my edits to your initComponent method. I haven't debugged this code, but it should work great for you.
initComponent() {
var me = this;
// this is where we will load all stores during init
var fields = me.getForm().getFields();
for (var i = 0; i < fields.length; i++) {
var store = fields[i].getStore();
if (store && !store.isLoaded()) {
store.load();
}
}
me.dockedItems = me.buildToolbars();
me.items = me.buildItems();
me.callParent();
},

Scope issue in extjs 4

I have this treepanel and i want to call this.getId() method of mainpaneltree from inside "Expand all" button But all i get is method undefined.I tried to put scope:thisin config objects but no success.
Ext.define('MA.view.patient.Tree', {
extend : 'Ext.tree.Panel',
alias : 'widget.EditPatientTree',
title : 'Simple Tree',
width : 150,
store:'Tree',
dockedItems : [ {
xtype : 'toolbar',
items : [ {
text : 'Expand All',
scope: this,
handler : function() {
//this.expandAll gives "Uncaught TypeError: Object [object DOMWindow] has no method 'getId'"
this.expandAll();
//the same error for this.getId();
this.getId();
}
} ]
} ],
rootVisible : false,
initComponent : function() {
this.callParent(arguments);
}
});
So my question is how to get reference to the current component and call its methods while you are inside nested methods or config objects of current component
The handler has arguments that are passed in, 1 of them is normally the button. From the button you can get the container.
Ext.define('MA.view.patient.Tree', {
extend : 'Ext.tree.Panel',
alias : 'widget.EditPatientTree',
title : 'Simple Tree',
width : 150,
store:'Tree',
dockedItems : [ {
xtype : 'toolbar',
items : [ {
text : 'Expand All',
scope: this,
handler : function(button, event) {
var toolbar = button.up('toolbar'), treepanel = toolbar.up('treepanel');
treepanel.expandAll();
treepanel.getId();
}
} ]
} ],
rootVisible : false,
initComponent : function() {
this.callParent(arguments);
}
});
You can make use of the methods like up, down for get references of components that are parent or child. In your case, you could get the reference of the tree panel by:
myTree = this.up('treepanel');
Similarly, you could use the down method, to get hold of any child reference.

How to call this onclick javascript function in my architecture

I am using this article of architecture http://blog.extjs.eu/know-how/writing-a-big-application-in-ext/
In my one class of Dashboardgrid i have two functions are :
,linkRenderer : function (data, cell, record, rowIndex, columnIndex, store) {
if (data != null) {
return ''+ data +'';
}
return data;
},
resellerwindow : function (cityname) {
// render the grid to the specified div in the page
// resellergrid.render();
resellerstore.load();
wingrid.show(this);
}
when the click event of linkrendrer function is called it gives error
this.resellerwindow is not a function
where and how should i put resellerwindow function ?
My ResellerDashBoard Class
Application.DashBoardGrid = Ext.extend(Ext.grid.GridPanel, {
border:false
,initComponent:function() {
var config = {
store:new Ext.data.JsonStore({
// store configs
autoDestroy: true,
autoLoad :true,
url: 'api/index.php?_command=getresellerscount',
storeId: 'getresellerscount',
// reader configs
root: 'cityarray',
idProperty: 'cityname',
fields: [
{name: 'cityname'},
{name: 'totfollowup'},
{name: 'totcallback'},
{name: 'totnotintrested'},
{name: 'totdealsclosed'},
{name: 'totcallsreceived'},
{name: 'totcallsentered'},
{name: 'totresellerregistered'},
{name: 'countiro'},
{name: 'irotransferred'},
{name: 'irodeferred'}
]
})
,columns: [
{
id :'cityname',
header : 'City Name',
width : 120,
sortable : true,
dataIndex: 'cityname'
},
{
id :'countiro',
header : ' Total Prospect',
width : 100,
sortable : true,
dataIndex: 'countiro'
},
{
id :'irotransferred',
header : 'Calls Transfered By IRO',
height : 50,
width : 100,
sortable : true,
dataIndex: 'irotransferred'
},
{
id :'irodeferred',
header : ' Calls Deferred By IRO',
width : 100,
sortable : true,
dataIndex: 'irodeferred'
},
{
id :'totcallsentered',
header : ' Total Calls Entered',
width : 100,
sortable : true,
dataIndex : 'totcallsentered',
renderer : this.linkRenderer
},
{
id :'totfollowup',
header : ' Follow Up',
width : 100,
sortable : true,
dataIndex: 'totfollowup'
},
{
id :'totcallback',
header : ' Call Backs',
width : 100,
sortable : true,
dataIndex: 'totcallback'
},
{
id :'totnotintrested',
header : ' Not Interested',
width : 100,
sortable : true,
dataIndex: 'totnotintrested'
},
{
id :'totdealsclosed',
header : ' Deals Closed',
width : 100,
sortable : true,
dataIndex: 'totdealsclosed'
},
{
id :'totresellerregistered',
header : ' Reseller Registered',
width : 100,
sortable : true,
dataIndex: 'totresellerregistered'
}
]
,plugins :[]
,viewConfig :{forceFit:true}
,tbar :[]
,bbar :[]
,height : 350
,width : 1060
,title : 'Reseller Dashboard'
}; // eo config object
// apply config
Ext.apply(this, Ext.apply(this.initialConfig, config));
Application.DashBoardGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent
/**
* It is the renderer of the links of cell
* #param data value of cell
* #param record object of data has all the data of store and record.id is unique
**/
,linkRenderer : function (data, cell, record, rowIndex, columnIndex, store) {
if (data != null) {
return ''+ data +'';
}
return data;
},
resellerwindow : function (cityname) {
// render the grid to the specified div in the page
// resellergrid.render();
resellerstore.load();
wingrid.show(this);
}
,onRender:function() {
// this.store.load();
Application.DashBoardGrid.superclass.onRender.apply(this, arguments);
} // eo function onRender
});
Ext.reg('DashBoardGrid', Application.DashBoardGrid);
Your scope is messed up, when the function in your <a> tag is called this does not point to your object where you defined the function but to your <a>-dom node.
It's pretty hard to call member functions from within a html fragment like the fragment returned by a grid renderer. I suggest you take a look at Ext.grid.ActionColumn to solve this problem. When you look at the code in this column type you should be able to write your own column type that renders a link instead of an icon like the ActionColumn.
Another option is using my Ext.ux.grid.ButtonColumn which doesn't render links but buttons in your grid.
more info on scope in ExtJS (and js in general): http://www.sencha.com/learn/Tutorial:What_is_that_Scope_all_about
this.resellerwindow is not a function
because 'this', in the onclick function is in fact a reference to the 'a' dom element;
In order to access the 'resellerwindow' function from the onclick handler, you need to make the function accessible from the global scope, where your handler is executed:
var globalObj =
{
linkRenderer : function (data, cell, record, rowIndex, columnIndex, store)
{
if (data != null)
return ''+ data +'';
return data;
},
resellerwindow : function (cityname)
{
// render the grid to the specified div in the page
// resellergrid.render();
resellerstore.load();
wingrid.show(this);
}
}
so use the globalObj.resellerwindow(......);
The problem is that this does not point to the class itself. Should you need to render the a element as a string instead of JavaScript object you will need to call a global function in which to call the resellerwindow function (after obtaining correct reference). However, I believe a much more efficient way would be to abandon the string and use JavaScript object instead. Then you can do something like the following:
var a = document.createElement("a");
a.onclick = this.resselerwindow;
If you use jQuery something like the following can be used:
return $("<a />").click(this.resselerwindow)[0];
instead of building and passing direct html, try these.
Create Anchor object
{ tag: 'a',
href: '#',
html: 'click me',
onclick: this.resellerWindow }
Make sure that, scope in linkRenderer is grid, by settings 'scope: this' in that column definition. So that this.resellerWindow refers to grid's function.
try returning created object.

Categories