ngrx selector not returning number but returning the entire state object instead - ngrx

I'm trying to make this feature selector to work. But instead of returning a number the selector returns the entire state object (in my case the CounterState)
Here is a my working example: https://stackblitz.com/edit/angular-ivy-ctypd1?file=src%2Fapp%2Fcounter.selectors.ts
I get the following outout on the page: Current Count: [object Object]
I get the following output in the console.
{counter: 1, loaded: true, loading: false}
{counter: 2, loaded: true, loading: false}
{counter: 3, loaded: true, loading: false}
I was expecting just 1,2,3 What am I missing?
Regards,

This is because you're creating a nested tree structure while registering the reducer.
StoreModule.forFeature(counterFeatureKey, { counter: counterReducer }),
This should be (or the selector needs to be tweaked):
StoreModule.forFeature(counterFeatureKey, counterReducer ),

Related

How can I persist nested redux store

I want to persist nested object of my redux store. I tried https://github.com/rt2zz/redux-persist package but it doesn't work in my case. I wonder if it's possible to define a whitelist like this: 'user.statuses.verification.isDone'
This is my store:
{
user: {
statuses: {
verification: { isPending: true, isDone: false },
activation: { isPending: true, isDone: false },
set1: { isPending: true, isDone: false, refNumber: xxx },
set2: { isPending: true, isDone: false, refNumber: xxx },
},
},
}
I want to persist only "isDone" in every of statuses and "refNumber".
Can anyone help me?
I already tried nested persist as described in redux persist documentation https://github.com/rt2zz/redux-persist#nested-persists but looks like it has a limitation to 2 levels.
I tried this https://stackoverflow.com/a/71616665 and it works perfectly. 
In this example you can see the blacklist but you just need to replace it with the whitelist.
const config = getPersistConfig({
key: 'root',
storage: AsyncStorage,
whitelist: [
'user.statuses.verification.isDone’,
'user.statuses.activation.isDone’,
'user.statuses.set1.isDone’,
'user.statuses.set1.refNumber’,
'user.statuses.set2.isDone’,
'user.statuses.set2.refNumber’,
],
rootReducer, // your root reducer must be also passed here
... // any other props from the original redux-persist config omitting the stateReconciler
})
You need to use this package: https://github.com/edy/redux-persist-transform-filter
The "issue" has already been addressed, it's more a precise implementation choice, not an issue according to the maintainers, and you have several different ways to address it:
redux-persist - how do you blacklist/whitelist nested state

Ionic and Firebase .update(): Nested Arrays are not supported

I'm having this issue while I'm trying to perform a crud update function. To put into context, this is an Ionic app with Firebase. This is an app in which the user will be able to create events and update them at a later stage if they want. However, I'm not being able to perform the update with the following error:
ERROR FirebaseError: Function DocumentReference.update() called with invalid data. Nested arrays are not supported (found in document Events/XWtRgH04iEG9IUIqMrgX)
Below are highlighted the function that will save an event after being updated and the service that contains the update function. Any help is greatly appreciated!
saveEvent(event) {
let id = event.id;
let evtSave = {
id: id,
createdAt: event['createdAt'],
createdBy: event['createdBy'],
updatedAt: Date.now(),
part: event['part'] || ['No participants'],
comments: event['comments'] || ['No comments'],
type: event['type'],
title: event['title'],
date: event['date'],
time: event['time'],
map: event['map'],
players: event['players'],
location: event['location'],
description: event['description'],
image: event['image']
};
console.log('saveEvent: ', evtSave);
this.eventServ.updateEvents(id, evtSave)
.then(res => {
this.searchEvents();
console.log('Event: ', res);
this.myAlert('Event successfully updated');
this.mode = 'listMode';
});
Below is the code contained in the service:
updateEvents(eventID, event){
return this.firestore.collection('Events').doc(eventID).update(({
id: event.id,
createdAt: event.date,
createdBy: event.createdBy,
updatedAt: Date.now(),
part: [event.part],
comments: [],
type: event.type,
title: event.title,
date: event.dateMilis,
time: event.time,
map: event.map,
players: event.players,
location: event.location,
description: event.description || 'No description...',
image: event.image || 'No image...',
})).catch((error)=>{
console.log('Error: ', error);
})
and finally a screenshot of how an event looks like in firebase:
At one place in your code you have part: event['part'] || ['No participants'], which will set part to an array of stringy, containing exactly one participant.
Later, when you save, you do: part: [event.part], which I assume can lead to the case where you will get part: [['No participants']].
This is a nested array and as firebase tells you in the error message, this is not supported in firestore.

Using Flow union types for Redux actions

Following the style of this Facebook app sample using Redux and Flow together, I made an action type in this manner:
type Action =
| { type: 'ADD_FILES', files: Array<{ id: number, file: File }> }
| { type: 'HANDLE_IMAGE_PUBLISHED', id: number, name: string }
| { type: 'SET_IMAGE_UPLOAD_PROGRESS', id: number, progress: number }
;
But I've found that when I try to process my actions with a reducer, Flow complains if I try to access the name or progress properties, saying "Property not found in object type".
That is, in my reducer, if I check that action.type === 'HANDLE_IMAGE_PUBLISHED' and then access action.name, Flow complains. And the same thing goes for for accessing action.progress property when action.type === 'SET_IMAGE_UPLOAD_PROGRESS'. Both these property accesses should be legit under their respective circumstances, as far as I can tell, but Flow complains.
Yet for some reason it's OK for me to access action.id anywhere, even though one of the types in my union doesn't specify an id property. I'm very confused.
Here is a live demo in the Flow REPL. What am I doing wrong?
This is simply a case of a type refinement invalidation:
https://flow.org/en/docs/lang/refinements/#toc-refinement-invalidations
Because you are using the value in a callback, Flow pessimistically assumes that you could have re-assigned action before the callback runs (it does not know that the map callback is called immediately). It also does not do the analysis to see that there is no place, in fact, that you re-assign it.
All that's needed is to pull the action out as a const:
export default (state: Array<ImageRecordModel> = [], action_: Action): Array<ImageRecordModel> => {
const action = action_;
(tryflow link)
You may also want to consider enabling const params in your .flowconfig. This does basically what you expect: treats all params as const:
[options]
experimental.const_params=true

meteor autocomplete server-side

I'm writing a meteor app and I'm trying to add an autocomplete feature to a search box. The data is very large and is on the server, so I can't have it all on the client. It's basically a database of users. If I'm not wrong, the mizzao:autocomplete package should make that possible, but I can't seem to get it to work.
Here's what I have on the server:
Meteor.publish('autocompleteViewers', function(selector, options) {
Autocomplete.publishCursor(viewers.find(selector, options), this);
this.ready();
});
And here are the settings I use for the search box on the client:
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
options: '',
template: Template.vLegend
}],
};
}
But I keep getting this error on the client:
Error: Collection name must be specified as string for server-side search at validateRule
I don't really understand the problem. When I look at the package code, it just seems like it's testing whether the subscription field is a string and not a variable, which it is. Any idea what the problem could be? Otherwise is there a minimum working example I could go from somewhere? I couldn't find one in the docs.
Error: Collection name must be specified as string for server-side search at validateRule
You get this error because you don't specify a Collection name in quotes.
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
collection: 'viewers', // <- specify your collection, in your case it is a "viewers" collection.
options: '',
template: Template.vLegend
}],
};
}
For more information please read here.
Hope this helps!

Data context in Meteor's Template.rendered callback randomly disappears on hot code push

Short version:
Session.get(), and Template.currentData() that are supposed to be passed to the template by the Router often turn out to be undefined in Template.<templateName>.render callback. This happens quite randomly, most often on hot code pushes, but not always, and not only on hot code pushes.
Longer version:
I'm using Iron Router to pass data context to the template appBody:
Router.route('/:_mapid', function() {
if (!isNaN(this.params._mapid)) {
Session.set('currentMap',Maps.findOne({mapid: Number(this.params._mapid)}));
this.render('appBody', {
data: function() { return Session.get("currentMap") }
});
}
});
The template then uses d3 to generate a bunch of div's, and set the dynamic page title in Template.appBody.rendered callback:
Template.appBody.rendered = function() {
Deps.autorun(function() {
d3.select("#map_body").selectAll("div").remove();
d3.select("#map_body").selectAll("div")
.data(Nodes.find({mapid: Template.currentData().mapid }).fetch(), function(d) {return d.nodeparentid;})
.enter().append("div")
.attr("id", function(d){return "node"+ d.nodeparentid})
.style("position","absolute")
.style("top",function(d) {return d.toppos+"px"})
.style("left",function(d) {return d.leftpos+"px"})
.style("width",function(d) {return d.width+"px"})
.style("height",function(d) {return d.height+"px"})
.classed("node", true)
document.title = "Map - " + Session.get("currentMap").title;
}
As you can see I try to pass the data context to the template in two different ways: by setting a global currentMap object via Session.set and by passing data key via the Router, and then accessing it via Template.currentData() method.
For some reason both of these method often fail (although I still can't figure out under what conditions). Here is a sample error I get from the browser console when trying to set a document title:
Exception from Tracker afterFlush function: Cannot read property 'title' of undefined
TypeError: Cannot read property 'title' of undefined
at http://localhost:3000/client/templates/app_body.js?47b256634607ca16879aa0ed823593aec01ee840:122:31
at Tracker.Computation._compute (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:288:36)
at new Tracker.Computation (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:206:10)
at Object.Tracker.autorun (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:476:11)
at Template.appBody.rendered (http://localhost:3000/client/templates/app_body.js?47b256634607ca16879aa0ed823593aec01ee840:117:10)
at null.<anonymous> (http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:2970:21)
at http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:1720:14
at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:2029:12)
at http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:1719:15
at Tracker.flush (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:438:11)
Any ideas on what could be causing this?

Resources