extjs How to get a grid - variables

In Designer I set my grid name to equal MyGrid
On clicking the button addRecord is called, it fails where rows is attemting to get an undefined grid.
How do I define this MyGrid so that it references the grid within the panel?
Ext.define('MyApp.view.MyPanel', {
extend: 'MyApp.view.ui.MyPanel',
initComponent: function() {
var me = this;
me.callParent(arguments);
var button = me.down('button[text=Submit]');
button.on('click', me.onSubmitBtnClick, me);
},
addRecord: function(myRecordArray) {
var rows = grid.getStore().getRange(); // ERROR happens here
console.log(rows);
},
onSubmitBtnClick: function() {
this.addRecord(["ll", "kk", "mm"]);
}
});
Chrome Javascript Debugger Console ->
Uncaught ReferenceError: grid is not defined

Before you call grid.getStore() you need to define "grid". You can just do var grid = this; right before the call because you are defining the addRecord function from inside of the grid.
EDIT:
I just noticed that this wasn't being called from inside the grid panel with the store but some other panel. What you will have to do to is set an id config on your grid panel. E.g. id: MyGridPanel There may already be an id config set on it and you just have to find out what it is. If you are using the ExtJS designer it may actually already be set to "MyGridPanel". Then you would call it like so:
var grid = Ext.getCmp("MyGridPanel");
then you would do:
grid.getStore().getRange()

try changing button.on('click', me.onSubmitBtnClick, me) to button.on('click', Ext.bind(me.onSubmitBtnClick, me), me)
This looks like a scope issue, in your onSubmitBtn() method, this probably refering to the wrong object (e.g. window, or the button), and not the grid object, which is what you want.

Related

Change ICN contentViewer's tab title in split pane mode?

I need to change the "title" for each document shown in ICN Viewer, dynamically, at runtime. I'll read the new viewer tab title from the document properties
ENVIRONMENT: ICN 2.0.3 CM8.5 WAS 8.5.5
CODE SO FAR:
I found a PARTIAL solution by hooking "ecm.model.desktop, onChange":
aspect.after(ecm.model.desktop, 'onChange', function() {
var contentViewer = dijit.byId('contentViewer');
if (contentViewer) {
var viewerTabTitleDef = new ViewerTabTitleDef ();
contentViewer.mainTabContainer.getChildren().forEach(function(child) {
viewerTabTitleDef.changeTitle(viewerTabTitleDef.self,
child.controlButton, child.contentViewerPane.viewerItem.item);
});
...
I was able to extend this for subsequent documents opened in the same viewer, and optimized by "removing()" the handler after this initial call. Here is the complete code:
var kill = aspect.after(ecm.model.desktop, 'onChange', function() {
var contentViewer = dijit.byId('contentViewer');
// "contentViewer" will be "unknown" unless viewer invoked
console.log('onChange: contentViewer', contentViewer);
if (contentViewer) {
console.log("new ViewerTabTitleDef()...");
kill.remove();
var viewerTabTitleDef = new ViewerTabTitleDef ();
contentViewer.mainTabContainer.getChildren().forEach(function(child) {
// For initially opened tabs
console.log('initially opened: child', child);
viewerTabTitleDef.changeTitle(viewerTabTitleDef.self, child.controlButton, child.contentViewerPane.viewerItem.item);
});
aspect.after(contentViewer.mainTabContainer, 'addChild', function(child) {
// For tabs added after the viewer was opened
console.log('subsequently opened: child', child);
viewerTabTitleDef.changeTitle(viewerTabTitleDef, child.controlButton, child.contentViewerPane.viewerItem.item);
}, true);
} // end if contentViewer
}); // end aspect.after(onChange desktop)
CURRENT PROBLEM:
Q: How can I change the label for a split tab (either vertical or horizontal)?
So far, I have NOT been able to find any event for any ICN/ECM widget or object variable that I can trigger on.
Thank you in advance!
===============================================
ADDENDUM:
Many thanks to Ivo Jonker, for his suggestion to modify the widget prototype's
"getHtmlName()" method. It worked!
Specifically:
I'm invoking this code from an ICN plugin. I set event handlers in my plugin's base .js file, but it actually gets invoked in the new, separate viewer window.
The original prototype looked like this:
getHtmlName: function() {
var methodName = "getHtmlName";
this.logEntry(methodName);
var displayName = this.item.getDisplayValue("{NAME}");
if (displayName == "") {
displayName = this.item.name;
}
var htmlName = entities.encode(displayName);
this.logExit(methodName);
return htmlName;
},
Per Ivo's suggestion, I overrode the prototype method like this:
myPluginDojo.viewerTabTitleDef = viewerTabTitleDef;
...
ecm.widget.viewer.model.ViewerItem.prototype.getHtmlName = function () {
console.log("NEW getHtmlName()...");
var displayName = myPluginDojo.viewerTabTitleDef.getTitle(this.item);
return displayName;
};
If i understand you correctly, you want to show a different tab-title (instead of the document title) in the navigator viewer whenever a doc is opened?
How about this:
Every document you open in the viewer is wrapped in a ecm.widget.viewer.model.ViewerItem which exposes the getHtmlName that returns the name used in the tab.
Your solution would be to implement your own getHtmlName.
Unfortunately though, the ViewerItem is constructed in the ecm.widget.viewer.ContentViewer#_open and then passed to the ecm.widget.viewer.ContentViewer#_openTab. So you'll either violate best practice by mingling with IBM private method's, or you'll go for a generic approach and just replace the ecm.widget.viewer.model.ViewerItem.prototype.getHtmlName

Using the same InfoWindow for two AttributeInspectors

I've got two editable feature layers in my application, and I'm trying to attach the appropriate attribute inspector depending on which feature layer my user is trying to edit.
I create the Attribute Inspectors for both feature layers when my application loads and then attach the appropriate attribute inspector to the map's InfoWindow when the user is trying to edit a feature layer.
All works well, until the user tries to edit another feature layer. When I try and attach a different attribute inspector to the infowindow, it just comes up blank.
Here's roughly what I'm doing:
// AttributeEditor1 for FeatureLayer1 in Class1
constructor: function(options) {
this.options = lang.mixin(this.options, options);
this.map = options.map;
this.configureAttributeEditor1();
},
configureAttributeEditor1: function() {
this.attributeEditor1 = new AttributeInspector({
layerInfos: layerInfos
}, domConstruct.create("div"));
// here I add a Save and Delete button and various event handlers
this.attributeEditor1.startup();
},
// I call this when I know that the user wants to edit FeatureLayer 1
attachEditor1: function() {
this.map.infoWindow.setContent(this.attributeEditor1.domNode);
this.map.infoWindow.resize(350, 240);
},
// AttributeEditor2 for FeatureLayer2 in Class2
constructor: function(options) {
this.options = lang.mixin(this.options, options);
this.map = options.map;
this.configureAttributeEditor2();
},
configureAttributeEditor2: function() {
this.attributeEditor2 = new AttributeInspector({
layerInfos: layerInfos
}, domConstruct.create("div"));
// here I add a Save and Delete button and various event handlers
this.attributeEditor2.startup();
},
// I call this when I know that the user wants to edit FeatureLayer 2
attachEditor2: function() {
this.map.infoWindow.setContent(this.attributeEditor2.domNode);
this.map.infoWindow.resize(350, 240);
},
Thanks in advance.
When you update the content of infoWindow using map.infoWindow.setContent, it destroys the previous content and then updated the new content. So basically your AttributeInspector1 will be destroyed when you updated the info window with AttributeInspector2.
You need not create multiple AttributeInspector, while working on multiple FeatureLayer. The layerInfos property is an array type, you could set upd multiple layers.
But, I guess you have different needs/actions to be taken when you switch between layers. The best thing you could do is to either create new AttributeInspector every time you switch, or just update the layerInfos and save and delete events. Make sure you remove the previous save and delete event handles.

How to pop to the parent window in a tab?

I am trying to replace the default Back button to a custom image button in a Titanium iOS project.
I am opening several windows in a tab with the following code:
currentTab.open(childWindow);
How do I "pop" back to the previous (parent) window?
I tried the following:
childWindow.close();
and:
currentTab.close(childWindow);
But both don't work. What am I doing wrong?
They added a method named popToRootWindow in Ti SDK 6.2
Reference : http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Tab-method-popToRootWindow
It's hard to say what is wrong on your side without checking the actual code. However here is the snippet of code which does exactly what you are looking for. It allows to open two windows in one tab. The onclick listener on the second window simple closes this window. It in turn triggers the first window to come up. Maybe it can be helpful to spot a problem in your code.
Here is the contents of index.js:
$.index.open();
var tabGroup = Titanium.UI.createTabGroup();
var win1 = Titanium.UI.createWindow({title: 'Window 1'});
win1.add(Titanium.UI.createLabel({text: 'Window 1'}));
var button1 = Titanium.UI.createButton({bottom: 0, title: 'Next'});
win1.add(button1);
button1.addEventListener('click', function (e) {
var win2 = Titanium.UI.createWindow({title: 'Window 2'});
win2.add(Titanium.UI.createLabel({text: 'Window 2'}));
var button2 = Titanium.UI.createButton({bottom: 0, title: 'Back to Window 1'});
win2.add(button2);
button2.addEventListener('click', function (e) {
win2.close();
});
tab.open(win2);
});
var tab = Titanium.UI.createTab({title: 'Tab 1', window: win1});
tabGroup.addTab(tab);
tabGroup.open();
Note: index.xml file for this example can be very simple: with only one empty element Window class="container"
Andrew's answer helped and I solved the problem with win.close() function call.
The reason it was giving the following error:
Undefined is not a variable.
was because I was trying to access the window variable with a wrong reference.
this.backButton.addEventListener("click", function() {
this.win.close();
});
this.win was the variable for the child window, and stupidly I used the same inside the backButton event listener, where this was recognized as the callback function and it gave me the above error.
Just changing it to the following helped.
_this = this;
this.backButton.addEventListener("click", function() {
_this.win.close();
});

How to catch opened event on a ComboBox with Dojo?

I want to know whether a combo box has been opened and call a function that displays an progress bar while it loads the data from a store. I've check the API but no I didn't find any suitable event for what I'm doing.
EDIT
What I want to do is start a progress bar while the combobox is populated from the store. I've created a widget with the combobox and the progress bar (a custom class) and "decorate" openDropDown function with aspect.before. This is the code I've written:
postCreate: function() {
this.inherited(arguments);
aspect.before(
this.comboBox, 'openDropDown',
lang.hitch(this, function(){
this.progressBar.increase();
})
);
on(
this.comboBox,
'search',
lang.hitch(this.progressBar, 'decrease')
);
}
But it seems is not using the right progressBar object.
It sounds like you are looking for something like an "onOpen" event. as of Dojo 1.10 The Dijit/Combobox widget does not support an event like the one you are describing, however it does support a number of other events that might meet your requirements.
I recommend looking into the api for a list of possible events: http://dojotoolkit.org/api/
However the following code will create a custom "onOpen" event like what you are describing. I've provided a jsfiddle which demos this new event
http://jsfiddle.net/kagant15/z4nvzy44/
var comboBox = new ComboBox({
id: "stateSelect",
name: "state",
value: "California",
store: stateStore,
searchAttr: "name"
}, "stateSelect")
// grab the existing openDropDown method
var openDropDownFunction = comboBox.openDropDown;
newFunction = function(){
topic.publish("openDropDown") // add the custom "openDropDown" event trigger
return openDropDownFunction.apply(this);
}
// replace the old comBox method will our new function
comboBox.openDropDown = newFunction;
// Subscribe to the custom openDropDown event and do something when it fires
topic.subscribe("openDropDown", function(){
console.log("Open Drop Down even trigger");
});

Dojo/Dijit TitlePane

How do you make a titlePane's height dynamic so that if content is added to the pane after the page has loaded the TitlePane will expand?
It looks like the rich content editor being an iframe that is loaded asynchronously confuses the initial layout.
As #missingno mentioned, the resize function is what you want to look at.
If you execute the following function on your page, you can see that it does correctly resize everything:
//iterate through all widgets
dijit.registry.forEach(function(widget){
//if widget has a resize function, call it
if(widget.resize){
widget.resize()
}
});
The above function iterates through all widgets and resizes all of them. This is probably unneccessary. I think you would only need to call it on each of your layout-related widgets, after the dijit.Editor is initialized.
The easiest way to do this on the actual page would probably to add it to your addOnLoad function. For exampe:
dojo.addOnLoad(function() {
dijit.byId("ContentLetterTemplate").set("href","index2.html");
//perform resize on widgets after they are created and parsed.
dijit.registry.forEach(function(widget){
//if widget has a resize function, call it
if(widget.resize){
widget.resize()
}
});
});
EDIT: Another possible fix to the problem is setting the doLayout property on your Content Panes to false. By default all ContentPane's (including subclasses such as TitlePane and dojox.layout.ContentPane) have this property set to true. This means that the size of the ContentPane is predetermined and static. By setting the doLayout property to false, the size of the ContentPanes will grow organically as the content becomes larger or smaller.
Layout widgets have a .resize() method that you can call to trigger a recalculation. Most of the time you don't need to call it yourself (as shown in the examples in the comments) but in some situations you have no choice.
I've made an example how to load data after the pane is open and build content of pane.
What bothers me is after creating grid, I have to first put it into DOM, and after that into title pane, otherwise title pane won't get proper height. There should be cleaner way to do this.
Check it out: http://jsfiddle.net/keemor/T46tt/2/
dojo.require("dijit.TitlePane");
dojo.require("dojo.store.Memory");
dojo.require("dojo.data.ObjectStore");
dojo.require("dojox.grid.DataGrid");
dojo.ready(function() {
var pane = new dijit.TitlePane({
title: 'Dynamic title pane',
open: false,
toggle: function() {
var self = this;
self.inherited('toggle', arguments);
self._setContent(self.onDownloadStart(), true);
if (!self.open) {
return;
}
var xhr = dojo.xhrGet({
url: '/echo/json/',
load: function(r) {
var someData = [{
id: 1,
name: "One"},
{
id: 2,
name: "Two"}];
var store = dojo.data.ObjectStore({
objectStore: new dojo.store.Memory({
data: someData
})
});
var grid = new dojox.grid.DataGrid({
store: store,
structure: [{
name: "Name",
field: "name",
width: "200px"}],
autoHeight: true
});
//After inserting grid anywhere on page it gets height
//Without this line title pane doesn't resize after inserting grid
dojo.place(grid.domNode, dojo.body());
grid.startup();
self.set('content', grid.domNode);
}
});
}
});
dojo.place(pane.domNode, dojo.body());
pane.toggle();
});​
My solution is to move innerWidget.startup() into the after advice to "toggle".
titlePane.aspect = aspect.after(titlePane, 'toggle', function () {
if (titlePane.open) {
titlePane.grid.startup();
titlePane.aspect.remove();
}
});
See the dojo/aspect reference documentation for more information.