modify field value in a crossfilter after insertion - crossfilter

I need to modify a field value for all records in a crossfilter before inserting new records.
The API doesn't say anything about it. Is there a way to do that ?
Even if it's a hack that would be really useful to me.

Looking at the code, the data array is held as a private local variable inside the crossfilter function so there's no way to get at it directly.
With that said, it looks like Crossfilter really tries to minimize the number of copies of the data it makes. So callback functions like the ones passed into crossfilter.dimension or dimension.filter are passed the actual records themselves from the data array (using the native Array.map) so any changes to make to the records will be made to the main records.
With that said, you obviously need to be very careful that you're not changing anything that is relied on by the existing dimensions, filters or groups. Otherwise you'll end up with data that doesn't agree with the internal Crossfilter structures and chaos will ensue.

The cool thing about .remove is it only removes entries that match the currently applied filters. So if you create a 'unique dimension' that returns a unique value for every entry in your dataset (like an ID column), you can have a function like this:
function editEntry(id, changes) {
uniqueDimension.filter(id); // filter to the item you want to change
var selectedEntry = uniqueDimension.top(1)[0]; // get the item
_.extend(selectedEntry, changes); // apply changes to it
ndx.remove(); // remove all items that pass the current filter (which will just be the item we are changing
ndx.add([selectedEntry]); // re-add the item
uniqueDimension.filter(null); // clear the filter
dc.redrawAll(); // redraw the UI
}

At the least you could do a cf.remove() then readd the adjusted data with cf.add().

Related

Store a manipulated collection in Power Apps

(1) In my Canvas App I create a collection like this:
Collect(colShoppingBasket; {Category: varCategoryTitle ; Supplier: lblSupplier.Text ; ProductNumber: lblProductNumber.Text });;
It works - I get a collection. And whenever I push my "Add to shopping basket" button, an item are added to my collection.
(2) Now I want to sort the collection and then use the sorted output for other things.
This function sorts it by supplier. No problems here:
Sort(colShoppingBasket; Supplier)
(3) Then I want to display the SORTED version of the collection in various scenarios. And this is where the issue is. Because all I can do is manipulate a DISPLAY of the collection "colShoppingBasket" - (unsorted).
(4) What would be really nice would be the option to create and store a manipulated copy of the original collection. And the display that whereever I needed. Sort of:
Collect(colShoppingBasketSORTED; { Sort(colShoppingBasket; supplier) });; <--- p.s. I know this is not a working function
You could use the following:
ClearCollect(colShoppingBasketSorted, Sort(colShoppingBasket, Supplier))
Note that it is without the { }
This will Clear and Collect the whole colShoppingBasket sorted.
If you want to store the table in a single row in a collection, you can use
ClearCollect(colShoppingBasketSortedAlternative, {SingleRow: Sort(colShoppingBasket, Supplier)})
I wouldn't recommend this though because if you want to use the Sorted values you'd have to do something like this:
First(colShoppingBasketSortedAlternative).SingleRow -> this returns the first records of the colShoppingBasketSortedAlternative then gets the content of the SingleRow column, which in this case is a Collection
Note: You will need to replace the , with ; to work on your case

Count of the icon tab filter

I would really like to understand how to use the "count" property of the IconTabFilter for SAPUI5 to dynamically show the count of the result set of a table.
I have the following code -
<IconTabFilter
count="{DataSet/$count}">
<Table items="{DataSet}">
But the count is not filled automatically.
I am using an oData model that is bound on the view level. I do not want to make another backend request just for the counts. What am I doing wrong here? Is there a different mechanism that can be used?
I also tried using the updateFinished event on the table to then get the count and set it via JS but the event is triggered only on DOM placement of the table. In my case the table is hidden behind the IconTab and is not placed into the DOM till the first time the user clicks the tab so its useless.
Really would appreciate some insight into how to use this!
Thanks!
Okay, so what I did was I bound my information to a local model and did an oData $expand query to fetch the entire pages information in one call.
This worked out for me because I had several sets of data to be fetched. Before they were bound individually to tables, now they are all in one query.
In the .done() method of the call I just used the setCount method of the IconTabFilter to set the count as per the return data set.

Unique id for label input pairs

I'm trying to generate unique id for label & input pairs.
After googling I now know that, unlike with handlebars, there is no array #index syntax extension in spacebars yet (also anybody knows why Blaze development has been inactive since the version 0.1 for past 5 months?).
So I ended up using the JS Array .map() solution inspired by this blog post and other posts. However, this solution returns label & input pairs of objects which DOM appears to be rendering the same on 'pagination' through Session.
Live example: http://meteorpad.com/pad/NXLtGXXD4yhYr9LHC
When clicking on first set of "Non-Indexed IDs" checkboxes, then next/previous, DOM will display new set of checkboxes correctly.
However clicking on the second set of "Indexed IDs" checkboxes below, then next/previous, DOM seems to retain the same checkboxes because one selected from the previous page remains checked on the next page.
What am I doing wrong or missing?
I also put the code on github for quick testing & refinement:
The solution, which I've found by looking at the ObserveSequence source, appears to be to give your generated objects a unique field called _id (generated like {{questionId}}:{{questionIndex}}:{{choiceIndex}}). See this meteorpad: http://meteorpad.com/pad/2EaLh8ZJncnqyejSr
I don't know enough about Meteor internals to say why, but this comment seems relevant:
// 'lastSeqArray' contains the previous value of the sequence
// we're observing. It is an array of objects with '_id' and
// 'item' fields. 'item' is the element in the array, or the
// document in the cursor.
//
// '_id' is whichever of the following is relevant, unless it has
// already appeared -- in which case it's randomly generated.
//
// * if 'item' is an object:
// * an '_id' field, if present
// * otherwise, the index in the array
//
// * if 'item' is a number or string, use that value
//
// XXX this can be generalized by allowing {{#each}} to accept a
// general 'key' argument which could be a function, a dotted
// field name, or the special #index value.
When the _id is absent, it uses the index in the array, so I guess ObserveSequence assumes it's the same object with changed fields, rather than a different object, so it re-uses the old elements rather than destroying them and recreating them. I suppose the name _id is chosen so that it works well with arrays generated by .fetch() on a Minimongo cursor.
I don't know if this is documented behaviour, or if it might change in the future.

AdvancedDataGrid (grouping) quick jump to row

I have a problem with the AdvancedDataGrid widget. When the dataProvider is an ArrayCollection (of arrays), the nth array (within the collection) is also the nth row within the grid, and I can jump and display the i-th row by scripting
adg.selectedIndex = i;
adg.scrollToIndex(i);
now, when I add a Grouping, the dataProvider ends up being a GroupingCollection2, and now the index in the dataprovider's source does not correspond to the index in the adg anymore (which is understandable, because it's being grouped).
How can I select and display a row in grouped data efficiently? Currently, I have to traverse the adg and compare each found item with its data attributes in order to find the correct index of the row within the adg, and jump to it like above. This process is very slow. Any thoughts?
edited later:
We already used a caching object as Shaun suggests, but it still didn't compensate for the search times. In order to fully construct a sorting of a list of things (which this problem equates to, as the list is completely reordered by the grouping), you always have to know the entire set. In the end we didn't solve that problem. The project is over now. I will accept Shaun's answer if no one knows a better way in three days.
Depending on what values your comparing against you can store the objects in a dictionary with the lookup using the property/properties that would be searched for, this way you have a constant time look-up for the object (no need to look at every single item). Say for example your using a property called id on an object then you can create an AS object like
var idLookup:Object = {};
for(myObject in objects)
idLookup[myObject.id] = myObject;
//Say you want multiple properties
//idLookup[myObject.id]={};
//idLookup[myObject.id][myObject.otherProp] = myObject;
now say the user types in an id you go into the idLookup object at that id property and retrieve the object:
var myObject:Object = idLookup[userInput.text];
myAdg.expandItem(myObject, true);
now when you want to get an object by id you can just do
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/AdvancedDataGrid.html#expandItem()
I haven't done any thorough testing of this directly, but use a similar concept for doing quick look-ups for advanced filtering. Let me know if this helps at all or is going in the wrong direction. Also if you could clarify a bit more in terms of what types/number of values you need to lookup and if there's the possibility for multiple matches etc. I may be able to provide a better answer.
Good luck,
Shaun

Flex DataGridColumn with array of objects as data provider

I have a datagrid that uses an array of objects as the data provider. The objects are essentially key/value pairs:
{ foo:"something"}
{ bar:"hello"}
{ caca:"lorem"}
The datagrid has 2 columns. The first column is the key and the second column is the value. Right now my grid looks like:
My dataFormatter function makes sure that depending on the column (i.e. the dataField value) the correct key or value gets printed out. This works fine for displaying. However, as soon as I try and edit the value field it essentially adds a new value into the object with a key of '1'. For example, if I edit the {caca:"lorem"} object it will then contain the value {caca:"lorem",1:"new value"}.
Is there any possible way I can set the DataGridColumn so that when I edit a value it will update the value associated with the key rather than inserting a new value? I've tried using a custom item editor but it still does the insert. It seems like I need to be able to update the 'dataField' with the actual key value but I'm not sure how to do that.
Looks like you need to think about where your data is going to be stored. I would recommend listening for a CollectionEvent.COLLECTION_CHANGE event on your data model. That event object will contain info about what change occurred, and you can make any updates you need to make.

Resources