Filtering grid with QueryReadStore - dojo

I have a grid wich store is a QueryReadStore. It works fine, even the virtual scrolling.
The problem is the filter, when I filter, it generates a strange URL like this:
http://mydomain:8080/project=%3F&1=f&2=i&3=l&4=t&5=e&6=r&7=......
And I want to looks like this:
http://localhost:8080/project?filter={%22op%22:%22contains%22,%22data%22:[{%22op%22:%22string%22,%22data%22:%22username%22,%22isCol%22:true},{%22op%22:%22string%22,%22data%22:%22s%22,%22isCol%22:false}]}
Here is the code that generates the grid and the filter:
this.grid = new EnhancedGrid({
store: null,
structure: this.columns,
rowsPerPage: 20,
autoHeight: false,
plugins: {
filter: {
closeFilterbarButton: false,
isServerSide: true,
setupFilterQuery: dojo.hitch(this, function(commands, request){
if(commands.filter && commands.enable){
var gridStoreURL = this.grid.store.url;
if(gridStoreURL.indexOf("?") > -1) {
request.query = "&filter=" + JSON.stringify(commands.filter);
} else {
request.query = "?filter=" + JSON.stringify(commands.filter);
}
}else{
}
}),
ruleCount: 3,
itemsName: "logs",
disabledConditions: {anycolumn : this.disabledFilterAnyColumn}
}
}
}, this.idGridContainer);
I create the store with this function:
var store = dojox.data.QueryReadStore({
url : this.urlBase + agentId,
requestMethod:"get"
});
this.grid.setStore(store, null, null);
When I use JsonStore to create the store, the filter works fine, but with this doesn't.
Thank you in advance

You appear to be attempting to set the store query to a string, but IIRC QueryReadStore only ever expects the query to be passed as an object, as opposed to JsonRestStore which can accept it either way.
Try something like this instead, for starters, and see if it gets you further:
request.query = { filter: JSON.stringify(commands.filter) }

Related

Syncfusion TreeGrid and Grid with WebAPI doesn't work on delete

I've set up a treeGrid (the grid is the same) to get data through the ASP.NET WebAPI using their DataManager:
var categoryID=15;
var dataManager = ej.DataManager({
url: "/API/myrecords?categoryID=" + categoryID,
adaptor: new ej.WebApiAdaptor()
});
$("#treeGridContainer").ejTreeGrid({
dataSource: dataManager,
childMapping: "Children",
treeColumnIndex: 1,
isResponsive: true,
contextMenuSettings: {
showContextMenu: true,
contextMenuItems: ["add", "edit", "delete"]
},
contextMenuOpen: contextMenuOpen,
editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal', editMode: "rowEditing" },
columns: [
{ field: "RecordID", headerText: "ID", allowEditing: false, width: 20, isPrimaryKey: true },
{ field: "RecordName", headerText: "Name", editType: "stringedit" },
],
actionBegin: function (args) {
console.log('ActionBegin: ', args);
if (args.requestType === "add") {
//add new record, managed manually...
var parentID = 0;
if (args.level != 0) {
parentID = args.parentItem.TaxonomyID;
}
args.data.TaxonomyID = 0;
addNewRecord(domainID, parentID, args.data, args.model.selectedRowIndex);
}
}
});
The GET works perfectly.
The PUT works fine as I'm managing it manually because it's not called at all from the DataManager, and in any case I want to manage the update of the records in the TreeGrid.
The problem is with DELETE, that is called by the DataManager when I click Delete from the context menu over an item in the TreeGrid.
It makes a call to the following URL:
http://localhost:50604/API/myrecords?categoryID=15/undefined
and obviously, I get a 405 (Method Not Allowed)
The problem is given by the categoryID parameters that break the RESTful schema, and the DataManager is not able to understand that there is a parameter.
A possible solution could be to send this parameter as a POST variable but the DataManager is not able to do it.
Does anyone have a clue of how to solve it? it's a common scenario in real-world applications.
While populating Tree Grid data using ejDataManger, CRUD actions will be handled using inbuilt Post (insert), Put (update), Delete requestType irrespective of CRUD URL’s. So, no need to bind ‘removeUrl’ for deleting records.
And, in the provided code example parameter is passed in the URL to fetch data hence the reported issue occurs. Using ejQuery’s addParams method we can pass the parameter in URL. You can find the code example to pass the parameter using Tree Grid load event and the parameter is retrieved in server side using DataManager.
[html]
var dataManager = ej.DataManager({
url: "api/Values",
adaptor: new ej.WebApiAdaptor()
});
$("#treeGridContainer").ejTreeGrid({
load: function (args) {
// to pass parameter on load time
args.model.query.addParams("keyId", 48);
},
});
[controller]
public object Get()
{
var queryString = HttpContext.Current.Request.QueryString;
// here we can get the parameter during load time
int num = Convert.ToInt32(queryString["keyId"]);
//..
return new {Items = DataList, Count = DataList.Count() };
}
You can find the sample here for your reference.
Regards,
Syncfusion Team

SDK2: sorting custom column in a rally grid

I have a rally grid that shows defects. I want do add a column that shows the number of days a defect has been open.
I know can do that by adding a custom renderer in the column configs, but I would also like to sort on this column. Unfortunately, the renderer does not change the sorting of the column.
I think I might be able to use the convert() function on the store instead to create a new virtual column (in this case openAgeDays), but I'm not sure how to do this from the constructor--I presume I make some changes to storeConfig?
Does anyone have an example of how to use a convert function (assuming that this is the right way to do it) to add a new virtual, sortable column to a rally grid?
this.grid = this.add({
xtype: 'rallygrid',
model: model,
disableColumnMenus: false,
storeConfig: [...]
As is the answer in the duplicate, you can add a doSort to the column:
{dataIndex: 'Parent', name: 'Parent',
doSort: function(state) {
var ds = this.up('grid').getStore();
var field = this.getSortParam();
console.log('field',field);
ds.sort({
property: field,
direction: state,
sorterFn: function(v1, v2){
console.log('v1',v1);
console.log('v2',v2);
if (v1.raw.Parent) {
v1 = v1.raw.Parent.Name;
} else {
v1 = v1.data.Name;
}
if (v2.raw.Parent) {
v2 = v2.raw.Parent.Name;
} else {
v2 = v2.data.Name;
}
return v1.localeCompare(v2);
}
});
},
renderer: function(value, meta, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
}
},

How update datatable without render all the table again?

I´m working with datatables for a meteor app.
My problem is that when some fields change all the table is rendered again, if I´m on page two on the table or I order by field, the table is rendered again and I´m back on the beginning.
My code:
Template.adminpage.rendered = function() {
$('#userData').dataTable({
"bDestroy":true,
"aaSorting": [[ 0, "desc" ]],
"bAutoWidth":false,
"bFilter": false,
"aoColumns": [
{ "bVisible": false },
null,
null,
null,
null,
null,
null,
null
],
"aaData": Template.adminpage.arrayUsersAdmin()
});
}
Array that populates the table:
Template.adminpage.arrayUsersAdmin=function() {
var adminUsers = allUserData.find({roles: 'basic'});
var arrayUserAdmin = [];
var count=0;
adminUsers.forEach(function(user) {
var idColumn = user._id;
var dateColumn=moment(user.createdAt).format("MMM Do HH:mm");
var usernameColumn=username;
var emailColumn=email;
arrayUserAdmin[count]=[
idColumn,
dateColumn,
usernameColumn,
emailColumn
];
count++;
});
return arrayUserAdmin;
}
Collection on the server:
if(Meteor.users.find({_id: this.userId}, {roles: 'admin'})){
Meteor.publish("allUserData", function () {
var self = this;
var handle = Meteor.users.find({}).observeChanges({
added: function(id, fields){
self.added("allUsersCollection", id, fields);
},
changed: function(id, fields){
self.changed("allUsersCollection", id, fields);
},
removed: function(id){
self.removed("allUsersCollection", id);
}
});
self.ready();
this.onStop(function() {
handle.stop();
});
});
}
Thanks for your time.
You can pass reactive: false as an option to find, which disables the underlying addition of a dependency, like so:
Template.adminpage.arrayUsersAdmin=function() {
var adminUsers = allUserData.find({roles: 'basic'}, reactive: false);
// Your code
return arrayUserAdmin;
}
This behaviour is documented here
Alternatively, if you would like the individual fields to update, you will have to add them in yourself. To do this, you can use allUserDate.find({roles: 'basic'}).observe. This will require you, however, to edit the HTML directly, and is quite messy. A better alternative would be to change your table structure entirely - don't use a data table, use a vanilla HTML table, and sort the data with minimongo queries.
Regardless, you can use observe like so:
allUserData.find({roles: 'basic'}).observe({
changed: function(newDocument, oldDocument) {
// Update table
}
});

Dojo Tree : bridge from *unformatted* json to expected format

I am very new to Dojo (1.7), and I am very excited by the AMD loader and the global philosophy, then thought I have red some dozen of documentation and googled a lot and my brains starts to grill, I am still unable to understand and perform some things : I would like to display a dijit.Tree of any sort of JSON, yes like a JSON editor, because I use also persistent JSON files for storing few datas (not only for GET/.../ transmission) . Here are my expects :
sample JSON : {"infos":{"address":"my address","phone":"my
phone"},"insurance":{"forks":[14,53,123],"prices":[5,8,"3%"]}}
display the differents variables of any JSON : the root child is the
root json variable, children L1 are the root variables, etc...and upon the json variable type (String, Number, Object, Array) I will also display a corresponding icon
not to have to parse the whole json and format it in one big time, would like for exemple to display first the root node, then the well formated children trought a getChildren method for example, so it is done progressively on expando (like a lazy load). I have already made my own Trees classes with javascript, the more flexible way was I gave a dataRoot, a renderItem(dataItem, domItem) and a getChildren(dataItem) to the constructor so I could perform and return all I want, the Tree only performed the rendering only when needed, the Tree had no knowing about datas structure neither modify it, but I am not sure to understand well why the dijit.Tree needs a so restrictive way of build...
Here is my last try, it might totally not the right way, (maybe I have to subclass) but as far as I understand, I need to play with 3 classes (dojo store, tree model and tree widget), but firstly it seems the model can't get the root node, please check my different code comments. So please is there any patient person that can give me a simple example with some clear explanations (yeah I am a bit demanding), at least the list of the right necessary variables for constructor's options I need for start displaying a nice tree view of my json file, there's so much I'm totally lost, many thanks !
...
// before there is the AMD part that load the needed things
Xhr.get({ url:'data/file.json', handleAs:'json',
load: function(data){
console.log('xhr.loaded : ', data);// got my javascript object from the json string
var store = new ItemFileReadStore({// is it the right store I need ??
// or the Memory store ?
// assuming later I'll need to save the data changes
rootId : 'root',//
rootLabel : 'Archive',// useless ? isn't it the model responsability ?
data : {id:'root', items:[data]}// trying to give a root node well formatted
});
var model = new TreeStoreModel({
store : store,
getChildren : function(obj){
// firstly here it seems the root is not found
// I got a 'error loading root' error
// what is missing in my instanciations ??
// what is exactyly the type of the 1st arg : a store ?
console.log('getChildren : ', this.get(obj.id));
},
mayHaveChildren : function(){
console.log('mayHaveChildren ', arguments);
return true;
}
});
var tree = new Tree({
model: model
}, domId);
tree.startup();
}
});
My solution is based on dojo/store/Memory inspired by Connecting a Store to a Tree:
You can find live demo at http://egoworx.com/ or download complete source from dropbox.
Now code. First dojo/store/Memory:
var data = {"infos":{"address":"my address","phone":"my phone", "gift": false, "now": new Date()},"insurance":{"forks":[14,53,123],"prices":[5,8,"3%"]}};
var store = new Memory({
data: data,
mayHaveChildren: function(object) {
var type = this.getType(object);
return (type == "Object" || type == "Array");
},
getChildren: function(object, onComplete, onError) {
var item = this.getData(object);
var type = this.getType(object);
var children = [];
switch(type) {
case "Array":
children = item;
break;
case "Object":
for (i in item) {
children.push({label: i, data: item[i]});
}
break;
}
onComplete(children);
},
getRoot: function(onItem, onError) {
onItem(this.data);
},
getLabel: function(object) {
var label = object.label || object + "";
var type = this.getType(object);
switch(type) {
case "Number":
case "String":
case "Boolean":
case "Date":
var data = this.getData(object);
if (data != label) {
label += ": " + this.getData(object);
}
}
return label;
},
getData: function(object) {
if (object && (object.data || object.data === false) && object.label) {
return object.data;
}
return object;
},
getType: function(object) {
var item = this.getData(object);
if (lang.isObject(item)) {
if (lang.isArray(item)) return "Array";
if (lang.isFunction(item)) return "Function";
if (item instanceof Date) return "Date";
return "Object";
}
if (lang.isString(item)) return "String";
if (item === true || item === false) return "Boolean";
return "Number";
},
getIconClass: function(object, opened) {
return this.getType(object);
}
});
Please note I added a boolean and Date type to your data.
dijit/Tree based on this store:
var tree = new Tree({
model: store,
persist: false,
showRoot: false,
getIconClass: function(object, opened) {
if (lang.isFunction(this.model.getIconClass)) {
return this.model.getIconClass(object, opened);
}
return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf";
}
}, "placeholder");
tree.startup();
And finally a stylesheet to display data type icons:
.dijitTreeIcon {
width: 16px;
height: 16px;
}
.Object {
background-image: url(http://dojotoolkit.org/api/css/icons/16x16/object.png);
}
.Array {
background-image: url(http://dojotoolkit.org/api/css/icons/16x16/array.png);
}
.Date {
background-image: url(http://dojotoolkit.org/api/css/icons/16x16/date.png);
}
.Boolean {
background-image: url(http://dojotoolkit.org/api/css/icons/16x16/boolean.png);
}
.String {
background-image: url(http://dojotoolkit.org/api/css/icons/16x16/string.png);
}
.Number {
background-image: url(http://dojotoolkit.org/api/css/icons/16x16/number.png);
}
I cannot access jsFiddle since I'm currently in China, but I'll put the code above there upon my return to Europe and post a link here.
Try somethign like that instead :
store = new dojo.data.ItemFileWriteStore({
url : "",
data: {
identifier: "id",
label : "label",
items : [{
id : "root",
label : "root",
type : "root",
children: [data]
}]
}
});
Also in general avoid overriding the tree functions, you might extend them, but becareful.
If you want to console.log, then rather connect to them...
ItemFileReadStore is a read-only store, so not the one you want for "saving modifications".
You can try the ItemFileWriteStore, or JsonRest, etc.

In an ExtJS Grid, how do I get access to the data store fields that are part of the sort set

How do I get access to the columns/datastore fields that are part of the sort set.
I am looking to modify the a grid's sort parameters for remote sorting. I need the remote sort param's sort key to match the column's field's mapping property. I need these things to happen though the normal 'column header click sorts the data' functionality.
Remote sorting and field mapping (ExtJS 4.1)
This functionality seems not to be implemented in ExtJS. Here is a solution using the encodeSorters function provided since ExtJS 4. Accessing fields map throught the model's prototype is a bit dirty but it does the job :
var store = Ext.create('Ext.data.Store', {
...,
proxy: {
...,
encodeSorters: function (sorters) {
var model = store.proxy.model,
map = model.prototype.fields.map;
return Ext.encode(Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
}));
}
}
});
However, it would be more relevant to override the original method :
Ext.data.proxy.Server.override({
encodeSorters: function(sorters) {
var min, map = this.model.prototype.fields.map;
min = Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
});
return this.applyEncoding(min);
}
});
Assuming you are using simpleSortMode, you could do something like this in your store.
listeners: {
beforeload: function( store, operation, eOpts ) {
if (store.sorters.length > 0) {
var sorter = store.sorters.getAt(0),
dir = sorter.direction,
prop = sorter.property,
fields = store.model.getFields(),
i,
applyProp = prop;
for (i = 0; i < fields.length; i++) {
if (fields[i].name == prop) {
applyProp = fields[i].mapping || prop;
break;
}
}
//clearing the sorters since the simpleSortMode is true so there will be only one sorter
store.sorters.clear();
store.sorters.insert(0, applyProp, new Ext.util.Sorter({
property : applyProp,
direction: dir
}));
}
}
},