Could you teach me how to call nested methods? Basic idea, i want to have a function inside a class that i can configure from outside by sending another folderSelector with different return path. But when right now i'm trying to do that extjs says to me:
[W] XTemplate evaluation exception: foldersSelector is not a function
Code example:
Ext.define('somepath.Some1', {
extend: 'somepath.SomeParent',
text: 'sometext',
foldersSelector: function(data){
return data.folders;
},
initComponent: function(){
...
this.callParent();
}
renderer: function(data){
bla bla bla / got data from somewhere
...
...
foldersSelector(data);
// with this.foldersSelector result the same!
}
});
You are missing this in your function. You need to call the function from the class object. Something like this:
Ext.define('MyApp.view.MyPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.mypanel',
height: 250,
width: 400,
title: 'My Panel',
defaultListenerScope: true,
listeners: {
render: 'onPanelRender'
},
onPanelRender: function(component, eOpts) {
// call using this
this.folderSelector();
// call using component
component.folderSelector();
},
folderSelector: function(data) {
console.log('Function')
}
});
Fiddle https://fiddle.sencha.com/#view/editor&fiddle/1mpe
In your case, you are in the grid column, you can't call this because that's the grid. You have to get the column.
Ext.define('MyApp.view.MyColumn3', {
extend: 'MyApp.view.SuperColumn',
alias: 'widget.mycolumn3',
id: 'myColumnId',
foldersSelector: function (data) {
console.log('I AM CALLED');
return data + '-SOSO'
},
renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
// you have to get the column, there are many ways how to do so
var c = Ext.first('#myColumnId')
return c.foldersSelector(value)
}
// option without the id
renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
// this is the grid
var gridColumns = this.getColumns();
// we know the column index
var c = gridColumns[colIndex];
return c.foldersSelector(value)
}
});
Fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1mpo
Related
Am new in Ext JS community. Here I want to apply a change event to child component which is 'textfield'.
I have specified the 'onChangeSealNumber' function in the controller. But it's not getting fired.
Can someone help me into it?
I have tried many approaches, however, If I pass anonymous function on change, it will work. But it won't work when we explicitly specify as 'onChangeSealNumber'.
View File
/**
* Search Form Panel View.
* #class 'BulkTransaction.view.searchfrom.SearchForm'
*/
Ext.define('BulkTransaction.view.searchform.SearchForm', {
extend: 'Ext.container.Container',
requires: [
'Common.view.widget.RepeatingWidgetGroup',
'BulkTransaction.view.storagelocation.StorageLocation',
'BulkTransaction.view.searchform.SearchFormController',
],
alias: 'widget.searchform',
controller: 'searchformcontroller',
items: [
{
xtype: 'basepanel',
width: '100%',
reference: 'searchform',
header: false,
items: [
{
width: '100%',
xtype: 'connect-repeating-widget-group',
bind: {
store: '{topSealNumbers}'
},
bindReference: 'topSealNumbers',
widgetConfig: {
xtype: 'textfield',
fieldLabel: BulkTransaction.util.Constants.searchForm.topSealNumbers,
allowBlank: false,
bind: '{topSealNumbers.searchCriteria}',
cls: 'seal-number-field',
listeners: {
change: 'onChangeSealNumber'
}
}
}
]
}
]
});
Controler File
/**
* Controller containing the methods implementing functionality
* related to search form
*/
Ext.define('BulkTransaction.view.searchform.SearchFormController', {
extend: 'Ext.app.ViewController',
alias: 'controller.searchformcontroller',
init: function () {
const me = this;
const viewModel = me.getViewModel();
viewModel.bind({
bindTo: '{topSealNumbers}',
deep: true
}, me.onSearchCriteriaChange, me);
},
/**
* Handle change to the sealnumber details
* #private
*/
onSearchCriteriaChange: function (store) {
const me = this;
let searchCriteriaRecords;
searchCriteriaRecords = store.queryBy(rec =>{
if (!Ext.isEmpty(rec.get('searchCriteria').trim())) {
return rec;
}
});
this.fireEvent('toggleSearchButton', searchCriteriaRecords.length > 0);
},
onSealNumberChange (elm) {
const me = this,
view = me.getView();
}
});
In you controller you need to create a function named onChangeSealNumber something like this
Ext.define('BulkTransaction.view.searchform.SearchFormController', {
extend: 'Ext.app.ViewController',
alias: 'controller.searchformcontroller',
onChangeSealNumber: function(field, newValue, oldValue, eOpts) {
//do something here
},
})
You can try (MyApp - name of your application):
listeners: {change: MyApp.app.getController('SearchFormController').onChangeSealNumber()}
But as for me its not good way to work with controller. More better add into controller (inside init):
init: function (application) {
this.control({
"searchform textfield": {
change: this.onChangeSealNumber
},
});
}
As for identifier I'm not sure because as usually use itemId and name
(like `"#myItemId textfield[name=MyFieldName]"` )
Inside my extjs grid, when I right click I call a context menu. When I click on one of the items I want to launch a method in the controller. This all works successfully, problem is I want to pass the parent grid that this is being called from into the controller method. Can someone please show me how to do this?
This is my context menu
Ext.define('Example.ContextMenuTradematch', {
xtype: 'contextMenuTradematch',
extend: 'Ext.menu.Menu',
items: [
{
text: 'Match Trade',
iconCls: 'greenIcon',
listeners: {
click: {
fn: 'onMatchTrade',
params: {
param1: this
}
}
}
},
{
text: 'Delete Trade',
iconCls: 'deleteIcon',
listeners: {
click: 'onDeleteTrade'
}
}
]
});
then this is my controller method
onMatchTrade: function (event, target, options) {
debugger;
var me = this;
How can I access the grid that the event originated from?
--and this is how I add the context menu to the grid
title: 'Tradematch Results: UNMATCHED',
xtype: 'grid',
itemId: 'gridUnmatchedId',
ui: 'featuredpanel-framed',
cls: 'custom-grid',
margin: '0px 10px 0px 10px',
flex: 2,
width: '100%',
bind: {
store: '{myTM_ResultsStore}'
},
listeners: {
itemcontextmenu: 'showContextMenuTradematch'
},
and this is how the controller adds it...
getContextMenu: function (cMenu) {
if (!this.contextMenu) {
debugger;
this.contextMenu = this.getView().add({ xtype: cMenu });
}
return this.contextMenu;
},
showContextMenuTradematch: function (view, rec, node, index, e) {
e.stopEvent();
e.stopEvent();
debugger;
this.getContextMenu('contextMenuTradematch1').show().setPagePosition(e.getXY());
return false;
},
The easiest way to do this is when you create your Example.ContextMenuTradematch instance - that I'm assuming you do from a itemcontextmenu listener - then you could pass a reference to the grid.
itemcontextmenu: function (grid, record, item) {
// code to create your menu
// probably something like:
if (!grid.contextMenu) {
grid.contextMenu = Ext.create('Example.ContextMenuTradematch', {
ownerGrid: grid
});
}
grid.contextMenu.showBy(item);
}
If onMatchTrade was fired by clicking on an Ext.menu.Item instance then it's signature will be:
onMatchTrade: function (item, e) {
var menu = item.up('menu'),
grid = menu.ownerGrid;
console.log(grid);
}
There was a lot of guessing here. If this is not how you are creating your menu or calling the methods, adding a fiddle with the issue would help.
Here is a fiddle to use as template: https://fiddle.sencha.com/#view/editor&fiddle/24fc
In ExtJs, there are many options to filter a grid. There are two nice examples in the documentation, like referenced in this question.
Remote filtering
Local filtering
However, having the filter hidden in the default dropdown menu of Ext.ux.grid.FiltersFeature looks really awkward for me. A good ergonomic choice would to create search fields in the column headers, like #Ctacus shows in his question.
How can this be achieved ?
After quite much research through the sparse documentation, and thanks to great questions and answers in SO, I came up with a simple class, that adds this functionality and and allows for configurations.
It looks like this:
You add this field in your grid like this:
Ext.define('Sandbox.view.OwnersGrid', {
extend: 'Ext.grid.Panel',
requires: ['Sandbox.view.SearchTrigger'],
alias: 'widget.ownersGrid',
store: 'Owners',
columns: [{
dataIndex: 'id',
width: 50,
text: 'ID'
}, {
dataIndex: 'name',
text: 'Name',
items:[{
xtype: 'searchtrigger',
autoSearch: true
}]
},
The following configs are possible, and work like described in the doc for Ext.util.Filter:
anyMatch
caseSensitive
exactMatch
operator
additionnaly you can use autoSearch. If true, the filter searches as you type, if false or not set, one has to click on the search icon to apply the filter.
ExtJs 5 / 6 Source:
Ext.define('Sandbox.view.SearchTrigger', {
extend: 'Ext.form.field.Text',
alias: 'widget.searchtrigger',
triggers:{
search: {
cls: 'x-form-search-trigger',
handler: function() {
this.setFilter(this.up().dataIndex, this.getValue())
}
},
clear: {
cls: 'x-form-clear-trigger',
handler: function() {
this.setValue('')
if(!this.autoSearch) this.setFilter(this.up().dataIndex, '')
}
}
},
setFilter: function(filterId, value){
var store = this.up('grid').getStore();
if(value){
store.removeFilter(filterId, false)
var filter = {id: filterId, property: filterId, value: value};
if(this.anyMatch) filter.anyMatch = this.anyMatch
if(this.caseSensitive) filter.caseSensitive = this.caseSensitive
if(this.exactMatch) filter.exactMatch = this.exactMatch
if(this.operator) filter.operator = this.operator
console.log(this.anyMatch, filter)
store.addFilter(filter)
} else {
store.filters.removeAtKey(filterId)
store.reload()
}
},
listeners: {
render: function(){
var me = this;
me.ownerCt.on('resize', function(){
me.setWidth(this.getEl().getWidth())
})
},
change: function() {
if(this.autoSearch) this.setFilter(this.up().dataIndex, this.getValue())
}
}
})
For ExtJs 6.2.0, the following bug and its workaround is relevant to this, else the column cannot be flexed.
ExtJs 4 Source:
Ext.define('Sandbox.view.SearchTrigger', {
extend: 'Ext.form.field.Trigger',
alias: 'widget.searchtrigger',
triggerCls: 'x-form-clear-trigger',
trigger2Cls: 'x-form-search-trigger',
onTriggerClick: function() {
this.setValue('')
this.setFilter(this.up().dataIndex, '')
},
onTrigger2Click: function() {
this.setFilter(this.up().dataIndex, this.getValue())
},
setFilter: function(filterId, value){
var store = this.up('grid').getStore();
if(value){
store.removeFilter(filterId, false)
var filter = {id: filterId, property: filterId, value: value};
if(this.anyMatch) filter.anyMatch = this.anyMatch
if(this.caseSensitive) filter.caseSensitive = this.caseSensitive
if(this.exactMatch) filter.exactMatch = this.exactMatch
if(this.operator) filter.operator = this.operator
console.log(this.anyMatch, filter)
store.addFilter(filter)
} else {
store.filters.removeAtKey(filterId)
store.reload()
}
},
listeners: {
render: function(){
var me = this;
me.ownerCt.on('resize', function(){
me.setWidth(this.getEl().getWidth())
})
},
change: function() {
if(this.autoSearch) this.setFilter(this.up().dataIndex, this.getValue())
}
}
})
In my code I use MVC architecture. My view Component looks like this:
Ext.define('calendar.view.event', {
extend: 'Ext.Component',
alias: 'widget.event',
renderTo: Ext.getBody(),
initComponent:function(){
this.addEvents('eventClick');
this.callParent(arguments);
},
afterRender: function() {
this.mon(this.el, 'click', this.eventClick, this); //mon( item, ename, [fn], [scope], [options] ) - zkratka pro addManagedListener.
this.callParent(arguments);
},
eventClick: function (ev, t) {
var height = this.getHeight();
this.fireEvent('eventClick', this, height, ev);
}
});
Im firing Event on click for controller which is like this:
Ext.define('calendar.controller.eventsChange', {
extend: 'Ext.app.Controller',
views: ['event'],
init: function () {
this.control({
'event': {
eventClick: function (callerObject) {
this.editEvent(callerObject)
}
}
});
},
editEvent: function (callerObject) { //oznaci jako editovatelny
callerObject.get
if(callerObject.hasCls('SpecEv') || callerObject.hasCls('activeEvent'))
{
if (callerObject.hasCls('activeEvent'))
{
callerObject.removeCls('activeEvent');
callerObject.addCls('SpecEv');
this.application.fireEvent('reRender');
}
else
{
console.log(callerObject);
callerObject.addCls('activeEvent');
callerObject.removeCls('SpecEv');
Ext.apply(callerObject, {
resizable: {
pinned:true,
dynamic:true
},
draggable: true,
});
callerObject.setLocalX(0);
var parentWidth = Ext.getCmp('SpecEv').getWidth();
callerObject.setWidth(parentWidth);
}
}
}
});
The problem comes when with
Ext.apply(callerObject, {resizable: {
pinned:true,
dynamic:true
},
draggable: true,
});
When console.log shows me the object after my apply, it says draggable:true and resizable:true. Does anyone know where the problem is?
Thanks for reponses.
It can't works, because your code only set configuration properties, which are handled only when component is initializing. So when you set these properties on already constructed object nothing happen. Component resizability and draggability will not be initialized automatically after setting these properties.
You can try use Ext.Component initResizable and initDraggable methods. But these methods are internal and undocumented.
callerObject.initResizable({
pinned:true,
dynamic:true
});
callerObject.initDraggable();
Also you can try setup Ext.util.ComponentDragger and Ext.resizer.Resizer for your existing component manually.
In my Grid, when I click on the Action button (the delete and edit button shown in the code below), I need to pop open a window without alerting the user with a Alert message;
In the following code I am using a HANDLER handler: buttonClicked and trying to access the row value i clicked from a different function below
buttonClicked :function (){...}
I don't know how to do this, can someone please help me ?
Can i access the row I clicked and display its name from the Controller class ?
CODE SNIPET
Ext.define('CountryAppTest.view.user.Gridview', {
extend: 'Ext.grid.Panel',
initComponent: function() {
this.store = 'store';
this.columns = [{
xtype: 'ac',
items: [{
icon: 'lib/extjs/examples/restful/images/delete.png',
handler: buttonClicked
}]
}, {
text: "username",
dataIndex: 'username'
}];
this.viewConfig = {
forceFit: true
};
this.callParent(arguments);
},
buttonClicked: function(grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
Ext.Msg.alert("Info", "name " + rec.get('username'));
}
});
Add the parameters (grid, rowIndex, colIndex) into your buttonClicked declaration.