Am trying to move nodes in a Tree panel in EXTJS 4. The locations of these nodes are stored in a SQL database. What should happen when i move the nodes is that, the id's of those nodes should get changed in the database, depending on the location on the tree. Till now, i have managed to get only the id of the parent node, and not the actual node itself. I dont understand why this is happening. Each time i move a node,its returning me the id of the parent node. Code is as follows:
function buildTree() {
consoleWrite('BUILD THE TREE!!!');
var tree = Ext.create('Ext.tree.Panel', {
title : '',
border : false,
height : SYSTEM.panelHeight,
viewConfig : {
listeners : {
},
enableDD : true,
plugins : {
ptype : 'treeviewdragdrop'
}
},
collapsible : false,
useArrows : true,
rootVisible : false,
store : TREEst,
multiSelect : false,
singleExpand : true,
id : 'PAGETREE',
listeners : {
afterRender : function() {
MASK.tree.hide();
},
itemmove : {
fn : function(v, node, oldParent, newParent, index) {
var nodeID = node.data.id;
alert(nodeID);
}
}
This nodeID is printing the id of the parent node, as its stored in the database, and not the actual node itself. If anyone could provide me with guidance on how to proceed, that would be really great. Thanks in advance.
I don't think your itemmove params signature is correct. The API docs for 4.1 say:
itemmove( Ext.data.NodeInterface this, Ext.data.NodeInterface oldParent, Ext.data.NodeInterface newParent, Number index, Object eOpts )
So your node is actually referring to oldParent.
Related
I am creating new ExtJs tabpanels and rendering panels inside it programmatically.
The panels (rendered inside tabs) are all written in separate JS files.
Opening, rendering and closing of the tabs is working completely fine.
But when I debug the code I see that the previous components of the closed tabs are still active in the memory. As a result of which the functioning of the components gets affected when the tab is reopened.
I want to destroy all the components inside the tab panels (if ExtJs, for some reasons, is not able to do it).
How can I do this?
Below is a sample code which I am trying:
Main Tab:
var tabs = new Ext.TabPanel({
id : 'screensTabPanel',
layout : 'fit',
enableTabScroll : true,
height : Ext.getBody().getStyleSize().height - 60,
activeTab : 0,
//enableTabScroll : true,
autoScroll : true,
autoRender : true,
border : false,
plugins : [ {
ptype : 'tabscrollermenu',
maxText : 30,
pageSize : 5
} ]
});
Dynamic Tab object:
var tabConfig = {
title : text,
bodyPadding : 3,
closeAction:'destroy',
autoScroll : true,
id : 'tab' + id,
closable : closable,
loader : {
loadMask : 'loading...',
autoLoad : true,
url : url,
scripts : true,
params : {
userId : 1
},
border : false,
appId : appIdx,
screenId : screenId,
gridType : gridType,
listeners : {
beforeclose : function(tab) {
debugger;
tab.removeAll(); //I tried doing this
tab.destroy(); //I tried doing this as well
return true;
}
}
};
Internal Panel code:
Ext.define('Ext.ux.window.VisualSQLQueryBuilder', {
extend: 'Ext.panel.Panel',
itemId: 'qb-VisualSQLQueryBuilderId',
renderTo: Ext.Element.get('divQueryBuilder'),
layout: {
type: 'border'
},
listeners:{
beforerender: function(thisa, eOpts ){
debugger;
/*if(Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId").length > 1){
Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId")[0].destroy();
}*/
Tab.MainTab = Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId")[Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId").length - 1];
}
},
items: [ .... screen components ... ]
});
Add Panel object to tab:
addedTab = ExtCont.add(tabConfig);
addedTab.show();
ExtCont.setActiveTab(addedTab);
Now this is what happens:
Open Tab (Name - Query Builder)
Code reaches the beforerender listener.
Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId") has only one object inside it.
Everything works fine.
Now the problem starts
Close the tab
Code reaches beforeclose listener. Trying tab.removeAll() and tab.destroy()
Reopen tab - Query Builder
Code reaches beforerender listener.
Now Ext.ComponentQuery.query("#qb-VisualSQLQueryBuilderId") has two objects inside it. So it is retaining the object of the tab opened first time. And the second one is that of the tab opened just now.
How do I ensure whenever a tab is closed all its components get smoothly destroyed?
from TabPanel:
Note: By default, a tab's close tool destroys the child tab Component and all its descendants. This makes the child tab Component, and all its descendants unusable. To enable re-use of a tab, configure the TabPanel with autoDestroy: false.
so it could really be an ExtJS Bug cause autoDestroy: true is default. maybe you could open a ticket.
This is my code -
var myTree = {
containerScroll: "true",
width: 500,
root: new Ext.tree.AsyncTreeNode({
id: "source",
text: "Root",
expanded: true,
draggable: true,
expandable: true
}),
loader: new Ext.tree.TreeLoader({
dataUrl: 'page.php?action=Get_Tree',
preloadChildren: true,
expandAll: function () {}
}),
xtype: "treepanel",
loadMask: {
msg: 'Loading...'
},
maskDisabled: false,
id: "tree",
listeners: {
click: function (node, event) {
// Render entity data in right panel
handleAction(node);
}
}
}
when user clicks on any node of Tree, I fetch the data from DB and rendering the another panel using handleAction method. In my case, I need to show node's info in another panel and update it. On update handler, I need to change node's text/id as its updated now.
This works fine but then I need to refresh the tree so that, I can view updated node. But, it doesn't work for me :(.
This is my code for updating node -
var tree = Ext.getCmp('tree');
var id = req.responseText.split('#')[1];
var myId = 'Spec#' + entityId;
var node = tree.getNodeById(myId);
node.id = 'Spec#' + id;
node.text = updated_spec_id;
tree.enable();
tree.getLoader().dataUrl = 'page.php?todo=Get_Tree';
tree.getLoader().load(tree.root);
// This I have tried but not succeed.
tree.getView().refresh();
tree.expandAll();
node.expand();
tree.getRootNode().expand(true);
However, when I manually expand it using mouse click, node is updated.
Please help. Thanks in advance.
Have you tried doLayout function? Excerpt from doc:
If the Container is already rendered when add is called, you may need to call doLayout to refresh the view which causes any unrendered child Components to be rendered. This is required so that you can add multiple child components if needed while only refreshing the layout once.
It seems to me, your tree doing normal behaviour. Because, you had used click event, therefore this event fire when you click the node.
Am working on moving nodes in a tree, and as they are moved, their ID's are updated in the database through C# in the back-end. Till now, i have managed to update the position of the node that is being moved, but after its moved, the position of the other nodes in the tree should also get updated. Could anyone tell me how to proceed with this?
itemmove : {
fn : function(v, oldParent, newParent, index, eOpts) {
var nodeID = v.data.id;
var oldParent = oldParent.data.id;
var newParent = newParent.data.id;
var index = index;
var level = v.data.level;
movenode(nodeID, oldParent, newParent, index, level);
}
}
function movenode(nodeID, oldParent, newParent, index, level) {
Ext.Ajax.request({
url : 'data/pages.aspx',
params : {
UserID : USER.UserID,
mode : 'MOVENODE',
currentNode : nodeID,
oldParentNode : oldParent,
newParentNode : newParent,
index : index,
level : level,
ProjDB : projDB
},
success : function() {
loadTREEst();
genMessage(LANG.Suc, LANG.SaveOK, 'tick', false);
},
failure : function() {
genMessage(LANG.Warn, LANG.GenWarn, 'warn', false);
}
});
}
So, i send the parameters to SQl, and then update the index of the node that has been moved.
For example, if i move a node from position 8 to 1, the index of the 8th node changes to 1 in the database, but the index of the first node remains at 1. And because of this, the tree also doesnt get updated. i want all the other nodes in the tree to get updated as well. So, in this case, the node in index 1 will become index 2, the node in index 2 will become index 3, and so on. Can anyone explain me how to do this.
Is there any other method other than autosync or sync to do this?
Thanks in advance.
Here is some sample code that works with 4.1:
Ext.define('BS.model.ItemCategory', {
extend: 'Ext.data.Model',
fields: [
{name: 'name' , type: 'string'},
{name: 'iconCls' , type: 'string', defaultValue: 'treenode-no-icon'},
{name: 'leaf' , type: 'boolean', defaultValue: false},
{name: 'expanded' , type: 'boolean', defaultValue: true, persist: false},
{name: 'index' , type: 'int'},
],
proxy: {
type: 'direct',
api: {
create: ItemCategories.Create,
read: ItemCategories.Read,
update: ItemCategories.Update,
destroy: ItemCategories.Delete,
},
},
});
You won't be having a direct proxy as your server isn't php, but just put the corresponding server scripts (see docs).
Then my store:
Ext.define('BS.store.ItemCategories', {
extend: 'Ext.data.TreeStore',
model: 'BS.model.ItemCategory',
autoSync: true,
root: {
text: 'Root',
id: 'NULL',
expanded: true
},
clearOnLoad: true,
});
And the view:
Ext.define('BS.view.admin.pages.item-categories.ItemCategories' ,
{
extend: 'Ext.tree.Panel',
alias : 'widget.item-categories-tree',
store: 'ItemCategories',
displayField: 'name',
rootVisible: false,
useArrows: true,
multiSelect: false,
singleExpand: false,
allowDeselect: true,
plugins: {
ptype: 'treeviewdragdrop',
},
});
That's pretty much it! When you move a node you'll see ExtJS sends an update request to the server with an array of all the nodes whose index (sort) has changed.
This is the code I had for 4.0.7, to my memory it solved this problem.
// This happens after drag and drop
onItemMove: function(aNode, aOldParent, aNewParent, aIndex, aOptions)
{
// Update the indeces of all the parent children (not just the one that moved)
for ( i = 0; i < aNewParent.childNodes.length; i++ )
{
aNewParent.childNodes[i].data.sort = i;
aNewParent.childNodes[i].setDirty();
}
this.mStore.sync();
},
Notice that you won't have mStore.sync() as you are sending your own request to the server, which only involves one record. By setting child nodes as dirty, sync sends more than one record to the server's update call (in my case, I'm using autosync and direct).
You should consider what happens when the user moves a node from a parent node to the parent's sibling - the index (sort) of some nodes in both the old and new parent will change. So you might end up with 6 records that need updating on the server.
All I'm saying is that given 4.1 already handles node moving correctly, you might be better off upgrading to 4.1 and take advantage of the native support for this than coding it yourself. If you stick to 4.0.7, just remember to consider that a moving a node could require the updating of many nodes.
I am new to Ext-JS4. I am working on a project in which I am configuring a toolbar. I have added few buttons to the toolbar, one of which has a menu and the menu basically has a grid which is loaded from a JSON store. The grid is used within the menu due to such requirement in the project. The grid is loaded properly but I need access to the menu item being clicked within the menu. I want the text of the menu item which is clicked. The following code will better explain my question.
var store = Ext.create('Ext.data.Store', {
storeId : 'favStore',
model : favModel,
autoLoad : true,
groupField : 'group_header',
proxy : {
type : 'ajax',
url : '../../data/favorites.json',
reader : {
type : 'json',
root : 'favoritesMenu'
}
}
});
var favGrid = Ext.create('Ext.grid.Panel', {
store : store,
columns : [{
dataIndex : 'listItem',
width : 200
}],
features : [groupingFeature],
width : 200,
height : 275,
autoHeight : true,
border : false
});
var favMenu = Ext.create('Ext.menu.Menu', {
items : [favGrid],
listeners : {
'click' : function(store,item) {
alert('Item clicked= ');//tried item.text here but not working
}
}
});
In the alert method on the click event I want the text of the menu item clicked. I hope I am clear with the question. Can anyone give me some suggestions? Also can anyone suggest me some good blogs on Ext-JS4?
All these things are defined within the initComponent method of Ext.define() for toolbar.
You can use the documentation.
For me it was very usefull:
http://docs.sencha.com/ext-js/4-0/
I believe in your case you want the listener to be attributed to your grid, not the menu. Something like...
var favGrid = Ext.create('Ext.grid.Panel', {
store : store,
columns : [{
dataIndex : 'listItem',
width : 200
}],
features : [groupingFeature],
width : 200,
height : 275,
autoHeight : true,
border : false,
listeners: {
'itemclick': function(view, record, item, index, e, eOpts){
//Assuming 'name' is a fieldname in the record
alert('item clicked = ' + record.get('name'));
}
}
});
Check out the Ext.grid.Panel documentation here: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.Panel . Click on "events" at the top and find "itemclick".
or you can have your menu listen to the grid's event by relaying the events.
favMenu.relayEvents(favGrid, ['itemclick']);
favMenu.on('itemclick', me.onFavFunction, me);
How can I use Ext.tree.ViewDDPlugin's events?
I have a TreePanel that uses DDPplugin, but I'd like to know how to listen to the drop event.
This is what my code looks like:
var monPretree = Ext.create('Ext.tree.Panel',{
id : 'treepanel',
title : 'TITRE',
//width : 800,
//height : 600,
width : 500,
enableDD: true,
useArrows : true,
viewConfig : {
plugins : {
ptype: 'treeviewdragdrop',
appendOnly: true,
listeners: {
drop: function (node, data, overModel, dropPosition) {
alert('CHANGE');
},
notifyDrop: function (dragSource, event, data) {
var nodeId = data.node.id;
alert(nodeId);
},
notifyOver: function (dragSource, event, data) {
alert('over');
}
}
}
},
singleExpand : false,
store : monPrestore,
rootVisible : false,
I would like to fire drop events for example, but my code doesn't work
Thanks :)
I've got same question and found this page.
There is note in documentation, in event section:
"This event is fired through the TreeView. Add listeners to the TreeView object"
I've tryed to found method in tree.Panel class to get view, unsuccessfully. So, all you need to do, just put listners block in configuration to viewConfig section (not in plugin section):
viewConfig : {
plugins : {
ptype: 'treeviewdragdrop',
...
},
listeners: {
drop: function (node, data, overModel, dropPosition) {
alert('CHANGE');
},
}
}
},
http://docs.sencha.com/ext-js/4-0/#!/api/Ext.tree.plugin.TreeViewDragDrop-event-drop
Take a look at the doc :
beforeinsert( Tree tree, Node parent, Node node, Node refNode, Object options )
Fires before a new child is inserted in a node in this tree, return false to cancel the insert. ...
As an addition to Anton's correct answer above: The code below shows how to "connect from the outside" to drop events, for example from a Controller etc:
// Drag & Drop on the TreePanel
var ganttTreeView = ganttTreePanel.getView();
ganttTreeView.on({
'drop': me.onDrop,
'scope': this
});;
You can also catch the drop event by overriding dropConfig inside a TreeGrid or TreePanel. Here is an example how I did.
var myTree = new Tree.TreePanel({
id: 'treepanel',
title: 'My Title',
enableDD: true,
ddGroup: 'GridDD',
dataUrl: 'yourMethodURLForJSONData',
dropConfig: {
dropAllowed: true,
ddGroup: "GridDD",
notifyDrop: function(source, e, data) {
alert("A node/leaf is dropped");
//If you want few more details
if (data.grid) {
var node = data.selections[0].data;
alert("This is a node dropped from a Grid.");
} else {
var node = data["node"];
alert("This is a node dropped from a Tree.");
}
}
}
});
You can also do the same for Ext.ux.tree.TreeGrid. Hope It will help.