Looping nested array Object in ListView React native - reactjs

I currently trying to play around with react-native..
I want to make a list view that get the dataSource from var which contain an object that have nested array inside.
var questionArray = [
{
question: "What is the emotion of the user? choose all that apply!",
answerArray: [
{ name: "Cheerful", status: true, answered: false },
{ name: "Impulsive", status: false, answered: false },
{ name: "Firm", status: false, answered: false },
{ name: "Merry", status: true, answered: false },
{ name: "Jumpy", status: false, answered: false },
{ name: "Energetic", status: false, answered: false },
{ name: "Glowing", status: false, answered: false },
{ name: "Animated", status: false, answered: false },
{ name: "Lively", status: false, answered: false },
{ name: "Creepy", status: false, answered: false },
{ name: "Excited", status: true, answered: false },
{ name: "Tense", status: false, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Pleased", status: true, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Hasty", status: false, answered: false },
{ name: "Delighted", status: true, answered: false },
{ name: "Hedonistic", status: false, answered: false },
{ name: "Eager", status: false, answered: false },
{ name: "Joyful", status: false, answered: false },
]
},
{
question: "What is the best way to describe this person's character? Choose all that apply.",
answerArray: [
{ name: "Cheerful", status: true, answered: false },
{ name: "Impulsive", status: false, answered: false },
{ name: "Firm", status: false, answered: false },
{ name: "Merry", status: true, answered: false },
{ name: "Jumpy", status: false, answered: false },
{ name: "Energetic", status: false, answered: false },
{ name: "Glowing", status: false, answered: false },
{ name: "Animated", status: false, answered: false },
{ name: "Lively", status: false, answered: false },
{ name: "Creepy", status: false, answered: false },
{ name: "Excited", status: true, answered: false },
{ name: "Tense", status: false, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Pleased", status: true, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Hasty", status: false, answered: false },
{ name: "Delighted", status: true, answered: false },
{ name: "Hedonistic", status: false, answered: false },
{ name: "Eager", status: false, answered: false },
{ name: "Joyful", status: false, answered: false },
]
}
];
and I called this variable inside render ListView which trigger renderRow function..
_renderRow( rowData, sectionID, rowID ) {
return (
<View>
<Text>{rowData.question}</Text>
<Text>{rowData.answerArray[0].name}</Text>
</View>
);
}
render() {
return (
<View>
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderRow.bind(this)}
/>
</View>
);
}
How do I render the loop inside this listView ?
Even the when I hard coded the index like above code, it's not working..
Thank you.

You should make two separate Components: Question & Answer
I've made a Codepen for you as an example, using your data
At first, I pass the questionsArray as prop to the ListView Component:
class Application extends React.Component {
render() {
return (
<div>
{ questionsArray.map((question, key) => <ListView key={`listview-${key}`} question={question} />) }
</div>
);
}
}
Then, you can pass the answers to the ListViewItem Component, like this:
class ListView extends React.Component {
render() {
return (
<div>
{this.props.question.question}
{this.props.question.answerArray.map((answer, key) => <ListViewItem answer={answer} />)}
</div>
);
}
}
This is the ListViewItem:
class ListViewItem extends React.Component {
render() {
return (
<div>
{this.props.answer.name}
</div>
);
}
}

Related

Return objects from a map function if true

I want to return object(s) from a map function only if documents are checked. Here is the structure of my state.
{
type: ListOfTypes[Math.floor(Math.random() * ListOfTypes.length)],
name: ListOfNames[Math.floor(Math.random() * ListOfNames.length)],
id: nanoid(),
channels: [
{
id: nanoid(),
Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
Files: [
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },],
},
{
id: nanoid(),
Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
Files: [
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
],
},
{
id: nanoid(),
Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
Files: [
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
],
}
]
}
I tried to map through the state array but I got an object with un necessary arrays using this.
const handleMoveAll = () => {
const CheckedDocuments = List.map( (connection: any) => (connection.id == connectionId) &&
connection.channels.map( (channel: any) => (channel.id == channelId) &&
channel.Files.map( (file: any) =>
file.documents.map( (doc: any) => doc.isChecked &&
doc
))
)
)
console.log(CheckedDocuments)
}
Is there a better way to loop through the Files array checking for checked documents and returning them in a single array?
Thanks to #HagaiHarari & #oakar.
const handleMoveAll = () => {
const CheckedDocuments = List.flatMap((connection: any) => (connection.id == connectionId) ?
connection.channels.flatMap((channel: any) => (channel.id == channelId) ?
channel.Files.flatMap( (file: any) =>
file.documents.filter( (doc: any) => { if(doc.isChecked) return doc }
))
: []
)
: []
)
console.log(CheckedDocuments)
}

Update if there is no such element

I have a document
{
videoSection:{
title: "Social construction",
videos: [
{title: "a", isApproved: true},
{title: "b", isApproved: false},
{title: "c", isApproved: true},
],
isPublished: false
}
}
I need to update the document (to set isPublished: true) if all the isApproved fields of the videos of videoSection is true which means if there is no isApproved = false.
What is the way of doing this ?
Demo - https://mongoplayground.net/p/obReFQ3FmkV
db.collection.update(
{
"videoSection.videos.isApproved": {
$exists: true,
$ne: false
}
},
{ $set: { "videoSection.isPublished": true } },
{ multi: true }
)
Note - { $exists: true } this add extra checks for the case where videos array is empty or not present, update will not happen.
check condition if isApproved is not false then update isPublished to true
db.collection.updateMany({
"videoSection.videos.isApproved": {
$ne: false
}
},
{
$set: {
"videoSection.isPublished": true
}
})
Playground

React state is not changing after the props change

I'm using redux with react, In my react state I'm assigning some state properties to the props but in my state the accounts are changing but the loading property doesn't change, I also tried to update the state in componentdidupdate but when I try to do that I get maximum update depth exceeded
In AllAccounts the accounts property is updating when the accounts are done fetching and the props change but the same doesn't happen for the loading property, It is set to the first value when it changes when it is set to true, The prop value is changing for loading but it is not changing in the state
This is my component
import React, { Component } from "react";
import { connect } from "react-redux";
import {
getAccounts,
deleteAccounts,
addAccount,
} from "../../../actions/accountActions";
import { getUsersForTenant } from "../../../actions/userActions";
import { Drawer } from "antd";
import getSortUrl from "../../../utils/getSortUrl";
import "../tablepage.css";
import Table from "../../../components/Table/Table";
import SearchHeader from "../../../components/SearchHeader/SearchHeader";
import Loading from "../../../components/Loading/Loading";
import AddAccount from "../../../components/AddEntities/AddAccount/AddAccount";
class AllAccounts extends Component {
constructor(props) {
super(props);
this.fetchData = this.fetchData.bind(this);
this.setSort = this.setSort.bind(this);
this.deleteRows = this.deleteRows.bind(this);
this.toggleDrawer = this.toggleDrawer.bind(this);
this.addAccount = this.addAccount.bind(this);
}
state = {
page: 0,
size: 50,
loading: this.props.loading,
accounts: this.props.accounts,
sort: undefined,
selectedItems: [],
checkboxActive: false,
drawerVisible: false,
columns: [
{
key: "name",
title: "Name",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: true,
},
{
key: "companyDomain",
title: "Company Domain",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "industrySector.name",
title: "Industry Sector",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "picture",
title: "Picture",
enabled: false,
searchable: false,
type: "picture",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "nbrEmployees",
title: "No. Employees",
enabled: true,
searchable: true,
type: "number",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "fixedPhone",
title: "Phone",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "source.name",
title: "Source",
enabled: false,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "linkedIn",
title: "LinkedIn",
enabled: true,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "social",
title: "Social Networks",
title: "Social Networks",
enabled: true,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "twitterPage",
title: "Twitter",
title: "twitter",
enabled: false,
bindCol: "social",
bindColTitle: "Social",
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "instagramPage",
title: "Instagram",
enabled: false,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "googlePlus",
title: "Google Plus",
enabled: false,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "user",
title: "User",
enabled: false,
searchable: false,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "isCustomer",
title: "Is Customer",
enabled: false,
searchable: false,
type: "boolean",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "Tags",
title: "Tags",
enabled: true,
searchable: false,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
],
};
toggleDrawer = () => {
this.setState({
drawerVisible: !this.state.drawerVisible,
});
};
deleteRows = (rows) => {
if (rows) {
this.props.deleteAccounts(rows, 1);
this.setState({
loading: true,
});
} else {
const { selectedItems } = this.state;
this.props.deleteAccounts(selectedItems, 1);
this.setState({
selectedItems: [],
loading: true,
});
}
};
addAccount = (accountData) => {
this.props.addAccount(accountData, 1);
};
componentDidUpdate(prevState, prevProps, snap) {
// if (prevProps.accounts != this.props.accounts) {
// this.setState({
// accounts: this.props.accounts,
// loading: false,
// });
// }
// if (prevProps.users != this.props.users) {
// this.setState({
// assignableUsers: this.props.users,
// });
// }
}
setSort = (column) => {
this.setState({
sort: column,
});
};
selectRow = (select, row) => {
if (select) {
this.setState({
selectedItems: [...this.state.selectedItems, row],
checkboxActive: true,
});
} else {
var { selectedItems } = this.state;
var index = 0;
for (var i = 0; i < selectedItems.length; i++) {
if (selectedItems[i].id == row.id) {
console.log(i);
index = i;
}
}
selectedItems.splice(index, 1);
if (selectedItems.length == 0) {
this.setState({
selectedItems: selectedItems,
checkboxActive: false,
});
} else {
this.setState({
selectedItems: selectedItems,
});
}
}
};
fetchData = () => {
this.setState(
{
loading: true,
},
() => {
const { page, size, sort } = this.state;
var sortUrl = "";
if (sort) {
const sortKey = sort.key;
const sortOrder = sort.sortOrder;
sortUrl = getSortUrl(sortKey, sortOrder);
}
this.props.getAccounts(page, size, sortUrl);
}
);
};
componentDidMount() {
this.fetchData(0, 50, undefined);
this.props.getUsersForTenant();
}
toggleEnableColumn = (index) => {
const { columns } = this.state;
var enableOccured = false;
columns[index].enabled = !columns[index].enabled;
columns.forEach((col) => {
if (!enableOccured && col.enabled) {
col.showCheckbox = true;
enableOccured = true;
} else {
col.showCheckbox = false;
}
});
this.setState({
columns: columns,
});
};
render() {
const {
size,
page,
accounts,
columns,
loading,
checkboxActive,
drawerVisible,
} = this.state;
return (
<div className="table-page-container">
<Loading loading={loading} />
<Drawer
title="Add New Account"
placement="right"
closable={true}
visible={drawerVisible}
onClose={this.toggleDrawer}
>
<AddAccount
toggleDrawer={this.toggleDrawer}
assignableUsers={this.props.users}
addAccount={this.addAccount}
/>
</Drawer>
<div className="breadcrumb-container"></div>
<div className="searchbar-container">
<SearchHeader
columns={columns}
checkboxActive={checkboxActive}
fetchData={this.fetchData}
deleteData={this.deleteRows}
toggleDrawer={this.toggleDrawer}
/>
</div>
<Table
size={size}
page={page}
data={accounts}
checkboxActive={checkboxActive}
module={"accounts"}
columns={columns}
toggleEnableColumn={this.toggleEnableColumn}
className="table-container"
selectRow={this.selectRow}
fetchData={this.fetchData}
setSort={this.setSort}
deleteData={this.deleteRows}
/>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
accounts: state.account.accounts,
users: state.user.users,
loading: state.account.loading,
};
};
const mapDispatchToProps = (dispatch) => {
return {
getAccounts: (page, size, sort) => dispatch(getAccounts(page, size, sort)),
addAccount: (accountData, accountType) =>
dispatch(addAccount(accountData, accountType)),
deleteAccounts: (rows, accountType) =>
dispatch(deleteAccounts(rows, accountType)),
getUsersForTenant: () => dispatch(getUsersForTenant()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(AllAccounts);
This is the reducer
import {
GET_ACCOUNT,
GET_ACCOUNTS,
GET_CUSTOMERS,
GET_PROSPECTS,
DELETE_ACCOUNT,
SET_ACCOUNTS_LOADING,
SET_ACCOUNTS_ERROR,
CLEAR_ERRORS,
} from "../actions/types";
const defaultState = {
accounts: [],
customers: [],
prospects: [],
loading: false,
errors: {},
};
const accountReducer = (state = defaultState, action) => {
switch (action.type) {
case GET_ACCOUNTS:
return {
...state,
accounts: action.payload,
errors: {},
};
case GET_CUSTOMERS:
return {
...state,
customers: action.payload,
errors: {},
};
case GET_PROSPECTS:
return {
...state,
prospects: action.payload,
errors: {},
};
case CLEAR_ERRORS:
return {
...state,
errors: {},
};
case SET_ACCOUNTS_LOADING:
return {
...state,
loading: action.payload,
};
case SET_ACCOUNTS_ERROR:
return {
...state,
errors: action.payload,
};
default:
return state;
}
};
export default accountReducer;
What you might need is the static getDerivedStateFromProps(props, state)
This method exists for rare use cases where the state depends on changes in props over time.
In order for your props to flow through your local state, you can write a logic inside that life-cycle method.
static getDerivedStateFromProps(props, state) {
if (!isEqual(props.accounts,state.accounts)) {
return {
accounts: props.accounts
};
}
return null;
}
}
Please take note that I am using isEqual from lodash/isEqual to deep check equality between state and props otherwise it will update everytime props flow in.
Reference: https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

How can I change nested state in class component to state in functional component?

I have some nested state in class component that I want change it to functional component, but I don't know how can I use nested state in functional component with hook and useState and also useEffect? can you help me please?
state = {
products: null,
totalPrice: 0,
addCounter: 0,
purchased: false,
loading: false,
form: {
name: {
elementType: 'input',
elmentConfig: {
type: 'text',
palceholder: 'Name...',
},
value: '',
validation: {
required: true,
},
valid: false,
used: false,
},
password: {
elementType: 'input',
elmentConfig: {
type: 'password',
palceholder: 'Password...',
},
value: '',
validation: {
required: true,
},
valid: false,
used: false,
},
email: {
elementType: 'input',
elmentConfig: {
type: 'text',
palceholder: 'Email...',
},
value: '',
validation: {
required: true,
},
valid: false,
used: false,
},
},
};
Convert your state with useState, however I would recommend separating your state in smaller 'states' to make it a little more manageable and not have deeply nested values.
eg.
const [checkout, setCheckout] = useState({
products: null,
totalPrice: 0,
addCounter: 0,
purchased: false,
loading: false
});
const [userForm, setUserForm] = useState({
name: {
elementType: 'input',
elementConfig: {
type: 'text',
placeholder: 'Name...'
},
value: '',
validation: {
required: true
},
valid: false,
used: false,
},
password: {
elementType: 'input',
elementConfig: {
type: 'password',
placeholder: 'Password...'
},
value: '',
validation: {
required: true
},
valid: false,
used: false,
},
email: {
elementType: 'input',
elementConfig: {
type: 'text',
palceholder: 'Email...'
},
value: '',
validation: {
required: true
},
valid: false,
used: false,
}
});
nb. you can get your state from the useState hook simply by calling the state name once it has been initialised.
setting your state can become complex when working with deeply nested states so the 'shallower' the better for each state imho.
see documentation here: https://reactjs.org/docs/hooks-state.html with equivalent class examples
You can try:
const [formElements, setFormElements] = useState({
products: null,
totalPrice: 0,
addCounter: 0,
purchased: false,
loading: false,
form: {
name: {
elementType: 'input',
elmentConfig: {
type: 'text',
palceholder: 'Name...',
},
value: '',
validation: {
required: true,
},
valid: false,
used: false,
},
password: {
elementType: 'input',
elmentConfig: {
type: 'password',
palceholder: 'Password...',
},
value: '',
validation: {
required: true,
},
valid: false,
used: false,
},
email: {
elementType: 'input',
elmentConfig: {
type: 'text',
palceholder: 'Email...',
},
value: '',
validation: {
required: true,
},
valid: false,
used: false,
},
},
});
By using this, the initial state can be available in formElements and to update it you can use setFormElements function.
Reference

Node.JS sequelizejs many to many

I'm working on a web site where users can have a project, and for each project they have, they are assigned a certain role. Here is the schema
How I can make it with the model of squelize (Or maybe it's better to don't use an ORM (it's what I'm thinking right now..))
Here you can see a part of my model :
//Users
module.exports = function(sequelize, DataTypes) {
return sequelize.define('User', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
// ******** //
}, {
tableName: 'users',
freezeTableName: true
});
};
//Projects
module.exports = function(sequelize, DataTypes) {
return sequelize.define('Project', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: true
}
}, {
tableName: 'projects',
freezeTableName: true
});
};
//ProjectRole :
module.exports = function(sequelize, DataTypes) {
return sequelize.define('ProjectRole', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: true
}
}, {
tableName: 'projects_roles',
freezeTableName: true
});
};
//user has projects :
module.exports = function(sequelize, DataTypes) {
return sequelize.define('UserProject', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
}, {
tableName: 'users_has_projects',
freezeTableName: true
});
};

Resources