ExtJs 3 TreePanel Sorting not working - sorting

I am using Ext.ux.tree.TreeGrid for tree grid panel. All is working fine except sort.
I have 3 level of hierarchy in it like - parent - child - grand child. I want to make sorting based on text of parent only. But I am getting random result every time. :(
This is my code -
var tree_grid = new Ext.ux.tree.TreeGrid({
title : 'Requirements',
height : 415,
enableDD : true,
enableHdMenu : true,
id : 'req_tree',
columns : [ {
header : 'Entity',
dataIndex : 'text',
width : 200,
sortable: true,
sortType : 'asText'
}, {
header : 'Text',
width : 50,
dataIndex : 'temp',
align : 'center',
// sortType : 'asFloat',
sortable: false
}],
dataUrl : 'my_page.php'
});
For sorting I have tried this -
1) var myTreeSorter = new Ext.tree.TreeSorter(tree_grid, {});
myTreeSorter.doSort(tree_grid.getRootNode());
2) new Ext.ux.tree.TreeGridSorter(tree_grid, {
folderSort: true,
dir: "desc",
sortType: function(node) {
// sort by a custom, typed attribute:
return parseInt(node.id, 10);
}
});
3) Used Attributes like - sortType, sortable, sortInfo.
None of the above helped me however. Please help.

var mySortStore = Ext.create("Ext.data.Store", {
model: "MyTreeStore",
data: []
});
Then when you go to add the node to the tree, use this function instead:
function addNodeSorted(node, childToBeAdded){
//clear the store from previous additions
mySortStore.removeAll();
//remove old sorters if they are dynamically changing
mySortStore.sort();
//add the node into the tree
node.appendChild(childToBeAdded);
var cn = node.childNodes,
n;
//remove all nodes from their parent and add them to the store
while ((n = cn[0])) {
mySortStore.add(node.removeChild(n));
}
//then sort the store like you would normally do in extjs, what kind of sorting you want is up to you
mySortStore.sort('height', 'ASC');//this is just an example
//now add them back into the tree in correct order
mySortStore.each(function(record){
node.appendChild(record);
});
}

Did you tried to use the config folderSort on the store:
TreeGrid Example: sencha TreeGrid
var store = Ext.create('Ext.data.TreeStore', {
model: 'Task',
proxy: {
type: 'ajax',
//the store will get the content from the .json file
url: 'treegrid.json'
},
**folderSort: true**
});
--
Other solution, can be used a sort filter on the store:
Store Sort: sencha sort
//sort by a single field
myStore.sort('myField', 'DESC');
//sorting by multiple fields
myStore.sort([
{
property : 'age',
direction: 'ASC'
},
{
property : 'name',
direction: 'DESC'
}
]);

Related

ExtJS4 dataView - Select node id

I have an ExtJS 4 dataView and i would like to catch the id of a selected node.
It is the first time that i'm using the dataView, then, there are some troubles.
The store is loaded correctly and i see the datas into the view very well. The problem which i'm having, concern the "classic" actions of update and delete, particularly getting the id of a selected item.
For example into a grid i click, then select a record and through a button's pressing i open a window (or other actions) with a loaded form (by sending in AJAX to the store, the id of the selected row) and i update the datas.
I'm not still able to do it with the ExtJS 4 dataView.
Below my dataView:
dataView_player = Ext.create('Ext.Panel', {
id: 'images-view',
frame: true,
collapsible: false,
autoWidth: true,
title: 'Giocatori (0 items selected)',
items: [ Ext.create('Ext.view.View', {
id:'players-view',
store: store_player,
multiSelect: true,
height: 310,
trackOver: true,
overItemCls: 'x-item-over',
itemSelector: 'div.thumb-wrap',
emptyText: 'Nessun giocatore visualizzato',
tpl: [
'<tpl for=".">',
'<div class="thumb-wrap" id="{id}-{name}">',
'<div class="thumb">',
'<img src="/img/players/{picture}" title="{name} {surname}" alt="{name} {surname}" style="">',
'</div>',
'<span class="" style="height:30px;">{general_description}{name} {surname}</span>',
'</div>',
'</tpl>',
'<div class="x-clear"></div>'
],
plugins: [
Ext.create('Ext.ux.DataView.DragSelector', {}),
Ext.create('Ext.ux.DataView.LabelEditor', {dataIndex: 'name'})
],
prepareData: function(data) {
Ext.apply(data, {
name: data.name,
surname: data.surname,
general_description: Ext.util.Format.ellipsis(data.general_description, 15)
});
return data;
},
listeners: {
'selectionchange': function(record, item, index, e) {
var node = this.getNode(record); //this.getNode(record);
console.log(node.get('id'));
}
}
}) ],
dockedItems: [{
xtype: 'toolbar',
items: [{
iconCls: 'delete',
text: 'Cancella Selezionati',
scale: 'medium',
tooltip: 'Per <b>cancellare</b> i giocatori selezionati',
tooltipType: 'qtip',
id: 'delete-player',
disabled: true,
handler: delete_news
}, '-', {
iconCls: 'edit',
text: 'Aggiorna Selezionata',
scale: 'medium',
tooltip: 'Per <b>aggiornare</b> un giocatore selezionato',
tooltipType: 'qtip',
disabled: false,
id: 'update-player',
handler: function(nodes) {
var l = nodes.get('id');
console.log(l);
}
}
}
]
}]
});
Of course, this is a wrong example (because the listeners don't work) but it's just to make an idea.
There are two main things what i would like to do:
1) Catch the id (and other store's fields) of the selected item on the action "selectionchange". Obviously, now it doesn't work because of this: node.get('id'). Of course it's a wrong syntax but make up the idea of my will.
2) Catch the id of the selected item on the handler event of the "update-player" button. As above, the issue is the nodes.get('id'). Further trouble, is how to pass the selected item's features. in handler: function(nodes) { the nodes variable does not assume any value and i don't know how to pass the params from the dataview to the handler function.
I hope that somebody will able to help me.
According to the docs the selectionchange event provides the selection model as well as the array of selected records, so you are probably assuming the wrong parameters in your listener.
Without doing further testing, I think it should be something like this:
listeners: {
'selectionchange': function(selModel, selection, eOpts) {
var node = selection[0];
console.log(node.get('id'));
}
}
Note that you're using multiSelect: true, so it could be more than one record in the selection array.
Answer for second part of the question:
In button handler, you need to get selection model of the view and from it get information about selected records:
handler: function(nodes) {
// find view component
var view = dataView_player.down('dataview');
// get all selected records
var records = view.getSelectionModel().getSelection();
// process selected records
for(var i = 0; i < records.length; i++) {
console.log(records[i].getId());
}
}

Select a row in jqGrid based on cell value

colModel: [
{ name: 'Id', index: 'Id', hidden: true, search: false },
{ name: 'Name', index: 'Name', hidden: true, search: false },
]
Just as the setSelection method allows selection of a row in jqGrid based on the row number, is it possible to similarly select a row based on one of the cell values.
For e.g. in the colModel above, is it possible to select a row having a certain 'Id' or 'Name' value...assuming that these values are unique for each row.
In the loadComplete: portion of your jqGrid you could iterate over each row and test for the value you are looking for. If the value is found, select the row.
Ex
loadComplete: function () {
var rowIds = $(this).jqGrid('getDataIDs');
for (i = 1; i <= rowIds.length; i++) {
rowData = $(this).jqGrid('getRowData', i);
if (rowData['Id'] == idSearchValue ) {
$(this).jqGrid('setSelection',i);
} //if
} //for
...
There would also be the rowattr: but I can't seem to find where you can get the rowID of the current row. Oleg might see this and respond as well as it was his addition to jqGrid but I didn't have any luck with my testing or read though of where you would get the current rowId to pass to the setSelection method.
If you have an array of objects containing cells values, you will need another approach.
Eg. with your colModel, you would like to retrieve rows with these values:
let toSearch = [
{ Name: 'Arthur', Id: 150},
{ Name: 'Julien', Id: 90},
]
Then what you can do is to retrieve the whole data from the jqGrid table and seek after values dynamically:
let data = $grid.jqGrid('getGridParam', 'data');
let toSelect = data.filter((row,i) => {
return toSearch.some(toSelectRow => {
for(let prop in prevRow) {
if(prevRow[prop] != row[prop])
return false;
}
return true;
})
});
toSelect.forEach((row) => $grid.jqGrid('setSelection',row.id, false)); // Prevent firing onSelectRow event
Here we pass false to prevent from firing onSelectRow event, if you need it just remove false

MVC3 JQGrid Set colmodel dynamically from controller

I've seen tons of examples about setting the colmodel in the view but I haven't been able to see the controller code!
I am trying to do it but the setup keep being wrong.
I am trying to reach this column formation:
colModel:
[
{ name: 'ID', index: 'ID', hidden: true },
{ name: 'Votes', index: 'Votes', width: 100, align: 'left' },
{ name: 'Question', index: 'Question', width: 300, align: 'left' },
{ name: 'my_clickable_checkbox', index: 'my_clickable_checkbox',
sortable: true,
formatter: chkFmatter, formatoptions: { disabled: false }, editable: true,
edittype: "checkbox"
}
],
This is my trial in the controller:
return Json(
new { colNames = new[] { "ID2", "Votes2", "Question2", "checkbox" },
colModel = new[] {
new { name = "ID", index = "ID", width = 0, formatter="",
edittype="", hidden = true },
new { name = "Votes", index = "Votes", width = 100, formatter="",
edittype="", hidden = false },
new { name = "Question", index = "Question", width = 300, formatter="",
edittype="", hidden = false },
new { name = "checkbox", index = "my_clickable_checkbox", width = 100,
formatter="chkFmatter", edittype="checkbox", hidden = false }
}
}, JsonRequestBehavior.AllowGet);
The creation of this array in the controller is forcing me to have the same number of properties in all rows. For example, I only need the ID to be hidden, but it forces me to supply a hidden property to all other columns.
Second problem, I need to call js function chkFmatter for the fourth column.
how can I reach that colModel formation in controller??
thanks much.
You might be interested in looking at jqGrid Importing and exporting functionality. It allows you to import or export the entire jqGrid configuration to or from another file format.
You can read this blog post:
jqGrid and ASP.NET MVC - Configuration Import/Export
to get the general idea on how to use those functionalities with ASP.NET MVC, but it`s a little bit out of date if it comes to ASP.NET MVC stuff (it is based on ASP.NET MVC 1).
You can also take a look at this jqGrid sample project:
jqGrid in ASP.NET MVC 3 and Razor
which (among other things) contains sample for configuration import/export.
Most imported thing to remember here is that you still need to set any jqGrid events/callbacks or call any additional methods like 'setFrozenColumns' after configuration import.

Nestedlist not showing store data when inside panel

I'm having a problem loading my nestedlist data when this list is shown inside of a panel.
Here is my code:
var titleBar = Ext.create("Ext.TitleBar", {
id: 'mainNavigationBar',
xtype : 'titlebar',
layout: 'hbox',
docked: 'top',
title : 'cSenchaTitleBar',
items:[
{
xtype:"button",
text:"Menu",
align:"left",
listeners:{
tap: function(){
nestedListxx.showBy(this);
}
}
},
]
});
var nestedList =
Ext.create('Ext.NestedList', {
displayField: 'text',
title:"cSenchaMenu",
store: "oNavStore",
id: 'mainNestedList',
xtype : 'nestedlist',
width:250,
useTitleAsBackText: false,
});
var nestedListxx = Ext.create("Ext.Panel", {
width:260,
items:nestedList
});
The problem is the following:
Say that if I change
nestedListxx.showBy(this); to nestedList.showBy(this);
It works like a charm, only there are no sleek black borders around the nested list.
But if I change it back it does show the nestedlist with the nice borders but without any data.
I know for sure that I forgot to set some key configuration, only the question is: which ones
You probably need to set a layout to your Ext.Panel.
Try :
var nestedListxx = Ext.create("Ext.Panel", {
width:260,
layout:'fit',
items:nestedList
});
Hope this helps

Extjs4 RESTful CRUD grid with Spring Controllers

I am new to Extjs4 and the javascript world in general. I have looked up the documentation and samples and trying to get a basic CRUD grid up and running with my spring backend.
I have a confusion related to the proxy in extjs, are they in the store or model according to the MVC paradigm ?
I have a controller.js defined which wraps these up together.
I would have thought that the REST calls would be made accroding to the urls being specified, which it is for now , but a create call is still sending the entire list. I am using jackson at the backend for automatic conversion to java objects but somehow that is not working (for add and update only).
How do i link these all up ?
a) Add a user .. do i create a new UserModel and then invoke a rest call like so or is it automatically supported by the proxy specified in the model ?
var record = new App.model.UserModel();
store = Ext.getStore('UsersStore');
store.insert(0, record);
store.save(); // .. this invokes the /createUser method
// .. what about /update ?
b) I am using the RowEditing plugin .. how can i fetch the roweditor in my controller.js where the reference for the view is available
Thanks in advance
relevant code listings ...
//UserController.js
Ext.define('App.controller.UsersController', {
extend : 'Ext.app.Controller',
init: function() {
this.control({
'userList button[action=add]' : {
click : this.editUser
} }); },
views : ['user.List','user.Edit'],
stores : ['UsersStore'] ,
models : ['UserModel'],
editUser : function(grid,record)
{
// empty record
var record = new App.model.UserModel();
// created new record
//How to get a reference to the roweditor here and then save that to the backend ?
//store = Ext.getStore('UsersStore');
//store.insert(0, record);
//store.save();
// this.getView('user.List').getP('rowEditor').startEdit(0, 0);
}});
//List.js
var rowEditor = Ext.create('Ext.grid.plugin.RowEditing', {
clicksToEdit: 2
}
Ext.define('App.view.user.List' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.userList',
title : 'All Users',
store : 'UsersStore',
selType: 'rowmodel',
plugins: rowEditor,
initComponent: function() {
this.columns = [
{header: 'SNo', dataIndex: 'userID', width:50},
{header: 'UID', dataIndex: 'userUID', flex: 1, editor: 'textfield', allowBlank:false},
{header: 'Name', dataIndex: 'userName', flex: 1, editor:'textfield',allowBlank:false},
{ header: 'Level', dataIndex: 'userLevel', flex: 1,
editor: {xtype: 'combobox', typeAhead: true, triggerAction: 'all', selectionOnTab:true,
store : [
['Level 1','Level 1'],
['Level 2','Level 2'],
['Level 3','Level 3']
]
}
},
{header: 'Email', dataIndex: 'emailID', flex: 1, editor: 'textfield'}
];
this.callParent(arguments);
},
dockedItems : [{
xtype : 'toolbar',
items : [{
text: 'Add',
iconCls: 'icon-add',
action: 'add'
}]
}]});
//Model.js
Ext.define('App.model.UserModel', {
extend: 'Ext.data.Model',
fields: ['userID','userUID','userName', 'userLevel' ,'emailID'],
proxy : {
type: 'ajax',
api :
{
read : 'rest/user/fetchAll',
update:'rest/user/updateUser',
create :'rest/user/createUser',
destroy : 'rest/user/deleteUser'
},
reader :
{
type : 'json',
root : 'users',
successProperty : 'success'
},
writer :
{
type : 'json',
allowSingle : 'true'
}
}});
//UserStore
Ext.define('App.store.UsersStore', {
extend: 'Ext.data.Store',
model: 'App.model.UserModel',
autoLoad : true});
//Sample Java controller
#Controller
#RequestMapping("/rest/user")
public class UserController {
#RequestMapping(value = "/fetchAll" , method= RequestMethod.GET)
public #ResponseBody Map<String,? extends Object>
fetchUsers() {
Map<String,Object> responseMap = new HashMap<String,Object>();
responseMap.put("success",true);
responseMap.put("users",userService.getUserRepository().findAll());
return responseMap; }
// was expecting a single object here ?
#RequestMapping(value = "/createUser")
public #ResponseBody Map<String,? extends Object>
createUser(#RequestBody List<User> users)
{ ... }
}
I would put Proxy's inside store objects, not models. But that just personal preference.
When you add record to the store object, if it has autoSync property set to true it would automatically generate create request. What exactly is happening with your create request? What is being sent?
After trying out Sha's comments above, i was finally able to nail the issue.
The problem is with the json reader
reader :
{
type : 'json',
root : 'users',
successProperty : 'success'
//added
idProperty : 'userID'
},
I had to add the idProperty to make Json recognize the dirty record, else it treats everything as a new record and sends back the whole list

Resources