I've got data like this:
this.registrations = [{
event: "Juniors 18s",
day: "Friday",
group: "nonpro",
players: [{
first: "Mary",
last: "Mack",
email: "marymack#dressedinblack.com",
phone: "8888675309",
signed: false,
waivers: [{
has_signed: true,
token: "ab",
url: "somesite.com",
signatureUrl: "someothersite.com",
message: "Minor waiver"
},
{
has_signed: true,
token: "ab",
url: "somesite.com",
signatureUrl: "someothersite.com",
message: "Parental waiver"
}
]
},
{... another record like that one}
]
Is there a way to display if each player has signed all the waivers? I know there is a .every function but I'm not sure how to use it with this nested data structure.
I was thinking something like below, but it didn't work:
this.registrations.has_signed = this.registrations.waivers.every( waiver => waiver.has_signed === true )
Then I tried this one, which at least seems like it might be closer to a win (but not quite). the players.signed property isn't used, but someone put it in there as false by default, so I'd love to use it:
this.registrations.forEach(reg => {
reg.players.forEach(p => {
if (p.waivers.every(waiver => waiver.has_signed === true)) {
p.signed = true;
} else {
p.signed = false;
}
return reg;
});
});
This snippet should do the required task.
const modifiedPlayers = this.registrations.map(reg => reg.players).map(player => {
player.signed = player.waivers.every(waiver => waiver.has_signed);
return player;
});
this.registrations.players = modifiedPlayers;
this.registrations.has_signed = false;
this.registrations.forEach(registration =>
registration.players.forEach(player =>
this.registrations.has_signed = player.waivers.every(waiver => waiver.has_signed)
)
);
You have to loop the outer arrays first to get to the waivers and use every to find out the has-signed.
Related
I have this state
this.state = {
dropdown1: false,
dropdown2: false,
dropdown3: false
}
I want to access to these dropdowns in state using this.setState but the number after 'dropdown' comes from API
onMaca = (ev) => {
this.setState({
dropdown + ev: true
})
}
So I want the key to be dynamic 'dropdown1' for example.
Thanks for your answers
you can access the object property like this object['property name']
onMaca = (ev) => {
this.state['dropdown' + ev]= true;
this.setState({
...this.state
})
}
https://codezup.com/add-dynamic-key-to-object-property-in-javascript/
You can use any of these to set key dynamically. I will try to update the answer with an example in a while for setState.
The state is a JS object, so you can get its keys as usual, like so:
const stateKeys = this.state.keys()
Now you have an array: [ "dropdown1", "dropdown1", "dropdown1" ]
One way to use it would be:
const keysMap = statekeys.map(( item, i ) => return {
key: item,
idx: i,
number: item.replace( /dropdown/, '' )
}
keysMap will look like so: [ { key: 'dropdown1', idx: 0, number "1" }, { key: 'dropdown1', idx: 1, number "2" }, { key: 'dropdown1', idx: 2, number "3" } ]
You can query keysMap for a given dropDownNumber like so:
let k = keysMap.find( kmap => kmap.key = dropDownNumber )
To set the dropdown's state:
this.setState({ k: <whatever> })
I have large array of objects and filtered the objects based on the userID. Here is the code below.
const filteredArr = LargeArr.Items.reduce(
async(acc, { attributes: { dob, name, picture} = { dob: null, name: null, picture: null }, userID }) => {
let pic = null;
if (picture) { pic = await getPic(picture); } // async here
acc[userID] = { name, userID, pic, dob };
return acc;
}, {});
Expected Output :
{
'1595232114269': {
name: 'Mark Status',
userID: '1595232114269',
picture: 'mark-status.jpg',
dob: '2020-08-10'
},
'48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d23d': {
name: 'Jack Thomas',
userID: '48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d23d',
picture: 'jack-thomas.jpg',
dob: '1990-12-20'
},
'48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d47p': {
name: 'Petro Huge',
userID: '48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d47p',
picture: 'petro huge.jpg',
dob: '1856-12-20'
},
'48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d55j': {
name: 'Mark Henry',
userID: '48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d55j',
picture: 'mark-henry.jpg',
dob: '2005-12-29'
}
}
I need to get picture from an api which is asynchronous, so used async await inside the reduce method. The problem here is it is always showing as Promise pending. If this was an array of object, then i can return Promise.all, but since this is object containing object how can i proceed with this inside reduce method? I need the exact same expected output.
Can somebody help me with this? Any help would be really appreciated.
To use reduce while iterating over items asynchronously, you'd have to have the accumulator which gets passed from callback to callback to be a Promise. While this is possible, it'll make things pretty difficult to read, and introduces some unnecessary syntax noise.
Use a plain for loop instead:
const filteredArr = {};
for (const item of LargeArr.Items) {
const { attributes: { dob, name, picture} = { dob: null, name: null, picture: null } } = item;
const pic = picture ? await getPic(picture) : null;
filteredArr[userID] = { name, uesrID, pic, dob };
}
If you really wanted to take the reduce route:
LargeArr.Items.reduce(
(acc, { attributes: { dob, name, picture} = { dob: null, name: null, picture: null }, userID }) => {
return acc.then(async (acc) => {
let pic = null;
if (picture) { pic = await getPic(picture); } // async here
acc[userID] = { name, userID, pic, dob };
return acc;
});
}, Promise.resolve({})
)
.then((filteredArr) => {
// do stuff with filteredArr
});
Unless the getPic calls need to be made in serial, you could consider using Promise.all instead, to iterate through the whole array at once, rather than waiting on the resolution of the prior Promise before going onto the next.
If your API can handle Promise.all:
const filteredArr = {};
await Promise.all(LargeArr.Items.map(async (item) => {
const { attributes: { dob, name, picture} = { dob: null, name: null, picture: null } } = item;
const pic = picture ? await getPic(picture) : null;
filteredArr[userID] = { name, uesrID, pic, dob };
}));
I'm trying to create new object with different properties name from Array.
Array is:
profiles: Array(1)
0:
column:
name: "profileName"
title: "Profile name"
status: "Active"
I want to create new function that return object with two properties:
id: 'profileName',
profileStatus: 'Active'
The function that I have create is returning only one property as undefined undefined=undefined.
function getProfile(profiles) {
if (!profiles.length) return undefined;
return profiles.reduce((obj, profile) => {
console.log('profiles', profile);
return ({
...obj,
id: profile.column.name,
profileStatus: profile.status,
});
}, {});
}
The function getProfile is taking as input array 'profiles' from outside,
I've just tested here and this seems to be working actually
const getProfile1 = (p) => p.reduce((obj, profile) =>({
...obj,
id: profile.column.name,
profileStatus: profile.status,
}), {});
You can use map as an alternative.
var profiles = [{"column":{"name": "profileName3","title": "3Profile name"},"status": "Active"},{"column":{"name": "profileName","title": "Profile name"},"status": "Active"}];
function getProfile(profiles) {
if (!profiles.length) return undefined;
return profiles.map(function(profile,v){
return {id:profile.column.name,profileStatus: profile.status};
});
}
console.log(getProfile(profiles));
Whenever I use reduce in this way, I usually index the final object by some sort of an id. As noted in another answer, you could use map in this situation as well. If you really want your final data structure to be an object, however, you could do something like this:
/**
* returns object indexed by profile id
*/
const formatProfiles = (profiles) => {
return profiles.reduce((obj, profile) => {
return {
...obj,
[profile.id]: {
id: profile.column.name,
profileStatus: profile.status,
}
};
}, {});
};
const profiles = [
{
id: 0,
status: 'active',
column: {
name: "profile_name_1",
title: "profile_title_1",
},
},
{
id: 1,
status: 'inactive',
column: {
name: "profile_name_2",
title: "profile_title_2",
}
}
];
const result = formatProfiles(profiles);
/**
* Result would look like this:
*/
// {
// '0': { id: 'profile_name_1', profileStatus: 'active' },
// '1': { id: 'profile_name_2', profileStatus: 'inactive' }
// }
In my reducer, I have the initial state which looks like this:
const initialState = {
isLoading: false,
events: [
{
year: 2021,
place: [
{
id: 1,
name: "BD"
},
{
id: 2,
name: "BD Test"
}
]
},
{ year: 2020, place: [{ id: 3, name: "AMS" }, { id: 4, name: "AMS TEST" }] }
]
};
I have been trying to implement the functionality of deletion operation. So, when the button will be clicked the "deleteItems" action will be dispatched that will remove the corresponding items from the place. This functionality works fine. But,I am trying to remove the whole items from the events array if there is no values in place.
This is what I have tried already but it just removes the individual place. But, I need to write the logic here of removing the whole items when place becomes empty.
case "deleteItems":
return {
...state,
events: state.events.map(event => {
const place = event.place.find(x => x.id === action.id);
if (place) {
return {
...event,
place: event.place.filter(x => x.id !== action.id)
};
}
return event;
})
};
So, after modifications, the state would look like this:(when there is no values in place for year 2021)
const initialState = {
isLoading: false,
events: [
{ year: 2020, place: [{ id: 3, name: "AMS" }, { id: 4, name: "AMS TEST" }] }
]
};
Does anybody know how to accomplish this. Any helps would be highly appreciated.Thanks in Advance.
Demo can be seen from here
I removed the places first.
Then I filtered events based on whether the place array is empty or not.
After that, I returned the state.
case "deleteItems":
const eventsPostDeletingPlaces = state.events.map(event => {
const place = event.place.find(x => x.id === action.id);
if (place) {
return {
...event,
place: event.place.filter(x => x.id !== action.id)
};
}
return event;
});
const eventsWithPlaces = eventsPostDeletingPlaces.filter((each) => each.place.length);
return {
...state,
events: eventsWithPlaces
}
Check the edited sandbox here
Basically the same logic as in the first answer, but with reduce instead of a map and an extra filter. Just an option.
case "deleteItems":
return {
...state,
events: state.events.reduce((events, event) => {
const place = event.place.find(x => x.id === action.id);
if (place) {
event.place = event.place.filter(x => x.id !== action.id);
}
if (event.place.length > 0) {
events.push(event);
}
return events;
}, [])
};
codesandbox
I currently have a map of an array of users which all have a unique _id key / value.
user = [{_id: "1", ... }, {_id: "2", ... }, ... ]
I also have two other arrays, one named teams and another named accounts.
teams = [{ _id: "1", members: [{ userId: "2" }, { userId: "4" }, ... ], ... }]
accounts = [{ _id: "1", authorizedUsers: [{ userId: "3"}, ... ], ownerTeamId: "2" }, ... ]
Trying to create two comparison functions which takes the argument of user and outputs numberOfTeams and numberOfAccounts for the corresponding user.
I have attempted the numberOfTeams below but I'm not sure if it's the most optimal.
numberOfTeams(user) {
let count = 0;
teams.forEach(team => {
team.members.forEach(member => {
if (member.userId === user._id) {
count++
}
})
});
return count;
}
With the numberOfAccounts, I'm stuck on how to compare authorizedUsers === user._id OR ownerTeamId === team._id where also members.userId === user.id, and then count++.
It’s probably a good start to write a function to get the teams a user belongs to:
function containsUserId(users, id) {
return users.some(user => user.userId === id);
}
function getUserTeams(user, teams) {
return teams.filter(team =>
containsUserId(team.members, user._id));
}
because then you can write numberOfTeams using it:
numberOfTeams(user) {
return getUserTeams(user, teams).length;
}
then a similar function to get accounts:
function getUserAccounts(user, accounts) {
const userTeamIds = new Set(
getUserTeams(user).map(team => team._id)
);
return accounts.filter(account =>
containsUserId(account.authorizedUsers, user._id) ||
userTeamIds.has(accounts.ownerTeamId));
}
then numberOfAccounts using it:
numberOfAccounts(user) {
return getUserAccounts(user, accounts).length;
}
Essentially: use more functions so you can understand the steps you’re taking to solve your own problem and, in doing so, use those steps more effectively.