I have a ui-grid bound to an object array called data like this:
$scope.grd = {
enableRowSelection: true,
multiSelect: true,
enableRowHeaderSelection: false,
columnDefs: [
{ field: 'id', name: 'ID' },
{ field: 'name', name: 'Name' },
{ field: 'tags', name: 'Tags' }
],
data: "data"
};
if I now replace an item in the array like this:
$scope.data[i] = replacementData;
the grid is updated correctly but the selection state is lost.
I guess the selection module simple doesn't support this though the core module does.
Is there a way to get the selection state of an item before replacing it?
I found this GridRow class in the docs of the selection module that has an isSelected property but no ideas how to get it...
Here is a Plunk that demonstrates the behavior - notice that the selectionCount is also wrong after the row is replaced, so there must be some kind of selected item info somewhere.
Update: It seems that replacing an item in the bound array doesn't remove the GridRow that ui-grid uses internally (that also is the reason why the selectedCount is wrong). Calling unSelectRow before replacing the item fixes the count but the GridRowstill exists...
Ended up copying all the properties from the replacementData over the old data object. That way the selection state is kept, and no new GridRow get's created.
Updated Plunk
angular.extend($scope.data[i], replacementData);
This is how I set up my selection model for my grid :
var selM = Ext.create('Ext.selection.Model', {
mode: 'SINGLE',
toggleOnClick: true,
allowDeselect:true
});
And then in my table I add this as a configuration paramater :
var packageGrid = Ext.create('js.grid.MyGrid', {
selModel: selM
});
The MULTI selection is disabled, which is great. However now nothing remains selected. If I click on a row the highlighting disappears as soon as I move the mouse away.
This could be an extjs bug. I have tried the other parameter 'SIMPLE' as well.
Here is a fiddle which shows my problem :
http://jsfiddle.net/fgkb8yw5/1/
RowModel is the default so you can simply use:
selModel: {
mode: 'SINGLE'
}
Example: http://jsfiddle.net/8mra2het/1/
It's not a bug, Ext.selection.Model is the abstract class - which shouldn't be instantiated directly. Normally - when you specify the selModel declaratively, the grid component will implement one of the grid-context appropriate sub-classes:
Ext.selection.CellModel
Ext.selection.RowModel
I updated your fiddle using RowModel to demonstrate.
First of all, I am using Extjs 4.1.
I have a grid with property grid and I want to add a column of checkbox into the grid. The property grid code is as follows:
var grid = Ext.create('Ext.grid.property.Grid', {
tbars:[],
selModel: Ext.create('Ext.selection.CheckboxModel',{mode: 'MULTI'}),
columnLines: true,
renderTo: Ext.getBody(),
source: {
"grouping": false,
"autoFitColumns": true,
"productionQuality": false,
"created": Ext.Date.parse('10/15/2006', 'm/d/Y'),
}
});
However the checkbox selection model does not show up in the grid.
anyone can point me to the correct direction or property grid does not work with checkbox ?
Although the selModel property is documented in Ext.grid.property.Grid, this is only because Ext.grid.property.Grid extends Ext.grid.Panel. The problem is that this type of grid only has a fixed selModel and namely of type cellmodel. You can see its behaviour by clicking on a property (the property editor gets the focus and e.g a date proeprty shows a date picker). The cellmodel selModel is hard coded in the source code in the initComponent() method, so if you want to change that, you should write your own subclass in which you overwrite that.
My question is similar to http://www.sencha.com/forum/showthread.php?2916-insert-update-delete-child-nodes-dynamically
only difference being that I am using Ext.Tree. I split main page into two portions.
I kept left portion for displaying data in tree structure and right portion for some displaying some details in the screen.
Currently there are some child nodes are under root node (Source). When one of child clicked, I populate some data in the right portion of screen.
Can anyone explain me to how update (insert/update/delete) child nodes dynamically when i add or delete data on right part of screen which is a grid.
Ext.onReady(function() {
var Tree = Ext.tree;
var tree = new Tree.TreePanel({
useArrows: true,
autoScroll: true,
animate: true,
enableDD: true,
containerScroll: true,
border: false,
// auto create TreeLoader
dataUrl:'[JS Array]',
root: {
nodeType: 'async',
text: 'ALL',
draggable: false,
id: ''
}
});
// render the tree
tree.render('tree-div');
tree.getRootNode().expand();
});
You should look at the TreeNode class. It has methods addChild() and getPath() and removeChild that can be used to remove nodes and leaves from your treee.
EDIT: The original answer is for a deprecated version
Current Documentation Link: http://docs.sencha.com/extjs/6.2.1/classic/Ext.data.TreeStore.html#methods
Current "classic" ext appears to have unified the datasources to use something closer to a traditional data store called a TreeStore which should allow you to manipulate the tree's leaves and branches.
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());
;)