How to call this onclick javascript function in my architecture - javascript

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.

Related

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

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;
...

Where to programmatically set column filters when using a spreadsheet selModel?

This is a follow up question that I got answered here: How can I programmatically set column filters?
I have a 188 line Ext.js view. In this view I extend Ext.grid.Panel and in this grid I have set the selModel like so ...
selModel: {
cellSelect: false, // Only support row selection.
type: 'spreadsheet' // Use the new "spreadsheet" style grid selection model.
},
On one of the columns, the Status column, I am programmatically setting the filter so that only rows that have the Status of Ready will appear when the page firsts renders. I have been doing this here in the code:
columns: [
...
{
text: 'Status',
dataIndex: 'status',
itemId: 'status',
renderer: function(value, metaData) {
var filter = this.up('panel').down('#status').filter;
if (!filter.menu) {
filter.createMenu();
filter.menu
.down('menuitem[value="Ready"]')
.setChecked(true);
}
metaData.tdStyle = (value == 'Ready') ?
'color:green;font-weight: bold' :
'color:red;font-style: italic'
return(value)
},
filter: 'list',
flex: 1,
},
... more columns ...
A helpful SO member pointed out that is not the most efficient place for the code that sets the filter as the code will be executed for each row in the grid.
I have tried adding an afterrender function like so ...
{
text: 'Status',
dataIndex: 'status',
itemId: 'status',
renderer: function(value, metaData) {
metaData.tdStyle = (value == 'Ready') ?
'color:green;font-weight: bold' :
'color:red;font-style: italic'
return(value)
},
filter: 'list',
flex: 1,
listeners: {
afterrender: function(value) {
Ext.Msg.alert('We have been rendered value is ' + value );
var filter = this.up('panel').down('#status').filter;
if (!filter.menu) {
filter.createMenu();
filter.menu
.down('menuitem[value="Ready"]')
.setChecked(true); //Uncaught TypeError: Cannot read property 'setChecked' of null
}
}},
... but that results in this error message, //Uncaught TypeError: Cannot read property 'setChecked' of null.
What am I doing wrong here? Do I need the listeners:? Am I not getting passed the data I think I am getting passed to my afterrender function? Should I defining a initComponent function?
UPDATE:
I changed my code to what DrakeES suggested, ...
{
text: 'Status',
dataIndex: 'status',
itemId: 'status',
renderer: function(value, metaData) {
metaData.tdStyle = (value == 'Ready') ?
'color:green;font-weight: bold' :
'color:red;font-style: italic'
return(value)
},
flex: 1,
filter: {
type: 'list',
value: 'Ready'
}
... but the result is this:
Where the animated loading image just sits there and spins. This prevents the user from be able to change the filter interactively. I wonder what it is I am doing wrong here?
I am programmatically setting the filter so that only rows that have
the Status of Ready will appear when the page firsts renders
What checking the filter's checkbox effectively does is setting filter on the store. Because you want the filter to be applied initially, it would be better to have it in the store config right away:
filters: [
{
id: 'x-gridfilter-status',
property: 'status',
value: 'Ready'
}
]
That way the grid view appear filtered in the first place — instead of initially showing all rows and only then filtering them out once the column menu renders and applies the filter. Note that having id: 'x-gridfilter-status' on the store's filter is required so that the column's filter picks it up instead of creating a duplicate.
Setting filter on the store, however, will not send feedback to the column filter menu, so the latter will remain unchecked unless you explicitly check it. Therefore, you still need an afterrender handler on either the grid or the column to make things look in sync.
A simple and elegant solution without listeners and stuff:
filter: {
type: 'list',
value: 'Ready'
}
Full working example: https://fiddle.sencha.com/#fiddle/prp

ExtJS qtip is not getting displayed

I have a grid panel and im trying to display a hover popup on a particular column. I have tried both tooltip and qtip but they are just not getting displayed. My grid panel looks as:
Ext.create('Ext.grid.Panel', {
id: 'frPanel-'+interfaceId,
store: frStore,
columns : [ {text : 'Source',
dataIndex : 'source',
renderer : function(value) {
return convertObjValue(value);
},
listeners: {
afterrender: function ()
{
Ext.create('Ext.tip.ToolTip',
{
target: this.el,
trackMouse: true,
html: "Hello there"
});
}
}
}, {
text : 'Destination',
dataIndex : 'destination',
menuDisabled : true,
renderer : function(value, metaData) {
var newValue = convertObjValue(value);
metaData.tdAttr = 'data-qtip="' + newValue + '"';
return newValue;
}
}
What am i doing wrong here? Any help how i can achieve this?
EDIT : So i made the second column work by adding Ext.QuickTips.init(); in the onReady() function. But i still wanna know how to make it work using the approach in first column.

Google Places Auto-complete in extjs4

I am using extjs4 and Spring at server side. I need to integrate Google Places Auto-complete inside one of the extjs4 form. Is there any way this can be done. I am not sure weather we can integrate Google Auto-complete with extjs I have searched but not find anything more specific to my requirement. Please guide me ..... look at my code ...
Ext.define('abce.view.ReportMissing', {
extend : 'Ext.panel.Panel',
alias : 'widget.report_missing',
bodyPadding : 10,
autoScroll : true,
frame : true,
items : [{
id : 'report_form',
xtype : 'form',
frame : true,
defaultType : 'textfield',
items : [{
xtype : 'combobox',
store : new Ext.data.Store({
autoLoad : true,
//fields : ['memberName', 'email'],
proxy : {
type : 'ajax',
headers : {
'Content-Type' : 'application/json',
'Accept' : 'application/json'
},
url : 'http://maps.googleapis.com/maps/api/geocode/json?address=hyd+&sensor=false',
remoteSort : true,
method : 'GET',
reader : {
type : 'json',
successProperty : 'status'
}
}
})
}]
});
https://developers.google.com/places/documentation/autocomplete
Why not instead of use the sencha combobox, use a simple text input as suggest the google api autocomplete documentation.
(I first try with a just common textfield but it didn't work)
Then declare a panel or component with html as the following example, and then assign the render:
xtype: 'component',
html: '<div> <input id="searchTextField" type="text" size="50"> </div>',
listeners: {
render: function () {
var input = document.getElementById('searchTextField');
autocomplete = new google.maps.places.Autocomplete(input, { types: ['geocode'] });
autocomplete.addListener('place_changed', this.fillInAddress);
},
And result in this:
The proxy cannot be used to retrieve data from a URL on a different origin. See the limitations section of Ext.data.proxy.ajax for more information.
http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.data.proxy.Ajax
You will probably need to set up an endpoint on your server to proxy the request to Google if you want to use that API.
I was looking for a way to do the same, and I came up writing a custom proxy against the google map javascript library
Then I used this custom proxy in a regular combo box
ComboBox:
Ext.create('Ext.form.field.ComboBox', {
store: {
fields: [
{name: 'id'},
{name: 'description'}
],
proxy: 'google-places'
},
queryMode: 'remote',
displayField: 'description',
valueField: 'id',
hideTrigger: true,
forceSelection: true
});
Custom proxy: (inspired from Ext.data.proxy.Ajax)
Ext.define('com.custom.PlacesProxy', {
extend: 'Ext.data.proxy.Server',
alias: 'proxy.google-places',
constructor: function() {
this.callSuper();
this.autocompletePlaceService = new google.maps.places.AutocompleteService();
},
buildUrl: function() {
return 'dummyUrl';
},
doRequest: function(operation) {
var me = this,
request = me.buildRequest(operation),
params;
request.setConfig({
scope : me,
callback : me.createRequestCallback(request, operation),
disableCaching : false // explicitly set it to false, ServerProxy handles caching
});
return me.sendRequest(request);
},
sendRequest: function(request) {
var input = request.getOperation().getParams().query;
if(input) {
this.autocompletePlaceService.getPlacePredictions({
input: input
}, request.getCallback());
} else {
// don't query Google with null/empty input
request.getCallback().apply(this, [new Array()]);
}
this.lastRequest = request;
return request;
},
abort: function(request) {
// not supported by Google API
},
createRequestCallback: function(request, operation) {
var me = this;
return function(places) {
// handle result from google API
if (request === me.lastRequest) {
me.lastRequest = null;
}
// turn into a "response" ExtJs understands
var response = {
status: 200,
responseText: places ? Ext.encode(places) : []
};
me.processResponse(true, operation, request, response);
};
},
destroy: function() {
this.lastRequest = null;
this.callParent();
}
});
Note: I wrote this against ExtJs6 but it should basically work alike for ExtJs4.

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.

Categories