How to create a new widget for dojox.grid.cells.dijit? - dojo

I am trying to create a button widget for dojox.grid.
My problems are:
1) The button is only shown when I double click the grid.
2) I can't figure out how to set attributes through declarative markup. It seems that the markupFactory function is responsible for it but it doesn't set the widget's label.
The following code demonstrates what I've got so far:
dojo.require("dojox.grid.DataGrid");
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.form.Button");
dojo.require("dojox.grid.cells.dijit");
dojo.require("dojo.parser");
dojo.declare("dojox.grid.cells.Button", dojox.grid.cells._Widget, {
widgetClass: dijit.form.Button,
alwaysEditing: true,
constructor: function(inCell)
{
this.inherited(arguments);
this.widget = new dijit.form.Button;
},
setValue: function(inRowIndex, inValue){
if (this.widget) {
this.widget.attr('value', inValue);
}
else {
this.inherited(arguments);
}
}
});
dojox.grid.cells.Button.markupFactory = function(node, cell)
{
dojox.grid.cells._Widget.markupFactory(node, cell);
}

For 1) The button is only shown when I double click the grid.
Set singleClickEdit: true in the Grid parameters
this.grid = new dojox.grid.DataGrid({
singleClickEdit: true,
structure: view1,
}, tmp);

Related

Dojo ListItem with Child Inputs

I have a dojo list item that is clickable.. But at the same time we like to put input elements inside the list item. The problem is that if you click on the child element(example checkbox) the listitem onclick intercepts the call first(which seems opposite of the html bubble up format). So we cannot call stoppropagation on the child element to stop the listitem from changing the page.
In the example below you will see the listitem alert come up before the checkbox alert..
How do you handle having input elements in a listitem without triggering the listitem..
fiddle::http://jsfiddle.net/theinnkeeper/HFA36/1/
ex.
var list1 = registry.byId("myList");
var item = new ListItem ({
label: "A \"programmatic\" ListItem",
moveTo: "#",
noArrow:true,
onClick : function() {
alert("listItem clicked !" + event.target.type);
}
});
list1.addChild(item);
var check = new cb({onClick:function(){alert("checkbox clicked");event.stopPropagation();}});
check.placeAt(item.containerNode.firstChild);
check.startup();
I had a similar problem a while back and noticed that the dojox/mobile/ListItem is not really great when adding extra event handlers to it (checkboxes, touch gestures, ...), so to solve that I usually extend dojox/mobile/ListItem and fix the events by myself.
For example:
var CheckedListItem = declare("dojox/mobile/CheckedListItem", [ ListItem ], {
_initializeCheckbox: function() {
this.checkbox = new CheckBox({
});
domConstruct.place(this.checkbox.domNode, this.containerNode.firstChild, "last");
this.checkbox.startup();
this.checkbox.onClick = this.onCheckboxClick;
},
onCheckboxClick: function() { },
_setOnCheckboxClickAttr: function(handler) {
this.onCheckboxClick = handler;
if (this.checkbox !== null && this.checkbox !== undefined) {
this.checkbox.onClick = handler;
}
},
_onClick: function(e) {
if (e.target !== this.checkbox.domNode) {
this.inherited(arguments);
}
},
postCreate: function() {
this.inherited(arguments);
this._initializeCheckbox();
}
});
Due to overriding _onClick() and adding additional checks I managed to get the intended behavior.
A full example can be found here: http://jsfiddle.net/LQ6Mb/

dojo How to dynamically change the title of the tab in tabContainer?

If I have made to the tab through the dojo,
mycode
var tab=new dijit.layout.ContentPane({
title:formCount,
id:''+formCount,
content:cont,
class:'tab',
closable: true,
onClose:function(){
return confirm('Relly want to remove?');
}
});
dijit.byId('tabContainer').addChild(tab);
After the tab is created, i want to change the tab title dynamically through dijit/Dialog.
but I don't know how it should be implemented,Please advise me
The best way to achieve this is to create your own widget and extend from dijit/layout/ContentPane, for example:
declare([ ContentPane ], {
});
Then you can add stuff to show a dialog, for example:
declare([ ContentPane ], {
btn: domConstruct.create("button", {
innerHTML: "Change title",
}),
_createButton: function() {
domConstruct.place(this.btn, this.domNode);
on(this.btn, "click", lang.hitch(this, this._showDialog));
},
postCreate: function() {
this.inherited(arguments);
this._createButton();
this._createDialog();
}
});
The postCreate function is a part of the widget lifecycle in Dojo and is automatically executed when the widget is loaded. So, we use that to add a "Change title" button to the contentpane that, when being clicked calls a function this._showDialog() (that's what you can see in this._createButton()).
Of course, you also need to create a dijit/Dialog before you can actuall show one, so you could do something like:
declare([ ContentPane ], {
/** ... */
dialog: null,
editField: null,
okBtn: null,
_showDialog: function() {
this.editField.value = this.title;
this.dialog.show();
},
_createDialog: function() {
var div = domConstruct.create("div");
domConstruct.place(div, this.domNode);
this.dialog = new Dialog({
title: "Change title",
content: ""
}, div);
this.editField = domConstruct.create("input", {
type: "text"
});
this.okBtn = domConstruct.create("button", {
innerHTML: "OK"
});
domConstruct.place(this.editField, this.dialog.containerNode);
domConstruct.place(this.okBtn, this.dialog.containerNode);
on(this.okBtn, "click", lang.hitch(this, this._saveTitle));
},
/** .. */
});
What happens here is that we create a dialog with a simple textfield and a button (the OK button), all of that can be found in this._createDialog().
In this._showDialog() you can see that I'm first changing the value of the textfield into the title of the contentpane. Then I show the dialog we made earlier.
Now all you have to do is read that value when the OK button is pressed:
declare([ ContentPane ], {
/** ... */
_saveTitle: function() {
this.set("title", this.editField.value);
this.dialog.hide();
},
/** ... */
});
That's all you really need. You can find a working example on JSFiddle: http://jsfiddle.net/LE49K/

Sencha Touch2: Passing data from Controller to floating Panel not working

I am new to Sencha Touch2 and facing problem while passing data from my Controller to Floating panel on listitem tap. Here is my controller implementation code:
Ext.define('CustomList.controller.Main', {
extend: 'Ext.app.Controller',
requires:['CustomList.view.DatePanel'],
config: {
refs: {
listView: 'listitems'
},
control: {
'main test2 list': {
activate: 'onActivate',
itemtap: 'onItemTap'
}
}
},
onActivate: function() {
console.log('Main container is active');
},
onItemTap: function(view, index, target, record, event) {
console.log('Item was tapped on the Data View');
Ext.Viewport.add({
xtype: 'DatePanel'
});
}
});
Am able to get data in the controller and DatePanel.js is my floating Panel.
DatePanel.js:
Ext.define('CustomList.view.DatePanel', {
extend: 'Ext.Panel',
alias: 'widget.DatePanel',
xtype:'datepanel',
config: {
itemid:'DatePanel',
modal:true,
centered: true,
hideOnMaskTap:true,
width:'500px',
height:'650px',
items:[
{
styleHtmlCls:'homepage',
tpl:'<h4>{name3}</h4>'
},
{
xtype:'toolbar',
docked:'bottom',
items:[{
text:'OK',
ui:'confirm',
action:'ShowTurnOverReport',
listeners : {
tap : function() {
console.log('Ok');
}
}
},
{
text:'Cancel',
ui:'confirm',
action:'Cancel',
listeners : {
tap : function() {
console.log('Cancel');
var panelToDestroy = Ext.getCmp('datepanel');
panelToDestroy.destroy();
Ext.Viewport.add(Ext.create('CustomList.view.Test2'));//Test.js is my list Panel
}
}
}]
}
]
}
});
Help me out in destroying the panel on 'Cancel' Button.
Can anyone please help me. Thanks.
Create instance of panel you want to add first.
var floatingDatePanel = Ext.create('Yourapp.view.YourDatePanel');
Next get data of selected list item on itemTap
var data = record.getData();
Assign this data to floatingDatePanel with setData() method
UPDATE,
after looking at your panel code, I guess you want to set data to first item in panel ie
{
styleHtmlCls:'homepage',
tpl:'<h4>{name3}</h4>'
}
Right ? If so then you need to change following code
floatingDatePanel.setData(data);
to
floatingDatePanel.getAt(0).setData(data);
Because, it is first item inside panel that is having a template assigned and hopefully the same where you want to set data.
then finally, you can add this panel into viewport with
Ext.Viewport.add(floatingDatePanel);

Add a custom button in column header dropdown menus {EXTJS 4}

I want a button in column header dropdown menu of grid in extjs4.
so that i can add or delete columns which are linked in database.
Any help will be appreciated...
Thankyou..:)
Couple of months ago I had the same problem. I've managed to solve it by extending Ext.grid.header.Container (I've overrided getMenuItems method). However, recently, I've found another solution which requires less coding: just add menu item manualy after grid widget is created.
I'll post the second solution here:
Ext.create('Ext.grid.Panel', {
// ...
listeners: {
afterrender: function() {
var menu = this.headerCt.getMenu();
menu.add([{
text: 'Custom Item',
handler: function() {
var columnDataIndex = menu.activeHeader.dataIndex;
alert('custom item for column "'+columnDataIndex+'" was pressed');
}
}]);
}
}
});
Here is demo.​
UPDATE
Here is demo for ExtJs4.1.
From what I have been seeing, you should avoid the afterrender event.
Context:
The application I am building uses a store with a dynamic model. I want my grid to have a customizable model that is fetched from the server (So I can have customizable columns for my customizable grid).
Since the header wasn't available to be modified (since the store gets reloaded and destroys the existing menu that I modified - using the example above). An alternate solution that has the same effect can be executed as such:
Ext.create('Ext.grid.Panel', {
// ...
initComponent: function () {
// renders the header and header menu
this.callParent(arguments);
// now you have access to the header - set an event on the header itself
this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
this.createHeaderMenu(menu);
}, this);
},
createHeaderMenu: function (menu) {
menu.removeAll();
menu.add([
// { custom item here }
// { custom item here }
// { custom item here }
// { custom item here }
]);
}
});
For people who would like to have not just one "standard" column menu but have an individual columnwise like me, may use the following
initComponent: function ()
{
// renders the header and header menu
this.callParent(arguments);
// now you have access to the header - set an event on the header itself
this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
menu.on('beforeshow', this.showHeaderMenu);
}, this);
},
showHeaderMenu: function (menu, eOpts)
{
//define array to store added compoents in
if(this.myAddedComponents === undefined)
{
this.myAddedComponents = new Array();
}
var columnDataIndex = menu.activeHeader.dataIndex,
customMenuComponents = this.myAddedComponents.length;
//remove components if any added
if(customMenuComponents > 0)
{
for(var i = 0; i < customMenuComponents; i++)
{
menu.remove(this.myAddedComponents[i][0].getItemId());
}
this.myAddedComponents.splice(0, customMenuComponents);
}
//add components by column index
switch(columnDataIndex)
{
case 'xyz': this.myAddedComponents.push(menu.add([{
text: 'Custom Item'}]));
break;
}
}
I took #nobbler's answer an created a plugin for this:
Ext.define('Ext.grid.CustomGridColumnMenu', {
extend: 'Ext.AbstractPlugin',
init: function (component) {
var me = this;
me.customMenuItemsCache = [];
component.headerCt.on('menucreate', function (cmp, menu) {
menu.on('beforeshow', me.showHeaderMenu, me);
}, me);
},
showHeaderMenu: function (menu) {
var me = this;
me.removeCustomMenuItems(menu);
me.addCustomMenuitems(menu);
},
removeCustomMenuItems: function (menu) {
var me = this,
menuItem;
while (menuItem = me.customMenuItemsCache.pop()) {
menu.remove(menuItem.getItemId(), false);
}
},
addCustomMenuitems: function (menu) {
var me = this,
renderedItems;
var menuItems = menu.activeHeader.customMenu || [];
if (menuItems.length > 0) {
if (menu.activeHeader.renderedCustomMenuItems === undefined) {
renderedItems = menu.add(menuItems);
menu.activeHeader.renderedCustomMenuItems = renderedItems;
} else {
renderedItems = menu.activeHeader.renderedCustomMenuItems;
menu.add(renderedItems);
}
Ext.each(renderedItems, function (renderedMenuItem) {
me.customMenuItemsCache.push(renderedMenuItem);
});
}
}
});
This is the way you use it (customMenu in the column config let you define your menu):
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
plugins: ['Ext.grid.CustomGridColumnMenu'],
columns: [
{
dataIndex: 'name',
customMenu: [
{
text: 'My menu item',
menu: [
{
text: 'My submenu item'
}
]
}
]
}
]
});
The way this plugin works also solves an issue, that the other implementations ran into. Since the custom menu items are created only once for each column (caching of the already rendered version) it will not forget if it was checked before or not.

Constrain position of Dojo FloatingPane

I have a dojox.layout.FloatingPane (as a custom dijit) which can be positioned anywhere within its enclosing div. My problem is that the user can potentially drag the FloatingPane completely outside of its container and be unable to retrieve it. Is there any easy way to force the FloatingPane to remain entirely visible at all times?
Here's my code:
dojo.provide("ne.trim.dijits.SearchDialog");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dojox.layout.FloatingPane");
dojo.declare("ne.trim.dijits.SearchDialog", [dijit._Widget, dijit._Templated], {
templateString: dojo.cache("ne.trim.dijits", "templates/SearchDialog.html"),
initialised:false,
floatingPane: null,
postCreate: function() {
this.init();
},
init: function() {
console.debug("SearchDialog.init()", "start");
if ( this.initialised === false ) {
this.createSearchDialog();
}
//ne.trim.AppGlobals.searchDialog = this;
console.debug("SearchDialog.init()", "end");
},
createSearchDialog: function() {
var node = dojo.byId('searchbox');
floatingPane = new dojox.layout.FloatingPane({
title: "A floating pane",
resizable: true, dockable: true, constrainToContainer: true,
style: "position:absolute;top:100;right:100;width:400px;height:300px;z-index:100",
}, node );
this.initialised=true;
floatingPane.startup();
}
});
First of all, see the working example at jsFiddle: http://jsfiddle.net/phusick/3vTXW/
And now some explanation;) The DnD functionality of FloatingPane is achieved via dojo.dnd.Moveable class instantialized in pane's postCreate method. To constrain the movement of the FloatingPane you should use one of these moveables instead:
dojo.dnd.parentConstainedMoveable - to constrain by a DOM node
dojo.dnd.boxConstrainedMoveable - to constrain by co-ordinates: {l: 10, t: 10, w: 100, h: 100}
dojo.dnd.constrainedMoveable - to constrain by co-ordinates calculated in a provided function
For more details see aforementioned jsFiddle.
According to documentation you should call destroy() on Moveable instance to remove it, but as FloatingPane's original Moveable is not assigned to any object property, I do not destroy it, I just instantiate one of those three moveables on the same DOM node in a subclass:
var ConstrainedFloatingPane = dojo.declare(dojox.layout.FloatingPane, {
postCreate: function() {
this.inherited(arguments);
this.moveable = new dojo.dnd.move.constrainedMoveable(this.domNode, {
handle: this.focusNode,
constraints: function() {
return dojo.coords(dojo.body());
}
});
}
});
Now you can use ConstainedFloatingPane instead of dojox.layout.FloatingPane:
var floatingPane = new ConstrainedFloatingPane({
title: "A Constrained Floating Pane",
resizable: true
}, searchboxNode);