I'm trying to show a success feedback once the users are registered without error. There is an errors redux reducer object which stores errors that come from the back end. And the if statement is supposed to give the success feedback if the errors object is empty, it displays the errors if there are any, it also registers the users if there is none, but it doesn't seem to execute the if(props.errors === {}) block.
function onSubmit(e) {
e.preventDefault();
const newUser = {
fname: fname,
lname: lname,
phone: phone,
email: email,
password: password,
};
dispatch(register(newUser));
if (props.errors === {}) { //This block is not executed
setSnackOpen(true);
setFname('');
setLname('');
setEmail('');
setPhone('');
setPassword('');
}
console.log('errors :' + props.errors); //logs 'errors : [object, object]'
}
The errors reducer:
import { GET_ERRORS } from '../actionTypes/actionTypes';
const initialState = {
};
export const errorReducer = (state = initialState, action) => {
switch (action.type) {
case GET_ERRORS:
return action.payload
default:
return initialState;
}
};
Because you are comparing props.errors with {} new empty object so even though both are empty they are pointing to different memory location so if condition will return false for the statement if(props.errors === {})
You can check length of the props.errors like
if(!Object.keys(props.errors).length)
Every time you declare a new object(empty or not), it will be created with a new reference. you can run below code in you dev console. all of them will give the result false. Because obj1 is a different empty object than obj2.
var obj1 = {}
var obj2 = {}
console.log(obj1 === {})
console.log(obj2 === {})
console.log(obj1 === obj2)
false
false
false
One way to check if an object is empty is this:
Object.keys(obj1)
This will give you an array of key values from object.
so, you can check the length of the array.
const keysArray = Object.keys(obj1)
if (keysArray.length === 0){
// do something
}
This if (props.errors === {}) would never be true, as it's actually comparing their references, which are not the same.
And I would do as below, and the advantage is that it would work both for when there isn't any key, as well as for when there are some, but their values are empty.
if (!Object.keys(props.errors).some((k) => props.errors[k]))
It's helpful for when you consider {firstNameError:"", lastNameError:"" } and {} as empty. See the snippet below:
const objOne={firstNameError:"", lastNameError:"" };
const objTwo= {};
if(!Object.keys(objOne).length){
console.log("First console prints empty")
}
if (!Object.keys(objOne).some((k) => objOne[k])){
console.log("Second console prints empty")
}
if(!Object.keys(objTwo).length){
console.log("First console prints empty")
}
if (!Object.keys(objTwo).some((k) => objTwo[k])){
console.log("Second console prints empty")
}
Related
I normally can do this when I render the react component with an isLoading however if I try to use that to test that a variable is ready it complains that the map is undefined even though in the console it certainly is an array value that I am selecting. The isLoading returns undefined sometimes, and I've tried checking for if isLoading is !undefined and so here I am stuck.
const { leadsBuilder, isLoading } = useTracker(() => {
const noDataAvailable = { leadsBuilder: [] };
if (!Meteor.user()) {
return noDataAvailable;
}
const handler = Meteor.subscribe("leadsBuilder");
if (!handler.ready()) {
return { ...noDataAvailable, isLoading: true };
}
const leadsBuilder = LeadsBuilderCollection.findOne({ _id: params._id });
return { leadsBuilder };
});
if (!isLoading && leadsBuilder) {
let stateReplace = [];
leadsBuilder.inputs.map((leadInput, i) => {
stateReplace.push({ id: i, text: leadInput.name });
});
}
You're testing if leadsBuilder is truthy, but your invoking the .map on a property of leadsBuilder.
You should replace your condition by:
if(!isLoading && leadsBuilder?.inputs?.length) {
//your code
}
The ? test if the variable / property is defined, and then we use length because we want the array to not be empty
I have a problem. Imagine this mutation:
SET_USER(state, payload) {
console.log("SET USER COMMIT")
Vue.set(state.user_data, 'uid', payload.uid || payload._id)
state.user_data.display_name = payload.display_name
state.user_data.email = payload.email
state.user_data.registered_on = payload.registered_on
state.user_data.confirmed = payload.confirmed
state.user_data.interacted_tags = payload.interacted_tags
},
And now, imagine this accessing to the rootState:
test({rootState}, uid) {
console.log(uid)
console.log("uid", rootState.user.user_data.uid)
}
Although user_data.uid is NOT null, and has a value which I see using getters (which also return null in actions), this console.log returns a null value. What could be wrong?
Here's an image of the user_data in the console:
You can write custom getters for these properties, this way you'll have a more maintainable and modular function to access the vuex state and its modules.
E.g
getters: {
getUserUid: state => {
// here you can do some logs for faster debug
return state.user.user_data.uid
}
}
I keep getting payload undefined when destructuring:
let videosArray = [];
if (payload.videos) {
const {
payload: { videos }
} = action;
videosArray = videos;
}
return videosArray;
How can I check for undefined? I have tried the check below, but keep getting the error:
if (typeof payload !== "undefined") {
You just have to make sure the action is defined first, and access its parameters instead of calling payload by itself. In your example it looks as if payload was undeclared when you try to access it
function getVideos(action) {
if (action && action.payload && action.payload.videos) {
const {payload: {videos}} = action;
return videos;
}
return [];
}
console.log(getVideos()); // action undefined, expected []
console.log(getVideos({})); // payload undefined, expected []
console.log(getVideos({payload: {}})); // videos undefined, expected []
console.log(getVideos({payload: {videos: [1,2,3]}})); // expected [1,2,3]
Of course if you really wanted to complete the task with just destructuring you could simply create some default values like this:
function getVideos(action) {
const {payload: {videos=[]}={}} = action || {};
return videos;
}
console.log(getVideos()); // action undefined, expected []
console.log(getVideos({})); // payload undefined, expected []
console.log(getVideos({payload: {}})); // videos undefined, expected []
console.log(getVideos({payload: {videos: [1,2,3]}})); // expected [1,2,3]
You need to have action defined like this const action = {payload: {videos: ["Matrix", "Star Wars"]}}
And you can check that payload is not undefined like this if(action && action.payload) then you could do your destructing operation.
You could take a check and a default value without destructuring.
function getVideos(action) {
return action && action.payload && action.payload.videos || [];
}
console.log(getVideos()); // action undefined, expected []
console.log(getVideos({})); // payload undefined, expected []
console.log(getVideos({ payload: {} })); // videos undefined, expected []
console.log(getVideos({ payload: { videos: [1, 2, 3] } })); // expected [1, 2, 3]
I have a function that takes in filter values and the passes a network request in my Angular app. Because I'm running into issues where the network request is made before the filters arrive, I've tried setting up some conditional checks to not make the network request until the filter values are available. It's not the ideal solution, but I'm trying to get something working (for now) on short notice.
This is my code. First, I set up a function to check if an object is empty or not. I do this because I want to only fire my network request once I have a non-empty object. And the object will be non-empty once the filter values have been applied. Here's the code:
isEmptyObj(obj) {
return Object.keys(obj).length === 0;
}
public async onFilterReceived(values) {
let filters = {};
if (!values) return;
if (values) {
filters = values;
}
this.route.params.subscribe(
(params: any) => {
this.page = params['page'];
}
);
let fn = resRecordsData => {
this.records = resRecordsData;
};
// Make request IF filters is NOT empty object (i.e. it has values)
if (!this.isEmptyObj(filters)) {
console.log('filter values within cond call: ', filters); // should not be empty
console.log('firstName within cond call: ', filters['firstName']); // should not be empty in this case as I selected a firstName value
console.log('should be false: ', this.isEmptyObj(filters)); // should be false
this.streamFiltersService.getByFilters(
this.page - 1, this.pagesize, this.currentStage, this.language = filters['language'], this.location = filters['location'],
this.zipcode = filters['zip'], this.firstName = filters['firstName'], this.lastName = filters['lastName'],
this.branch = filters['branch'], fn);
}
}
Clearly this is not working as intended. When I look at what logs to the console from WITHIN the conditional section, I see 'filters' and 'firstName' as empty values. In other words, my conditional check is not working as I intended it to. What am I missing here? How could I approach this differently so that the network request is only made once I have the values?
By the way, when I console.log values, this is what I get:
{zip: Array(0), firstName: Array(0), lastName: Array(0), language: Array(0), location: Array(0), …}
By the way, earlier console logs I used demonstrate that initially filters is an empty object. It's only I assign values to filters that it is no longer an empty object.
So, why then is my conditional check before the network request working as intended?
Within the if conditional I see this console.log:
filter values within cond call: {zip: Array(0), firstName: Array(0), lastName: Array(0), language: Array(0), location: Array(0), …}
Help me understand how this is happening based on my above code.
The first issue is that the method isEmptyObj(obj) to check for keys isn't working as you are expecting. This is because the sample values you provided:
{zip: Array(0), firstName: Array(0), lastName: Array(0), language: Array(0), location: Array(0), …}
Even though it is only empty arrays, that still has keys, so that method isEmptyObj will return false for that sample value. The only time it would return false would be for a plain empty object {}.
function isEmptyObj(obj) {
return Object.keys(obj).length === 0;
}
console.log(isEmptyObj({}));
console.log(isEmptyObj({ zips: [] }));
So change that to something like where you filter "falsy" values based on length:
function isEmptyObj(obj) {
return Object.keys(obj).map(key => obj[key]).filter(v => v.length > 0).length === 0;
}
console.log(isEmptyObj({ }));
console.log(isEmptyObj({ zip: [] }));
The next issue is the flow of onFilterReceived. It does not need to be an async, method, also this.route.params.subscribe() will effectively always execute after the rest of the code in the method. Try the following by moving everything into subscribe() at the very minimum. Keep in mind you need to subscribe() to an HTTP calls to actually get them to execute:
public onFilterReceived(values) {
let filters = {};
if (!values) return;
if (values) {
filters = values;
}
this.route.params.subscribe((params: any) => {
this.page = params['page'];
let fn = resRecordsData => (this.records = resRecordsData);
// Make request IF filters is NOT empty (i.e. it has values)
if (!this.isEmptyObj(filters)) {
this.streamFiltersService.getByFilters(
this.page - 1, this.pagesize, this.currentStage, this.language = filters['language'],
this.location = filters['location'],
this.zipcode = filters['zip'], this.firstName = filters['firstName'], this.lastName = filters['lastName'],
this.branch = filters['branch'],
fn
)
.subscribe(results => console.log(results));
}
});
);
}
You can use operators such as switchMap, takeWhile, and tap to streamline the Observable portion:
import { switchMap, takeWhile, tap } from 'rxjs/operators';
// ..
public onFilterReceived(values) {
let filters = {};
if (!values) return;
if (values) {
filters = values;
}
this.route.params.pipe(
tap((params: any) => this.page = params['page']),
takeWhile(_ => !this.isEmptyObj(filters)),
switchMap((params: any) => {
let fn = resRecordsData => (this.records = resRecordsData);
return this.streamFiltersService.getByFilters(
this.page - 1, this.pagesize, this.currentStage, this.language = filters['language'],
this.location = filters['location'],
this.zipcode = filters['zip'], this.firstName = filters['firstName'], this.lastName = filters['lastName'],
this.branch = filters['branch'],
fn
);
});
).subscribe(results => console.log(results));
}
Hopefully that helps!
I have an array containing one object of this form :
Array = [ { type: type, message: message } ]
I keep getting ESLint errors asking me to use object destructuring and array destructuring.
Currently my code looks like this :
let type=null;
let message=null;
if (data.length > 0) {
({ type, message } = data[0]);
}
So far this works and my variables are assigned correctly, however I am still getting the "Use array destructuring" message from ESLint.
Any help with this would be appreciated. Thank you
You can destructure the array:
let type=null;
let message=null;
if (data.length > 0) {
[{ type, message }] = data;
}
The code above is a shorter version of:
[ firstElement ] = data; // array destructruring
({ type, message } = firstElement); // object destructuring
Faly's way is good. You can also use default values when destructuring:
function test(label, data) {
// 1 -----------------------------vvvvv
let [{type = null, message = null} = {}] = data;
// 2 -----^^^^^^^---------^^^^^^^
console.log(label, type, message);
}
test("test1: ", []);
test("test2: ", [{type: "t"}]);
test("test3: ", [{type: "t", message: "m"}]);
That works because if data.length is 0, data[0] is undefined, and so triggers use of the default value {} (1) for the array part of that; within the object part of that, we use null (2) to handle any missing values on the object as well.
EsLint wants you to write
let type = null;
let message = null;
if (data.length > 0) {
[{ type, message }] = data;
}
which destructures the first item of an iterable data into the {type, message} target. (More items are ignored).
I would however recommend to use default values for the empty case:
const [{type, message} = {type:null, message:null}] = data;
or also
const [{type = null, message = null} = {}] = data;