is there a way to receive some return value from a controller like
app.controllers.theController = new Ext.Controller({
...
getPrefsData: function(options){
//console.log("#getPrefsData: " + options.datastring);
return options.datastring;
},
...
to use it inside a panel-item:
app.views.PrefsView = Ext.extend(Ext.Panel, {
...
items: [
xtype: 'togglefield',
name: 'enableThis',
label: 'Enabler',
value : HERE I NEED THE VALUE FROM THE CONTROLLER,
]
something like
value: Ext.dispatch({
controller: app.controllers.clockcontroller,
action: 'getPrefsData',
datastring:'alarm'
});
doesn't work...
Maybe this will help;
In my application I needed to use somekind of session variable when switching between panels. A user selects an item in a list, and in the next panel I want to know what the ID was of the selected item.
Getting a return value from the controller (/function) didn't work out for me.
Instead I used:
Ext.apply(panel, {
testVariabele: index,
}),
This piece of code allowed me to set a 'global' variable ("panel" is the ID of my main panel) inside the function (controller). To access the variable in another panel or card you can now use:
panel.testVariabele;
Related
I am using a Kendo Grid with AngularJs and TypeScript. I am able to get the selected row but I cannot assign the result to a local variable as it seems to run in a different scope.
My grid has the following properties:
this.gridOptions = {
dataSource: {
data: this.items,
pageSize: 10
},
selectable: 'row',
filterable: {
mode: 'row'
},
change: this.onItemSelect,
...
}
The typescript function is as follows:
onItemSelect(kendoEvent : any) {
var grid = kendoEvent.sender;
this.selectedItem = grid.dataItem(grid.select());
}
selectedItem is defined in my Controller class:
export class ServicePackageModalController {
private selectedItem : any;
...
}
The problem is the this.selectedItem is undefined when I check it in another button event later on. I assume this is because the scope is different when the function gets called in the Kendo Grid, so 'this' means something else and not my controller class:
handleNext() {
console.debug(this.selectedItem) //this is undefined here?
}
So my question is how do I assign this result to my controller class so I can access it later on?
Only way I could see to solve this was adding the following code to my handleNext function:
var entityGrid = $("#EntitesGrid").data("kendoGrid");
var selectedItem = entityGrid.dataItem(entityGrid.select());
You also need to have an id attribute with the name EntitiesGrid on the kendo-grid directive.
Our testing team require IDs or class values to be set on the HTML elements in our message popup boxes. This is for their automated tests.
I can pass in a class value for the dialog panel by passing in a cls value like so:
Ext.Msg.show({
title:'Reset Grid Layout',
msg: 'Are you sure that you want to reset the grid layout?',
cls:'Reset-Grid-Layout-Message',
buttons: Ext.Msg.YESNO,
fn: function (response) {
if (response == 'yes') {
}
},
icon: Ext.window.MessageBox.QUESTION
});
Now we also need it on the buttons, and also on the text being displayed. Is there some way of getting a cls value onto the buttons?
I was thinking it may be possible to expand the button parameter into something like :
buttons : [{name:'but1', cls:'asdf'}, {name:'but2', cls:'asdf2'}]
But google is not giving me back anything useful.
If your testing team uses Selenium for their automated test, adding ids/classes in every component could be difficult for both of you.
Overriding components in Ext is a good solution, but I don't recommend this because it will affect all your components. Unless you know what you're doing.
I suggest, extend Ext.window.MessageBox and generate classes for your buttons based on your parent cls.
// Put this somewhere like /custom/messagebox.js
Ext.define('App.MyMessageBox', {
extend: 'Ext.window.MessageBox'
,initConfig: function(config) {
this.callParent(arguments);
}
,makeButton: function(btnIdx) {
var me = this;
var btnId = me.buttonIds[btnIdx];
return new Ext.button.Button({
handler: me.btnCallback
,cls: me.cls + '-' + btnId
,itemId: btnId
,scope: me
,text: me.buttonText[btnId]
,minWidth: 75
});
}
});
To use:
App.Box = new App.MyMessageBox({
cls:'reset-grid-layout'
}).show({
title:'Reset Grid Layout'
,msg: 'Are you sure that you want to reset the grid layout?'
,buttons: Ext.Msg.YESNO
,icon: Ext.window.MessageBox.QUESTION
});
Your buttons will have reset-grid-layout-yes and reset-grid-layout-no class.
You can do the same with other components you have. Check out the Fiddle. https://fiddle.sencha.com/#fiddle/7qb
You should refer to the API
cls : String A CSS class string to apply to the button's main element.
Overrides: Ext.AbstractComponent.cls
You can also use the filter on right side (not the one in the right top corner). Just type cls and you will see all properties, methods and events containing cls (note that you see by default just public members, use the menu on the right of this searchfield to extend this)
Edit
If you just need it for testing purpose I would recommend to override the responsible method. This should work (untested!)
Ext.window.MessageBox.override({
buttonClasses: [
'okCls', 'yesCls', 'noCls', 'cancelCls'
],
makeButton: function(btnIdx) {
var btnId = this.buttonIds[btnIdx];
var btnCls = this.buttonClasses[btnIdx];
return new Ext.button.Button({
handler: this.btnCallback,
cls: btnCls,
itemId: btnId,
scope: this,
text: this.buttonText[btnId],
minWidth: 75
});
}
});
I have a combo box in which the user selects a value, that value is passed to the checkbox data store and it is populated dynamically from database (oracle). I tried the code below. It seems that the selected parameter is being passed to checkbox and I can see the data being populated on the console. I just can't render the checkbox on form. The error I get is: typeError: this.items[0] is undefined.
testArray = new Array();
var testStore = new Ext.data.JsonStore({
proxy:new Ext.data.HttpProxy({
method:'GET',
prettyUrls:false,
url:'kiu.htm',
listeners:{
'loadexception':{
fn:test.form.data.loadException
}
}
}),
fields:["id", "display"],
reader:new Ext.data.JsonReader({
id:'id',
root:'results',
totalProperty:'totalCount',
fields:new Ext.data.Record.create([
{name:'id',type:'int'},
{name:'display',type:'string'}
])
}),
listeners:{
load: function(t, records, options, success) {
for(var i=0; i<records.length; i++) {
testArray.push({name:records[i].data.id, boxLabel: records[i].data.display});
alert(testArray[i].id);
}
}
}
});
{
xtype:'combo',
id:'comboid3',
store:combostore,
displayField:'display',
valueField:'id',
tabIndex:1,
loadingText:'Loading combo...',
listeners :{
select:function(event){
testStore.baseParams = {
"comboid":Ext.getCmp('comboid3').getValue()
};
testStore.load();
}
}
},
{
xtype:'checkboxgroup',
fieldLabel:'Check',
items:testArray
}
Help will be appreciated!
Specifying the Ext JS version is always going to be helpful. It appears this must be 2.x or 3.x and not the current version.
The issue is timing, load calls are asynchronous so by attempting to utilize testArray in this fashion you are likely referencing an empty array by the time it parses the items property of your checkboxgroup. You have a couple options around this... one is to grab a reference to the checkbox group and add the items into it, the other is to not put the checkbox group in the form at all until the call returns and then add it with the populated items array. In either case it is likely that you will need to look up a component reference to either the FormPanel or the CheckboxGroup from within the load handler function and call the 'add' method to add child items.
I think I have a very popular problem, but not found answer for it now. :)
I got 2 similar comboboxes - at first i set my value by id - comboT.setValue("22763"); and it properly set a text value linked with this id.
At second combobox i at first reload store(jsonstore) and then set value - comboC.setValue("3"); But this combo set only ID not text value (if i open list i can see what combo properly marked text value. And after (if list simply close without select) text value properly displayed at combo.
How to solve this problem?
Thanks.
Something like this, syntax may be slightly off since I am doing it from memory:
var val = 3;
var store = comboC.getStore();
store.on("load", function() {
comboC.setValue(val);
}):
store.load();
Loading the store is asynchronous, you might want to move setting the new value into the callback: event handler of store.load({...}), because otherwise, you set the value before the store is actually loaded.
EDIT: for completeness, an example, so you have an alternative version (in some cases it might be undesireable to bind the callback to the store itself, like ormuriauga did):
var val = 3;
var store = comboC.getStore();
store.load({
callback: function() {
comboC.setValue(val);
}
});
One more example on how to set the combobox's value by searching a string in the underlying data store. I was able to code this by using the samples in these answers as a baseline:
//The store's data definition must have at least a data.id field defined
set_combobox_value_from_store = function (combobox, valueField, value) {
//Get a reference to the combobox's underlying store
var store = combobox.getStore();
store.load({
callback: function () {
//Find item index in store
var index = store.find(valueField, value, false);
if (index < 0) return;
//Get model data id
var dataId = store.getAt(index).data.Id;
//Set combobox value and fire OnSelect event
combobox.setValueAndFireSelect(dataId);
}
});
In extjs 4.1 looks like combo.setValue() works when the type of valueField in the Model is "string". this was my code
Ext.define('Model.CboObras', {
extend: 'Ext.data.Model',
idProperty: 'co_obra',
fields: [{
name: 'co_obra',
type: 'int'
}, {
name: 'nb_obra',
type: 'string'
}]
});
this does not work.
When I changed my code to this:
Ext.define('Model.CboObras', {
extend: 'Ext.data.Model',
idProperty: 'co_obra',
fields: [{
name: 'co_obra',
type: 'string'
}, {
name: 'nb_obra',
type: 'string'
}]
});
After that I use this:
var store = comboC.getStore();
store.load({
callback: function() {
comboC.setValue(val);
}
});
it now works like a charm!
I'm adding a custom context menu to a TreePanel.
This was all working when I had a separate function for the context menu, but I was having problems where the context menu items would end up doubled/tripling up if I clicked on one of the options and then viewed the context menu again.
I had a look around for other contextmenu examples and came up with this one by Aaron Conran I pretty much "stole" it wholesale with a few additions, tacking the function directly into the Ext.ext.treePanel config. This gave me an error about "oe is undefined" which seemed to refer to "contextmenu: this.onContextMenu" in the tree config.
I figured it was probably something to do with the way I was defining all of this, so I decided to look at extending Ext.ext.TreePanel with my function in it as a learning exercise as much as anything.
Unfortunately, having managed to sort out extending TreePanel I'm now back to getting "oe is undefined" when the page tries to build the TreePanel. I've had a look around and I'm not really sure whats causing the problem, so any help or suggestions would be greatly appreciated.
Here is the code that is used to define/build the tree panel. I hope its not too horrible.
siteTree = Ext.extend(Ext.tree.TreePanel,{
constructor : function(config){
siteTree.superclass.constructor.call(this, config);
},
onContextMenu: function(n,e){
if (!this.contextMenu){
console.log('treeContextMenu',n,e);
if (n.parentNode.id == 'treeroot'){
var menuitems = [{text:'Add Child',id:'child'}];
} else {
var menuitems =
[{text:'Add Child',id:'child'},
{text:'Add Above',id:'above'},
{text:'Add Below',id:'below'}];
}
this.contextMenu = new Ext.menu.Menu({
id:'treeContextMenu',
defaults :{
handler : treeContextClick,
fqResourceURL : n.id
},
items : menuitems
});
}
var xy = e.getXY();
this.contextMenu.showAt(xy);
}
});
var treePanel = new siteTree({
id: 'tree-panel',
title : 'Site Tree',
region : 'center',
height : 300,
minSize: 150,
autoScroll: true,
// tree-specific configs:
rootVisible: false,
lines: false,
singleExpand: true,
useArrows: true,
dataUrl:'admin.page.getSiteTreeChildren?'+queryString,
root: {
id: 'treeroot',
nodeType: 'async',
text: 'nowt here',
draggable: false
},
listeners:{
contextmenu: this.onContextMenu
}
});
As a total aside; Is there a better way to do this in my context menu function?
if (n.parentNode.id == 'treeroot') {
Basically, if the clicked node is the top level I only want to give the user an add Child option, not add above/below.
Thanks in advance for your help
In your instantiation of your siteTree class you have:
listeners: {
contextmenu: this.onContextMenu
}
However, at the time of the instantiation this.onContextMenu is not pointing to the onContextMenu method you defined in siteTree.
One way of fixing it is to call the method from within a wrapper function:
listeners: {
contextmenu: function() {
this.onContextMenu();
}
}
Assuming you don't override the scope in the listeners config 'this' will be pointing to the siteTree instance at the time the listener is executed.
However, since you are already defining the context menu in the siteTree class, you may as well define the listener there:
constructor: function( config ) {
siteTree.superclass.constructor.call(this, config);
this.on('contextmenu', this.onContextMenu);
}
Ensuring the context menu is removed with the tree is also a good idea. This makes your siteTree definition:
var siteTree = Ext.extend(Ext.tree.TreePanel, {
constructor: function( config ) {
siteTree.superclass.constructor.call(this, config);
this.on('contextmenu', this.onContextMenu);
this.on('beforedestroy', this.onBeforeDestroy);
},
onContextMenu: function( node, event ) {
/* create and show this.contextMenu as needed */
},
onBeforeDestroy: function() {
if ( this.contextMenu ) {
this.contextMenu.destroy();
delete this.contextMenu;
}
}
});
I had this problem yesterday. The issue with the duplicate and triplicate items in the context menu is due to extjs adding multiple elements to the page with the same ID. Each time you call this.contextMenu.showAt(xy) you are adding a div with the ID 'treeContextMenu' to the page. Most browsers, IE especially, deal with this poorly. The solution is to remove the old context menu before adding the new one.
Here is an abridged version of my code:
var old = Ext.get("nodeContextMenu");
if(!Ext.isEmpty(old)) {
old.remove();
}
var menu = new Ext.menu.Menu({
id:'nodeContextMenu',
shadow:'drop',
items: [ ... ]
});
menu.showAt(e.xy);
I suggest never using hardcoded IDs. #aplumb suggests cleaning the DOM to reuse an existing ID. OK, but I suggest you cleanup the DOM when you no longer need the widgets/elements in the DOM and you should never reuse an ID.
var someId = Ext.id( null, 'myWidgetId' );
var someElement = new SuperWidget({
id: someId,
...
});
Just to add to owlness's answer
This bit here:
listeners: {
contextmenu: this.onContextMenu
}
Gets executed when the javascript file is loaded. this at that stage is most likely pointing to the window object.
A simple way to fix it is adding the listener on hide event of context menu, so you destroy him.
new Ext.menu.Menu(
{
items:[...],
listeners: { hide: function(mn){ mn.destroy(); } }
}
).show(node.ui.getAnchor());
;)