Quickly toggling switch causes UI flicker (Firestore) - react-native

Performing two quick "switch toggles" causes a flicker because React-Native Switch updates the UI for second-switch element before Firestore DB completes the first switch update.
I have a collection of tasks, where each task has the following schema:
task : {
shared: {
sample_user_id_1: true,
sample_user_id_2: false
}
}
Because Firestore returns a full document snapshot (and not just a specific part of document that was updated), I see two solutions here to remove the flicker:
1) Only dispatch & pipe the change that was updated, essentially only listening to part of the document at a time (dispatch a state change independent of Redux-Firestore) eg:
if(newValue.shared[user_id_1] !== oldState.shared[user_id_1])
dispatch(manualShareUpdate(user_id_1));
This solution does not seem scalable.
2) Change Data structure such that each "shared" bit is stored independently of other shared bits eg.
task : {
id: task_1
}
New "task_shared" collection for each task, shared pair
task_shared : {
task_id: sample_task_id
user_id: sample_user_id,
shared: true
}

Related

My Vuex getter is not getting automatically updated.. how I can debug it?

I'm using Vuex with a getter that filters a lot of data and then some components present it to the user grouped by status. The user can increment the visible count of elements per status by 5. How many items are visible currently is on the Vuex store and a getter uses this to create a "View object".
When I update this visibility object the getter is no rerun so something in the dependency tracking went south. I'm not adding or deleteing properties, still I'm using Vue.set(...) just to be sure.
This is the mutation that increments the visible amount of items for a status:
viewMore(state, status) {
console.log('viewMore')
const current = state.visibility.statuses[status]
Vue.set(state.visibility.statuses, status, current + 5)
}
This mutation is running well and I can see in the developer tools how the visibility increments reactively with every commit. Now here is the getter that depends on this data:
visibleProspects(state, getters) {
console.log('visibleProspects')
let result = {}
for (const status in getters.sourceData) {
if (!result[status]) {
result[status] = { prospects: [] }
}
getters.sourceData[status].forEach(function(prospect) {
if (result[status].prospects.length < state.visibility.statuses[status])
result[status].prospects.push(prospect)
})
}
return result
}
What this does is traverses a complex getter named sourceData (not shown here for brevity) and then depending on how many visible items there are it returns a new structure with that maximum in an array. visibleProspects is then used by my components and everything runs fine the first time or if a update the data that sourceData computes (e.g adding / editing / deleting a prospect).. but no matter what I do modifying state.visibility.statuses is not forcing visibleProspects to recompute.
How can I debug this?
You can make deep copy to make it reactive (using JSON.parse(JSON.stringify())
viewMore(state, status) {
console.log('viewMore')
const current = state.visibility.statuses[status]
state.visibility.statuses[status] = current + 5
state.visibility = JSON.parse(JSON.stringify(state.visibility))
}
#ittus 's answer should work. But the clone operation would be heavy if your state is big.
alternatively, you may try using Vue.set on the root state state.visibility instead. This should make the reactivity works as expected.
Vue.set(state.visibility, 'statuses', {
...state.visibility.statuses,
[status]: current + 5
})

dijit.Tree not collapsing when reloaded

I have implemented a dijit tree with checkboxes as per the implementation provided on http://jsfiddle.net/5QcFY/14/ and that is working perfectly fine. I am displaying the tree on dialogue box. There are "categories" as parent nodes and "types" as the children nodes. Initially all the parents nodes are displayed collapsed. Once user selects options from children nodes from tree and closes the dialogue box, the selected items are getting passed to the further processing logic.
Below is my implementation:
typeTreeHandle = new dijit.Tree({
store: dataStore,
id: "docTree",
showRoot: false,
autoExpand: false,
_createTreeNode: function(args) {
var tnode = new dijit._TreeNode(args);
tnode.labelNode.innerHTML = args.label;
//As parent nodes don't need checkboxes
if (!args.isExpandable)
{
var cb = new dijit.form.CheckBox();
cb.set('checked', false);
cb.placeAt(tnode.labelNode, "first");
//To store reference of checkbox object to destroy afterwards.
checkBoxArr.push(cb);
dojo.connect(cb, "onChange", function() {
var treeNode = dijit.getEnclosingWidget(this.domNode.parentNode);
dojo.publish("/checkbox/clicked", [{
"checkbox": this,
"item": treeNode.item}]);
});
}
return tnode;
}
}, "myTree");
Now the issue is: when the user again open the dialog box, the previously expanded categories are still shown expanded. Because of which the loading of elements of tree gets slower. Even if I close the browser window and open again, I can still see the categories previously expanded. I tried destroying the references of the objects created for the checkboxes, but still the problem continues.
Any pointer related to this issue would be really appreciated.
The persist property is what you are looking for, it seems:
Enables/disables use of cookies for state saving.
By default, a Tree will remember which branches were opened/closed. To
use this feature you must specify an id for the Tree. To disable the
feature, set the “persist” parameter to false.
http://dojotoolkit.org/reference-guide/1.10/dijit/Tree.html#persistence
Somewhat confusingly, the API docs have the following to say about the autoExpand property (which I see you've tried already):
Fully expand the tree on load. Overrides persist.
It appears this is only true for autoExpand: true. Using persist: true (which is the default) will override autoExpand: false too, as you have seen.
http://jsfiddle.net/5QcFY/336/

Can't obtain iteration 'Theme' in Rally app (2.0RC3)

I'm modifying the IterationSummary app from the 2.0RC3 SDK, and adding more iteration info to it. For some reason, I am not able to retrieve the 'Theme' for the iteration, although I am able to query for other fields from the iteration object. Starting with the sample, I simply added the following lines #192
{
cls: 'theme',
html: iteration.get('Theme')
},
I can get 'Name' but I can't get the 'Theme' value even though it is clearly set on the iteration, and I verified that value using the REST API to query that same iteration. And querying other fields such as 'Name' works well. Any idea why 'Theme' is not being returned?
Do you fetch 'Theme' ?
You may see a general example that builds a grid of iterations that fall within a release (selected in the releasecombobox) that has Theme column populated as long as an iteration has a theme entered is in this github repo.
This example is different from the IterationSummary app because in my example I explicitly create Rally.data.wsapi.Store for Iteration object and fetch Theme.
Customizing the IterationSummary app will still require explicit fetching of Theme field, but you are correct that it is not obvious from the IterationSummary app how other fields are being fetched, e.g. State of iteration. The iteration object in that app is returned from this.getContext().getTimeboxScope().getRecord() and if you print out that object in the console, theme will be empty. The fields that exist on this.getContext().getTimeboxScope().getRecord() are limited and cannot be customized for performance reasons.
In order to modify this app to display Theme, the Iteration model has to be accessed and Theme fetched explicitly. Here are the steps I took to modify the app:
added getTheme function:
getTheme: function(){
var iteration = this.getContext().getTimeboxScope().getRecord();
return iteration.self.load(iteration.getId(), {
fetch: ['Theme']
});
}
In rc3 every time when we have a record, .self will give its model, so there is no need to do this manually:
Rally.data.ModelFactory.getModel({
type: 'Iteration',
//...
Note fetch: ['Theme']
Next, inside _addContent method getTheme() is called
return Deft.Promise.all([this.getTheme(), this.calculateTimeboxInfo()]).then({
success: function(results) {
var theme = results[0].get('Theme');
and then finally theme variable's value is passed to:
{
cls: 'theme',
html: theme
}
The full code is available in this github repo.

Rally grid color rows based on model

I have a rallygrid that is configured to display two models: PortfolioItem/Feature and PortfolioItem/Rollup. I want to color them in the grid to differentiate them. I am not garunteed that they will alternate in the grid, or anything like that. I just want to apply a subtle color to the rollups to differentiate them visually.
Can anyone think of an easy way to achieve this?
I have tried:
viewConfig: {
getRowClass: function(record, index, rowParams, store) {
console.log('record',record); // nothing logged in console
console.log('index',index);
return 'colorCodeGrid'; // class never added
}
},
[EDIT]
viewConfig: {
stripeRows: false, // rows are no longer striped
getRowClass: function(record, index, rowParams, store) {
console.log('record',record); // still nothing logged in console
console.log('index',index);
return 'colorCodeGrid'; // class never added
}
},
It is strange to me that the viewConfig does correctly un-stripe the rows, but the getRowClass never gets called. I thought maybe just the viewConfig as a whole was not being used in the case of a rallygrid.
Your approach above with the viewConfig should work- I am going to file a defect on this. The root cause is that the Rally.ui.grid.GridView is blowing away the getRowClass function in its constructor (for internal browser testing purposes- ugghh) rather than checking if there was one supplied and calling that as well.
You can see it the source for the constructor here: https://developer.help.rallydev.com/apps/2.0rc1/doc/source/GridView.html#Rally-ui-grid-GridView
You should be able to work around it by just re-overriding the function before the view is rendered.
[EDIT by asker]
Added the following to the grid, and it worked:
listeners: {
beforerender: function(cmp) {
console.log('beforerender');
console.log('view',cmp);
cmp.view.getRowClass = function(record, index, rowParams, store) {
console.log('record',record); // still nothing logged in console
console.log('index',index);
return 'colorCodeGrid'; // class never added
};
}
},
UPDATE:
I just fixed this in the nightly build, so this should no longer be an issue in public sdk builds beginning with the next public release after 2.0rc2.

Dojo Tree Refresh

Using Dojo 1.3, after adding a child (i.e. folder or item) to a tree, is there a way to have it reflected immediately via refresh or some other method?
From the official Dojo manual
Updating a Tree
People often ask:
how do I update a tree (adding or
deleting items?)
You can't update the
tree directly, but rather you need to
update the model. Usually the model is
connected to a data store and in that
case you need to update the data
store. Thus, you need to use a data
store that allows updates (through
it's official API), like
dojo.data.ItemFileWriteStore.
how do I refresh a Tree from the
store?
This isn't supported. The store
needs to notify the tree of any
changes to the data. Currently this is
really only supported (out of the box)
by dojo.data.ItemFileWriteStore, as
setting up a client-server dojo.data
source where the server notifies the
client whenever the data has changed
is quite complicated, and beyond the
scope of dojo, which is a client-only
solution.
Say, if your model has the query `{type:'continent'} - meaning any items with this property are top-level-items, then the following will model extension will monitor changes and refresh the tree's view
var dataStore = new ItemFileWriteStore( { ... });
new Tree({
store: dataStore,
model: new ForestModel({
onNewItem: function(item, parentInfo){
if(this.store.getValue(item, 'type') == 'continent'){
this._requeryTop();
}
this.inherited(arguments);
}
}
});
This should in turn call childrenChanged in the tree and update it every time a new item is added.
See model reference
As an addition, if the item added is not a toplevel item, an immediate update should be doable with this statement. parent is the treenode which has had an item added to its children.
tree._collapseNode(parent);
parent.state = 'UNCHECKED';
tree._expandNode(parent);
A more or less 'standard' refresh of the tree can be achieved by following. Reason for it not being added to base implementation, i think is because it will break the linkage with DnD features on a tree
dojo.declare("My.Tree", [dijit.Tree], {
// Close the store? (So that the store will do a new fetch()).
reloadStoreOnRefresh : true,
update: function() {
this.model.store.clearOnClose = this.reloadStoreOnRefresh;
this.model.store.close();
// Completely delete every node from the dijit.Tree
delete this._itemNodesMap;
this._itemNodesMap = {};
this.rootNode.state = "UNCHECKED";
delete this.model.root.children;
this.model.root.children = null;
// Destroy the widget
this.rootNode.destroyRecursive();
// Recreate the model, (with the model again)
this.model.constructor(this.model)
// Rebuild the tree
this.postMixInProperties();
this._load();
}
}
);
I've solved this WITHOUT needing the refresh.
_refreshNodeMapping: function (newNodeData) {
if(!this._itemNodesMap[newNodeData.identity]) return;
var nodeMapToRefresh = this._itemNodesMap[newNodeData.identity][0].item;
var domNode = this._itemNodesMap[newNodeData.identity][0].domNode;
//For every updated value, reset the old ones
for(var val in newNodeData)
{
nodeMapToRefresh[val] = newNodeData[val];
if(val == 'label')
{
domNode.innerHTML = newNodeData[val];
}
}
}