dojo 1.6 DataGrid cannot display lists? - dojo

In dojo 1.7.2, if I create a data store containing array values, dojox.grid.DataGrid displays them with no problem, separating each item with a coma.
However, in dojo 1.6, it takes only the first element of my array. I have a project where I have to use version 1.6. Is there any workaround for this in that version ?
To illustrate the problem, here are 2 examples :
On dojo 1.6 : http://jsfiddle.net/psoares/HbFNY/
On dojo 1.7 : http://jsfiddle.net/psoares/QLm65/
Thanks !

Apparently the problem comes from ItemFileReadStore rather than from the grid.
I modified my code for 1.6 to use ObjectStore and MemoryStore instead, and it worked.
See http://jsfiddle.net/psoares/HbFNY/16/

this is a flaw and yet it is not.. The construct of your JSON is not quite right as any value is not allowed as array unless it is one of the childAttrs. Due to nature of [1,2,3].toString() that is why your attempts on setting values as arrays are considered valid.
The get/set in an ItemFileReadStore works with its items as such:
store._arrayOfAllItems = {
value1 : { values : [ 'realvalue' ] },
value2 : { values : [ 'realvalue' ] }
};
the getter then says
store.get = function(itemById, val) { return itemById[val][0]; }
// why only the first arrayslot is pulled from store---/^
In your JSON construct, what prohibits you from settings the values as such following?
var data = {
id: 'id',
label: 'id',
items: [
{
id: "value1",
values: "a,b,c" // permit-able string value
},
{
id: "value2",
values: "foo"}
]
};
If you want multiple values by same key of one ID then you must deliver the data as children and handle them as such, like;
data: {
id: 'id',
label: 'id',
childrenAttrs: [ 'items', 'children'], // << default behavior
items: [ {
id: "value1",
children: [
{ id: "value1_1", values: 'a' },
{ id: "value1_2", values: 'b' },
{ id: "value1_3", values: 'c' }
]
}, {
id: "value2",
values: "foo"
} ]
}
However, only the dojox.grid.TreeGrid will allow using multi-lvl datastores

Related

Indexes: Search by Boolean?

I'm having some trouble with FaunaDB Indexes. FQL is quite powerful but the docs seem to be limited (for now) to only a few examples/use cases. (Searching by String)
I have a collection of Orders, with a few fields: status, id, client, material and date.
My goal is to search/filter for orders depending on their Status, OPEN OR CLOSED (Boolean true/false).
Here is the Index I created:
CreateIndex({
name: "orders_all_by_open_asc",
unique: false,
serialized: true,
source: Collection("orders"),
terms: [{ field: ["data", "status"] }],
values: [
{ field: ["data", "unique_id"] },
{ field: ["data", "client"] },
{ field: ["data", "material"] },
{ field: ["data", "date"] }
]
}
So with this Index, I want to specify either TRUE or FALSE and get all corresponding orders, including their data (fields).
I'm having two problems:
When I pass TRUE OR FALSE using the Javascript Driver, nothing is returned :( Is it possible to search by Booleans at all, or only by String/Number?
Here is my Query (in FQL, using the Shell):
Match(Index("orders_all_by_open_asc"), true)
And unfortunately, nothing is returned. I'm probably doing this wrong.
Second (slightly unrelated) question. When I create an Index and specify a bunch of Values, it seems the data returned is in Array format, with only the values, not the Fields. An example:
[
1001,
"client1",
"concrete",
"2021-04-13T00:00:00.000Z",
],
[
1002,
"client2",
"wood",
"2021-04-13T00:00:00.000Z",
]
This format is bad for me, because my front-end expects receiving an Object with the Fields as a key and the Values as properties. Example:
data:
{
unique_id : 1001,
client : "client1",
material : "concrete",
date: "2021-04-13T00:00:00.000Z"
},
{
unique_id : 1002,
client : "client2",
material : "wood",
date: "2021-04-13T00:00:00.000Z"
},
etc..
Is there any way to get the Field as well as the Value when using Index values, or will it always return an Array (and not an object)?
Could I use a Lambda or something for this?
I do have another Query that uses Map and Lambda to good effect, and returns the entire document, including the Ref and Data fields:
Map(
Paginate(
Match(Index("orders_by_date"), date),
),
Lambda('item', Get(Var('item')))
)
This works very nicely but unfortunately, it also performs one Get request per Document returned and that seems very inefficient.
This new Index I'm wanting to build, to filter by Order Status, will be used to return hundreds of Orders, hundreds of times a day. So I'm trying to keep it as efficient as possible, but if it can only return an Array it won't be useful.
Thanks in advance!! Indexes are great but hard to grasp, so any insight will be appreciated.
You didn't show us exactly what you have done, so here's an example that shows that filtering on boolean values does work using the index you created as-is:
> CreateCollection({ name: "orders" })
{
ref: Collection("orders"),
ts: 1618350087320000,
history_days: 30,
name: 'orders'
}
> Create(Collection("orders"), { data: {
unique_id: 1,
client: "me",
material: "stone",
date: Now(),
status: true
}})
{
ref: Ref(Collection("orders"), "295794155241603584"),
ts: 1618350138800000,
data: {
unique_id: 1,
client: 'me',
material: 'stone',
date: Time("2021-04-13T21:42:18.784Z"),
status: true
}
}
> Create(Collection("orders"), { data: {
unique_id: 2,
client: "you",
material: "muslin",
date: Now(),
status: false
}})
{
ref: Ref(Collection("orders"), "295794180038328832"),
ts: 1618350162440000,
data: {
unique_id: 2,
client: 'you',
material: 'muslin',
date: Time("2021-04-13T21:42:42.437Z"),
status: false
}
}
> CreateIndex({
name: "orders_all_by_open_asc",
unique: false,
serialized: true,
source: Collection("orders"),
terms: [{ field: ["data", "status"] }],
values: [
{ field: ["data", "unique_id"] },
{ field: ["data", "client"] },
{ field: ["data", "material"] },
{ field: ["data", "date"] }
]
})
{
ref: Index("orders_all_by_open_asc"),
ts: 1618350185940000,
active: true,
serialized: true,
name: 'orders_all_by_open_asc',
unique: false,
source: Collection("orders"),
terms: [ { field: [ 'data', 'status' ] } ],
values: [
{ field: [ 'data', 'unique_id' ] },
{ field: [ 'data', 'client' ] },
{ field: [ 'data', 'material' ] },
{ field: [ 'data', 'date' ] }
],
partitions: 1
}
> Paginate(Match(Index("orders_all_by_open_asc"), true))
{ data: [ [ 1, 'me', 'stone', Time("2021-04-13T21:42:18.784Z") ] ] }
> Paginate(Match(Index("orders_all_by_open_asc"), false))
{ data: [ [ 2, 'you', 'muslin', Time("2021-04-13T21:42:42.437Z") ] ] }
It's a little more work, but you can compose whatever return format that you like:
> Map(
Paginate(Match(Index("orders_all_by_open_asc"), false)),
Lambda(
["unique_id", "client", "material", "date"],
{
unique_id: Var("unique_id"),
client: Var("client"),
material: Var("material"),
date: Var("date"),
}
)
)
{
data: [
{
unique_id: 2,
client: 'you',
material: 'muslin',
date: Time("2021-04-13T21:42:42.437Z")
}
]
}
It's still an array of results, but each result is now an object with the appropriate field names.
Not too familiar with FQL, but I am somewhat familiar with SQL languages. Essentially, database languages usually treat all of your values as strings until they don't need to anymore. Instead, your query should use the string definition that FQL is expecting. I believe it should be OPEN or CLOSED in your case. You can simply have an if statement in java to determine whether to search for "OPEN" or "CLOSED".
To answer your second question, I don't know for FQL, but if that is what is returned, then your approach with a lamda seems to be fine. Not much else you can do about it from your end other than hope that you get a different way to get entries in API form somewhere in the future. At the end of the day, an O(n) operation in this context is not too bad, and only having to return a hundred or so orders shouldn't be the most painful thing in the world.
If you are truly worried about this, you can break up the request into portions, so you return only the first 100, then when frontend wants the next set, you send the next 100. You can cache the results too to make it very fast from the front-end perspective.
Another suggestion, maybe I am wrong and failed at searching the docs, but I will post anyway just in case it's helpful.
My index was failing to return objects, example data here is the client field:
"data": {
"status": "LIVRAISON",
"open": true,
"unique_id": 1001,
"client": {
"name": "TEST1",
"contact_name": "Bob",
"email": "bob#client.com",
"phone": "555-555-5555"
Here, the client field returned as null even though it was specified in the Index.
From reading the docs, here: https://docs.fauna.com/fauna/current/api/fql/indexes?lang=javascript#value
In the Value Objects section, I was able to understand that for Objects, the Index Field must be defined as an Array, one for each Object key. Example for my data:
{ field: ['data', 'client', 'name'] },
{ field: ['data', 'client', 'contact_name'] },
{ field: ['data', 'client', 'email'] },
{ field: ['data', 'client', 'phone'] },
This was slightly confusing, because my beginner brain expected that defining the 'client' field would simply return the entire object, like so:
{ field: ['data', 'client'] },
The only part about this in the docs was this sentence: The field ["data", "address", "street"] refers to the street field contained in an address object within the document’s data object.
This is enough information, but maybe it would deserve its own section, with a longer example? Of course the simple sentence works, but with a sub-section called 'Adding Objects to Fields' or something, this would make it extra-clear.
Hoping my moments of confusion will help out. Loving FaunaDB so far, keep up the great work :)

useGetList fetched data sorted by id ignoring sort option

The problem is that data fetched by useGetList is sorted by ids of the objects and ignores the order by other keys given by my backend. This is my call example (try to order by name):
const { data, loading } = useGetList(
'my-controller-path',
{ page: 1, perPage: 10000 },
{ field: 'name', order: 'ASC' },
{}
)
console.log(data)
When I print data after this call, data is sorted by 'id' and not by 'name'. It's not a problem with the backend because I hardcoded returning data to eliminate this from equation. Data provided from backend:
data: [
{ id: 2, name: 'Ana'},
{ id: 3, name: 'Bea'},
{ id: 1, name: 'Cena'}
]
And when I print data on console after using useGetList:
[
{id: 1, name: "Cena"},
{id: 2, name: "Ana"},
{id: 3, name: "Bea"}
]
Any idea what is causing the problem? I read the source code of useGetList and don't quite understand if the problem lays there. The link to source code.
How does your API works ? In my case, I needed to map the sort properties like so:
getList: async (
resource,
{ pagination: { page, perPage }, sort: { field, order }, filter }
) => {
const query = {
...filter,
sort: order.toLowerCase(),
order: field,
page: JSON.stringify(page),
limit: JSON.stringify(perPage),
};
...
}
in my custom data provider to match my API sort and order properties.

Is it possible to add animations to dgrid rows?

We currently have a dgrid with a single column and rows like this:
Recently I added some code so that we can delete rows with the little X button that appears above the row when we hover them.
The handler calls this to delete the row:
this.grid.store.remove(rowId);
When we delete a row, since it's instantaneous and each row contains similar text, it's not always obvious to the user that something just happened.
I was wondering if it would be possible add some sort of dojo or css animation to the row deletion, like the deleted row fading or sliding out. This would make the row deletion more obvious.
Thanks
I have created a jsfiddle for animating(wipeOut) a selected row.
require({
packages: [
{
name: 'dgrid',
location: '//cdn.rawgit.com/SitePen/dgrid/v0.3.16'
},
{
name: 'xstyle',
location: '//cdn.rawgit.com/kriszyp/xstyle/v0.2.1'
},
{
name: 'put-selector',
location: '//cdn.rawgit.com/kriszyp/put-selector/v0.3.5'
}
]
}, [
'dojo/_base/declare',
'dgrid/OnDemandGrid',
'dgrid/Selection',
'dojo/store/Memory',
"dojo/fx",
'dojo/domReady!'
], function(declare, Grid, Selection, Memory,fx) {
var data = [
{ id: 1, name: 'Peter', age:24 },
{ id: 2, name: 'Paul', age: 30 },
{ id: 3, name: 'Mary', age:46 }
];
var store = new Memory({ data: data });
var options = {
columns: [
/*{ field: 'id', label: 'ID' },*/
{ field: 'name', label: 'Name' },
{ field: 'age', label: 'Age' }
],
store: store
};
var CustomGrid = declare([ Grid, Selection ]);
var grid = new CustomGrid(options, 'gridcontainer');
grid.on('dgrid-select', function (event) {
// Report the item from the selected row to the console.
console.log('Row selected: ', event.rows[0].data);
//WipeOut animation for selected row.
fx.wipeOut({ node: event.rows[0].element }).play();
});
});

ExtJs4+: can calculated model field be editable?

My model has two data fields: persistent and calculated:
Ext.define('My.model.Value', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
{ name: 'id', type: 'auto' },
{ name: 'percentage', type: 'float' }, // values in 0..1 range
{ name: 'percentageDecimal', type: 'float', persist: false,
calculate: function(v) {
v = v.percentage;
return Ext.isNumber(v) ? v * 100.0 : v;
}
}
]
});
The percentageDecimal field is used in a grid and it is editable.
Question: how can I change my model to automatically update percentage field everytime the percentageDecimal is updated?
I use ExtJs 5.0.1.
I used #adaskos' suggestion as follows:
Ext.define('My.model.Value', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
{ name: 'id', type: 'auto' },
{ name: 'percentage', type: 'float' }, // values in 0..1 range
{ name: 'percentageDecimal', type: 'float', persist: false,
calculate: function(v) {
v = v.percentage;
return Ext.isNumber(v) ? v * 100.0 : v;
}
}
],
set: function (fieldName, value, options) {
if (Ext.isString(fieldName)) {
// single field update
if (fieldName === 'percentageDecimal') {
this.set('percentage', Ext.isNumber(value) ? 0.01 * value : value);
return;
}
} else {
// multiple fields update
if (Ext.isDefined(fieldName.percentageDecimal)) {
var data = Ext.clone(fieldName);
data.percentage = Ext.isNumber(data.percentageDecimal)
? 0.01 * data.percentageDecimal
: data.percentageDecimal;
delete data.percentageDecimal;
this.set(data);
return;
}
}
this.callParent(arguments);
}
});
I don't know if they added an automated way to do this in 5.0.1, but you can always override the set method and whenever an update occurs to percentageDecimal, you recalculate the percentage.
An alternative I prefer: if you expect enough updates but all you want is to display it in a grid, you can remove the extra computed field from the model and set your column with dataIndex: 'percentageDecimal' and change its renderer function to display it as you like (as a decimal).
Like below:
... , { text: 'Percentage', dataIndex: 'percentageDecimal'
, renderer: function (v) {
return Ext.isNumber(v) ? v * 100.0 : v;
}
}
You should use the config options depends to have this updated automatically!
And use the function convert instead of calculate (not sure if it work with calculate, i need to test)
See http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.data.field.Field-cfg-depends

Hydrate object fields

I want to get Feature object for User Stories that I got from lookback API.
But when I try to hydrate Feature I get only UnFormatted feature ID.
Can I get real Feature objects for User Stories from lookback result set?
Below the example of code that I use for retrieving data:
storeConfig: {
find: {
"_TypeHierarchy": { '$in' : [-51038] },
"Children": null
},
fetch: ["ScheduleState", "PlanEstimate", "ObjectID", "_ValidFrom", "_ValidTo", "c_BaselineDeliveryConfidence", "Name", "Feature"],
hydrate: ["ScheduleState", "c_BaselineDeliveryConfidence", "Name", "Feature"],
sort: {
"_ValidFrom": 1
},
compress: true,
useHttpPost: true
It is not possible to hydrate objects straight out of the LBAPI. However, I have been working on a helper class to do just that, using a method similar to what Nick suggested.
https://github.com/ConnerReeves/RallyHelpers/blob/master/RecordHydrator/RecordHydrator.js
Here's an example of how it's used. I'm gathering all leaf User Stories (that have an iteration assignment) and then hydrating that Initiative field:
launch: function() {
var self = this;
Ext.create('Rally.data.lookback.SnapshotStore', {
limit : Infinity,
fetch : ['Name','Iteration'],
filters : [{
property : '__At',
value : 'current'
},{
property : '_TypeHierarchy',
value : 'HierarchicalRequirement'
},{
property : 'Iteration',
operator : '!=',
value : null
},{
property : 'Children',
value : null
}]
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
self._hydrateRecords(records);
}
});
},
_hydrateRecords: function(records) {
Ext.create('CustomApp.RecordHydrator', {
fields: [{
name : 'Iteration',
hydrate : ['Name','StartDate','EndDate']
}]
}).hydrate(records).then({
success: function(hydratedRecords) {
console.log(_.groupBy(hydratedRecords, function(record) {
return record.get('Iteration') && record.get('Iteration').get('Name');
}));
}
});
}
Feature is a full object to which a user story has a reference to (via Feature attribute).
Your code which is similar to this query:
https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/111/artifact/snapshot/query.js?find={"_TypeHierarchy":"HierarchicalRequirement"}&fields=["Name","ScheduleState","PlanEstimate","Feature"]&hydrate=["ScheduleState"]
will return something like this:
{
Feature: 12483739639,
Name: "my story",
ScheduleState: "Defined",
PlanEstimate: 3
}
where 12483739639 is ObjectID of the Feature. Adding "Feature" to the hydrate will not make a difference.
If you want to get the full Feature object or some of its attributes, in your code you may use the OID of the feature and issue a separate query. You may also push those OIDs into an array and use $in operator in that second query.