i have the following state:
state = {
profile: {
name: { value: '', isRequired: true, hasError: false, order: 1 },
industry: { value: '', isRequired: false, hasError: false, order: 2 },
address: { value: '', isRequired: false, hasError: false, order: 3 },
crn: { value: '', isRequired: true, hasError: false, order: 4 },
website: { value: '', isRequired: false, hasError: false, order: 5 },
employeesNbr: { value: '', isRequired: true, hasError: false, order: 6 },
phoneNumber: { value: '', isRequired: true, hasError: false, order: 7 },
userRole: { value: '', isRequired: true, hasError: false, order: 8 },
personCheck: {
value: false,
isRequired: true,
hasError: false,
order: 9,
},
},
showModal: {
modal: { error: false },
},
};
And I have the following section of a submit handler
if (
!profile.name.hasError &&
!profile.crn.hasError &&
!profile.employeesNbr.hasError &&
!profile.phoneNumber.hasError &&
!profile.userRole.hasError &&
profile.personCheck.hasError
) {
showModal.modal.error = true;
}
What ways can I use to enhance the if statement?
Thank you
In the following way it would be optimized since as soon as one of the profile.* props has hasError to true would "returns" (due the or instead of and): the and (&&) needs to evaluate all the conditions where the or || it stops as soon as one is true.
You can also probably remove the if statement:
showModal.modal.error = profile.personCheck.hasError && !(
profile.name.hasError ||
profile.crn.hasError ||
profile.employeesNbr.hasError ||
profile.phoneNumber.hasError ||
profile.userRole.hasError)
Do you like it better that way?
if (
!(profile.name.hasError ||
profile.crn.hasError ||
profile.employeesNbr.hasError ||
profile.phoneNumber.hasError ||
profile.userRole.hasError) &&
profile.personCheck.hasError
) {
showModal.modal.error = true;
}
or if you prefer something more fancy:
if (
(Object.entries(state.profile)
.filter(prop => prop[1].hasError).length === 1) && // there is exactly one error
state.profile.personCheck.hasError // personCheck has error
)
It would be easy to simplify it into a loop if you were doing the same check for all properties in the profile. Doing a different check for personCheck makes it hard to reduce it like that.
You can use an array for all the properties that you want the same check on.
if (profile.personCheck.hasError &&
["name", "crn", "employeesNbr", "phoneNumber", "userRole"].every(prop => !profile[prop].hasError)) {
showModal.modal.error = true;
}
Related
I have a array of object
const formFields = {
firstName: {
value: '',
label: 'FirstName',
type: 'text',
placeHolder: 'Enter Firstname',
helperText: '',
required: false,
error: false
},
lastName: {
value: '',
label: 'LastName',
type: 'text',
placeHolder: 'Enter LastName',
helperText: '',
required: false,
error: false
},
emailID: {
value: 'sfas',
label: 'emailID',
type: 'email',
placeHolder: 'Enter Email ID',
helperText: '',
required: true,
error: false
},
password: {
value: '',
label: 'password',
type: 'password',
placeHolder: 'Enter password',
helperText: '',
required: true,
error: false
},
confirmPassword: {
value: '',
label: 'confirmPassword',
type: 'password',
placeHolder: 'Enter Confirm Password',
helperText: '',
required: true,
error: false
}
}
const [inpValues, setInpValues] = useState(formFields)
Filter and Update
I am trying to filter the object by values where required === true and value.length === 0
and update the filtered array values like helperText = "Enter the " + label and error = true
const validate = () => {
const requiredFields = Object.values(inpValues).filter((fields) => {
if (fields.required === true && fields.value.length === 0) {
//How to setInpValues
//setInpValues(...inpValues, fields: { fields.helperText = "Enter the " + fields.label})
//fields.error = true
}
})
}
<MyButton color="primary" handleOnClick={validate} text="SIGN UP"></MyButton>
The validate function should be, this will also take care of reverting the error back in case of validity.
const validate = () => {
let newValues={...inpValues}
const requiredFields = Object.keys(newValues).forEach((key) => {
let field=newValues[key];
if (field.required === true && field.value.length === 0) {
field.helperText=`Enter the ${field.label}`;
field.error = true;
newValues[key]= field;
}else{
newValues[key].error=false;
newValues[key].helperText='';
}
})
setInpValues(newValues);
}
The array filter callback function expects you to return a boolean that says if the current value should be filtered out or not. I think something like
const validate = () => {
const requiredFields = Object.values(inpValues).filter((fields) => {
if (fields.required === true && fields.value.length === 0) {
return true;
}
return false;
})
setInpValues(requiredFields)
}
this would solve it. In this example you first filter the input values and when they're filtered, you set them to the state. This sets inputValues to be all the required fields, every time you click.
I have two arrays
const condition = [
{ iosSend: true },
{ androidSend: true }
]
const myArray = [
{
androidSend: false,
iosSend: true,
macosSend: false,
id: 1
},
{
androidSend: true,
iosSend: false,
macosSend: false,
id: 2
},
{
androidSend: true,
iosSend: true,
macosSend: false,
id: 3
},
{
androidSend: false,
iosSend: false,
macosSend: true,
id: 4
}
]
Where I want to filter myArray with the following conditions:
Return a array with objects that has at least one of the keys of object inside condition array Equals false.
I mean, in the example, the return should return an array
with objects with ids 1, 2 and 4
Which is the best way to do this?
The following is an example of filtering if you wanted all items that match any condition.
const condition = {
iosSend: false,
androidSend: false
};
const myArray = [
{
androidSend: false,
iosSend: true,
macosSend: false,
id: 1
},
{
androidSend: true,
iosSend: false,
macosSend: false,
id: 2
},
{
androidSend: true,
iosSend: true,
macosSend: false,
id: 3
},
{
androidSend: false,
iosSend: false,
macosSend: true,
id: 4
}
];
const conditions = Object.entries(condition);
const filteredArr = myArray.filter(o => {
for (const [key, val] of conditions) {
if (key in o && o[key] == val) return true;
}
return false;
});
console.log(filteredArr);
#EDIT:
I changed conditions to be either iosSend false or androidSend false after clarifying comment from author
I have a set of input fields with checkboxes where the user can choose an option. Then it's saved in local storage as true if checked and false if not. The localStorage under key "passengers" looks like this:
0: {name: "", child: false, luggage: true}
1: {name: "", child: true, luggage: false}
2: {name: "", child: false, luggage: true}
3: {name: "", child: true, luggage: false}
I want to count occurrences of true and store as a number in a variable
public luggageCounter: number;
I was trying to use
this.luggageCounter = countTrue([this.passengers[i].luggage]], true)
console.log(this.luggageCounter)
and const countTrue = (arr, val) => arr.reduce((a, v) => (v === val ? a +1 : a), 0)
but both of these solutions don't work. I was also thinking about making it easier and toggling the value from HTML by adding code below with [ngClass] and binding it with method in component.ts but also with no success.
<div>Extra luggage: {{ passengers[i].luggage ? 'Yes' : 'No' }}<div>
Any ideas how to make this simple task work? I'm out of ideas :)
Please try the following solution
const data = [
{ name: "", child: false, luggage: true },
{ name: "", child: true, luggage: false },
{ name: "", child: false, luggage: true },
{ name: "", child: true, luggage: false },
];
const total = data.reduce((previousValue, currentValue) => {
if (currentValue.luggage) {
previousValue += 1;
}
return previousValue;
}, 0);
console.log(total);
See
Array.prototype.reduce()
I have a config.ts file with following content:
export const keyOrders: {} = {
"aa": { active: true, order: 0 },
"bb": { active: true, order: 1 },
"cc": { active: true, order: 2 },
"dd": { active: true, order: 3 },
"ee": { active: false, order: 4 },
"ff": { active: true, order: 5 }
};
I am trying to push to array if active is only true. I have tried following code which is pushing key if active is true but if active is false then it is returning "undefined"
public keys = [];
public keyOrders = keyOrders;
ngOnInit() {
this.keys = Object.entries(this.keyOrders).map((a: any) => {
if(a[1].active == 'true') {
return a[0];
}
});
}
Use filter followed by map.
If you want to sort the items based on their order property, use sort before map.
filter will only keep items passing the predicate, in this case a truthy active property. Then map will map this array to the keys.
In your case, using map will give you an array of the same length, you must filter it first.
type Order = { active: boolean, order: number };
const keyOrders: { [key: string]: Order } = {
"aa": { active: true, order: 0 },
"bb": { active: true, order: 1 },
"cc": { active: true, order: 2 },
"dd": { active: true, order: 3 },
"ee": { active: false, order: 4 },
"ff": { active: true, order: 5 }
}
this.keys = Object.entries(this.keyOrders)
.filter(([_, val]) => val.active)
.sort((a, b) => a[1].order - b[1].order)
.map(([key, _]) => key);
For the types to work out, Object.entries() must be recognized by Typescript, for this, add "lib": [ "es2017.object" ] in your tsconfig.json file.
Here is a JavaScript demo (types stripped):
const keyOrders = {
"aa": { active: true, order: 0 },
"bb": { active: true, order: 1 },
"cc": { active: true, order: 2 },
"dd": { active: true, order: 3 },
"ee": { active: false, order: 4 },
"ff": { active: true, order: 5 }
};
const keys = Object.entries(keyOrders)
.filter(([_, val]) => val.active)
.sort((a, b) => a[1].order - b[1].order)
.map(([key, _]) => key);
console.log(keys);
How to check diffrence between two Objects and add missing values?
Example: https://jsfiddle.net/aca0hdv9/
var defaultOptions = {
monit : {
map:{
googleMap: false
},
vehiclesList: {
rightSide: false,
number: true,
driver: true,
note: true,
},
vehicleCloud: {
speed: true,
date: true,
alarms: true,
fuelsCloud: true
},
driverCloud: true
};
var userCacheOptions = {
monit : {
// Missing map options
vehiclesList: {
rightSide: false,
number: false,
driver: false
// Missing note option
},
vehicleCloud: {
speed: true,
date: true,
alarms: true,
fuelsCloud: true
},
// Missing driverCloud option
}
};
I don't want to assign default values, i just want add missing values. Any idea how to do this in the least complicated way?
You can use Object.keys to get all ennumerable keys. From there, you simply have to iterate over them.
var defaultOptions = {
monit: {
map: {
googleMap: false
},
vehiclesList: {
rightSide: false,
number: true,
driver: true,
note: true,
},
vehicleCloud: {
speed: true,
date: true,
alarms: true,
fuelsCloud: true
},
driverCloud: true
}
};
var userCacheOptions = {
monit: {
// Missing map options
vehiclesList: {
rightSide: false,
number: false,
driver: false
// Missing note option
},
vehicleCloud: {
speed: true,
date: true,
alarms: true,
fuelsCloud: true
}
// Missing driverCloud option
}
};
function fillBlanks(receiver, giver) {
var receiverkeys = Object.keys(receiver);
var giverkeys = Object.keys(giver);
for(var i = 0; i < giverkeys.length; i++) {
if(typeof receiver[giverkeys[i]] != typeof giver[giverkeys[i]]) {
receiver[giverkeys[i]] = giver[giverkeys[i]];
}
if(receiver[giverkeys[i]] != giver[giverkeys[i]]) {
receiver[giverkeys[i]] = giver[giverkeys[i]];
}
}
}
fillBlanks(userCacheOptions.monit, defaultOptions.monit);
console.log(userCacheOptions.monit);
You could iterate over the keys and check for objects and call the function recursive with the new objects to check. If a value is missing, then set it to the default value.
function setDefault(user, def) {
Object.keys(def).forEach(function (k) {
if (def[k] !== null && typeof def[k] === 'object') {
if (!(k in user)) {
user[k] = {};
}
setDefault(user[k], def[k]);
return;
}
if (!(k in user)) {
user[k] = def[k];
}
});
}
var defaultOptions = { monit: { map: { googleMap: false }, vehiclesList: { rightSide: false, number: true, driver: true, note: true, }, vehicleCloud: { speed: true, date: true, alarms: true, fuelsCloud: true }, driverCloud: true } },
userCacheOptions = { monit: { vehiclesList: { rightSide: false, number: false, driver: false }, vehicleCloud: { speed: true, date: true, alarms: true, fuelsCloud: true }, } };
setDefault(userCacheOptions, defaultOptions);
console.log(userCacheOptions);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would do this job as follows; It recursively iterates and modifies the userCacheOptions object at place.
var defaultOptions = {
monit : {
map:{
googleMap: false
},
vehiclesList: {
rightSide: false,
number: true,
driver: true,
note: true,
},
vehicleCloud: {
speed: true,
date: true,
alarms: true,
fuelsCloud: true
},
driverCloud: true
}
};
var userCacheOptions = {
monit : {
// Missing map options
vehiclesList: {
rightSide: false,
number: false,
driver: false
// Missing note option
},
vehicleCloud: {
speed: true,
date: true,
alarms: true,
fuelsCloud: true
},
// Missing driverCloud option
}
};
function restoreMissing(def,obj){
Object.keys(def).map(k => (typeof def[k] === "object" &&
typeof obj[k] === "object") ? restoreMissing(def[k],obj[k])
: !obj[k] && (obj[k] = def[k]));
return obj;
}
console.log(restoreMissing(defaultOptions,userCacheOptions))
This is the pattern that you want to follow, you just add the appropriate actions for each check.
if(!(defaultOptions.equals(userCacheOptions))){
//check for userCacheOptions if the value is set
//if its not set then set it as you want
if(!(userCacheOptions.getGoogleMap().isSet())){
userCacheOptions.setGoogleMap("whatever you want to set");
}
//same each variable etc
}