React Redux - Table of select dropdowns with mutually exclusive options
up vote
1
down vote
favorite
I'm scratching my head on this one. And i find it's also not easy to explain. I'll do my best:
I have an html table, each row has an image and, amongst other elements, also a select dropdown with a top 10 list, to rank the image.
When a user selects a ranking, the database gets updated accordingly ->
The current image top 10 ranking is saved in the image entry, and the rank of the former image to inherit the position gets updated to 'null'. (this is already working -> so if I reload the page, everything turns up fine).
What I'm unable to achieve, is for the updated images array that I receive back from the db to update the state (or the props) and therefor the selected option value of the image that formerly inherited the rank.
Here's my ImageList
Component (the important parts):
class ImageList extends Component {
constructor(props) {
super(props)
this.state = {
project: ,
description: '',
name: '',
values: ,
value: '',
positions: props.positions
}
}
updatePosition = (projectId, projectName, imageId, imgName, i, e) => {
this.props.setGridPosition(
projectId,
projectName,
imageId,
imgName,
e.target.value
)
}
getAllImages() {
let imageList =
if (this.props.project.project) {
const { project, waiting } = this.props.project
for (let [i, img] of project.images.entries()) {
if (!img.isDeleted) {
let options = ['-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
this.props.positions[i] = img.gridPosition
let imgSrc = `/public/${project._id}/${img.originalName}`
imageList.push(
<tr
key={img._id}
style={waiting ? { opacity: '.5' } : { opacity: '1' }}
>
<td>
<img src={imgSrc} alt="" style={{ width: '60px' }} />
</td>
<SelectFieldGroup
name={`placeInGrid_${i}`}
onChange={this.updatePosition.bind(
this,
project._id,
project.name,
img._id,
img.originalName,
i
)}
options={options}
value={this.props.positions[i]}
/>
</td>
</tr>
)
}
}
}
return imageList
}
render() {
return (
<div className={styles['image-list']}>
<table className={styles['image-table']}>
<tbody>{this.getAllImages()}</tbody>
</table>
</div>
)
}
}
const mapStateToProps = state => ({
auth: state.auth,
project: state.project
})
export default connect(
mapStateToProps,
{ deleteImage, setGridPosition }
)(ImageList)
I receive the props - the project and positions (as an empty array) - from the parent Component.
I hope the issue is somehow clear. I would really appreciate any help or pointers to where I went wrong.
Edit:
As requested, for clarification, here are some other parts of the code:
SelectFieldGroup.js
:
import React from 'react'
import PropTypes from 'prop-types'
import cx from 'classnames'
import globalStyles from './Bootstrap.module.css'
import commonStyles from './Common.module.sass'
const SelectFieldGroup = ({ name, onChange, options, value, disabled }) => {
let optionArray =
for (let [index, option] of options.entries()) {
optionArray.push(<option key={index}>{option}</option>)
}
return (
<div className={globalStyles['form-group']}>
<select
value={value}
className={cx(
globalStyles['custom-select'],
commonStyles['custom-select'],
commonStyles['dark-input']
)}
name={name}
onChange={onChange}
disabled={disabled}
>
{optionArray}
</select>
</div>
)
}
SelectFieldGroup.propTypes = {
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
disabled: PropTypes.string
}
export default SelectFieldGroup
The relevant part of imageActions.
:
export const setGridPosition = (
projectId,
projectName,
imageId,
imageName,
position
) => dispatch => {
dispatch(setWaiting())
const data = {
projectId: projectId,
projectName: projectName,
imageId: imageId,
imageName: imageName,
position: position
}
console.log(projectId)
axios
.post('/api/projects/set_grid_position', data)
.then(res => {
console.log(res.data)
dispatch({
type: SET_GRID_POSITION,
payload: res.data
})
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: {}
})
)
}
The node express api:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const errors = {}
Project.findById(req.body.projectId).then(currentProject => {
let updatedProject = currentProject
ProjectGridPosition.findOne({ position: req.body.position }).then(
gridPosition => {
if (req.body.position != '-') {
// Mark the previous position of the image as empty.
ProjectGridPosition.findOne({ imageId: req.body.imageId })
.then(oldPos => {
oldPos.isTaken = false
oldPos.save()
})
.catch(err => res.status(400).json(err))
// Set the gridPosition inside the image.
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
else {
updatedProject = currentProject
}
})
if (gridPosition) {
if (gridPosition.projectId) {
Project.findById(gridPosition.projectId)
.then(project => {
console.log(project.name)
project.images.forEach(img => {
if (img.gridPosition == req.body.position) {
console.log(img.originalName)
img.gridPosition = '-'
}
})
project.save(err => {
if (err) {
res.json(err)
} else {
if (project == currentProject) {
updatedProject = currentProject
}
}
})
})
.catch(err => res.json(err))
}
gridPosition.projectId = req.body.projectId
gridPosition.projectName = req.body.projectName
gridPosition.imageId = req.body.imageId
gridPosition.imageName = req.body.imageName
gridPosition.isTaken = true
gridPosition.save()
res.json(updatedProject)
} else {
const newPosFields = {
projectId: req.body.projectId,
projectName: req.body.projectName,
imageId: req.body.imageId,
imageName: req.body.imageName,
position: req.body.position,
isTaken: true
}
new ProjectGridPosition(newPosFields)
.save()
.then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
.catch(err => res.json(err))
}
} else {
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
ProjectGridPosition.findOne({ imageId: req.body.imageId }).then(
newPos => {
newPos.isTaken = false
newPos.save().then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
}
)
})
}
}
)
})
}
)
And finally, the relevant part of projectReducer.js
:
import {
// ...
SET_GRID_POSITION
} from '../actions/types'
const initialState = {
project: null,
projects: null,
loading: false,
waiting: false
}
export default function(state = initialState, action) {
switch (action.type) {
// ....
case SET_GRID_POSITION:
return {
...state,
project: action.payload,
waiting: false
}
default:
return state
}
}
reactjs react-redux
New contributor
|
show 4 more comments
up vote
1
down vote
favorite
I'm scratching my head on this one. And i find it's also not easy to explain. I'll do my best:
I have an html table, each row has an image and, amongst other elements, also a select dropdown with a top 10 list, to rank the image.
When a user selects a ranking, the database gets updated accordingly ->
The current image top 10 ranking is saved in the image entry, and the rank of the former image to inherit the position gets updated to 'null'. (this is already working -> so if I reload the page, everything turns up fine).
What I'm unable to achieve, is for the updated images array that I receive back from the db to update the state (or the props) and therefor the selected option value of the image that formerly inherited the rank.
Here's my ImageList
Component (the important parts):
class ImageList extends Component {
constructor(props) {
super(props)
this.state = {
project: ,
description: '',
name: '',
values: ,
value: '',
positions: props.positions
}
}
updatePosition = (projectId, projectName, imageId, imgName, i, e) => {
this.props.setGridPosition(
projectId,
projectName,
imageId,
imgName,
e.target.value
)
}
getAllImages() {
let imageList =
if (this.props.project.project) {
const { project, waiting } = this.props.project
for (let [i, img] of project.images.entries()) {
if (!img.isDeleted) {
let options = ['-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
this.props.positions[i] = img.gridPosition
let imgSrc = `/public/${project._id}/${img.originalName}`
imageList.push(
<tr
key={img._id}
style={waiting ? { opacity: '.5' } : { opacity: '1' }}
>
<td>
<img src={imgSrc} alt="" style={{ width: '60px' }} />
</td>
<SelectFieldGroup
name={`placeInGrid_${i}`}
onChange={this.updatePosition.bind(
this,
project._id,
project.name,
img._id,
img.originalName,
i
)}
options={options}
value={this.props.positions[i]}
/>
</td>
</tr>
)
}
}
}
return imageList
}
render() {
return (
<div className={styles['image-list']}>
<table className={styles['image-table']}>
<tbody>{this.getAllImages()}</tbody>
</table>
</div>
)
}
}
const mapStateToProps = state => ({
auth: state.auth,
project: state.project
})
export default connect(
mapStateToProps,
{ deleteImage, setGridPosition }
)(ImageList)
I receive the props - the project and positions (as an empty array) - from the parent Component.
I hope the issue is somehow clear. I would really appreciate any help or pointers to where I went wrong.
Edit:
As requested, for clarification, here are some other parts of the code:
SelectFieldGroup.js
:
import React from 'react'
import PropTypes from 'prop-types'
import cx from 'classnames'
import globalStyles from './Bootstrap.module.css'
import commonStyles from './Common.module.sass'
const SelectFieldGroup = ({ name, onChange, options, value, disabled }) => {
let optionArray =
for (let [index, option] of options.entries()) {
optionArray.push(<option key={index}>{option}</option>)
}
return (
<div className={globalStyles['form-group']}>
<select
value={value}
className={cx(
globalStyles['custom-select'],
commonStyles['custom-select'],
commonStyles['dark-input']
)}
name={name}
onChange={onChange}
disabled={disabled}
>
{optionArray}
</select>
</div>
)
}
SelectFieldGroup.propTypes = {
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
disabled: PropTypes.string
}
export default SelectFieldGroup
The relevant part of imageActions.
:
export const setGridPosition = (
projectId,
projectName,
imageId,
imageName,
position
) => dispatch => {
dispatch(setWaiting())
const data = {
projectId: projectId,
projectName: projectName,
imageId: imageId,
imageName: imageName,
position: position
}
console.log(projectId)
axios
.post('/api/projects/set_grid_position', data)
.then(res => {
console.log(res.data)
dispatch({
type: SET_GRID_POSITION,
payload: res.data
})
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: {}
})
)
}
The node express api:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const errors = {}
Project.findById(req.body.projectId).then(currentProject => {
let updatedProject = currentProject
ProjectGridPosition.findOne({ position: req.body.position }).then(
gridPosition => {
if (req.body.position != '-') {
// Mark the previous position of the image as empty.
ProjectGridPosition.findOne({ imageId: req.body.imageId })
.then(oldPos => {
oldPos.isTaken = false
oldPos.save()
})
.catch(err => res.status(400).json(err))
// Set the gridPosition inside the image.
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
else {
updatedProject = currentProject
}
})
if (gridPosition) {
if (gridPosition.projectId) {
Project.findById(gridPosition.projectId)
.then(project => {
console.log(project.name)
project.images.forEach(img => {
if (img.gridPosition == req.body.position) {
console.log(img.originalName)
img.gridPosition = '-'
}
})
project.save(err => {
if (err) {
res.json(err)
} else {
if (project == currentProject) {
updatedProject = currentProject
}
}
})
})
.catch(err => res.json(err))
}
gridPosition.projectId = req.body.projectId
gridPosition.projectName = req.body.projectName
gridPosition.imageId = req.body.imageId
gridPosition.imageName = req.body.imageName
gridPosition.isTaken = true
gridPosition.save()
res.json(updatedProject)
} else {
const newPosFields = {
projectId: req.body.projectId,
projectName: req.body.projectName,
imageId: req.body.imageId,
imageName: req.body.imageName,
position: req.body.position,
isTaken: true
}
new ProjectGridPosition(newPosFields)
.save()
.then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
.catch(err => res.json(err))
}
} else {
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
ProjectGridPosition.findOne({ imageId: req.body.imageId }).then(
newPos => {
newPos.isTaken = false
newPos.save().then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
}
)
})
}
}
)
})
}
)
And finally, the relevant part of projectReducer.js
:
import {
// ...
SET_GRID_POSITION
} from '../actions/types'
const initialState = {
project: null,
projects: null,
loading: false,
waiting: false
}
export default function(state = initialState, action) {
switch (action.type) {
// ....
case SET_GRID_POSITION:
return {
...state,
project: action.payload,
waiting: false
}
default:
return state
}
}
reactjs react-redux
New contributor
It may be helpful to see the definition ofSelectFieldGroup
. Is that a custom component or one from another library?
– Tex
Nov 21 at 22:49
can you add your reducer code where you are saving your update images array and also thesetGridPosition
action code in order to have a better view at your state management.
– Pranay Tripathi
Nov 22 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
Thanks for sharing the additional code. The challenge now is that there's quite a lot of code to try to digest all at once. I think the source of your problem, though, is ingetAllImages
, specifically here:this.props.positions[i] = img.gridPosition
. One should never mutateprops
directly. Rather, one should update the state (either component state viasetState
or Redux*) and let React (and potentially Redux) take care of updating the component when the positions change. * If I had to choose between component state and Redux, I'd definitely choose Redux here.
– Tex
Nov 23 at 8:05
|
show 4 more comments
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I'm scratching my head on this one. And i find it's also not easy to explain. I'll do my best:
I have an html table, each row has an image and, amongst other elements, also a select dropdown with a top 10 list, to rank the image.
When a user selects a ranking, the database gets updated accordingly ->
The current image top 10 ranking is saved in the image entry, and the rank of the former image to inherit the position gets updated to 'null'. (this is already working -> so if I reload the page, everything turns up fine).
What I'm unable to achieve, is for the updated images array that I receive back from the db to update the state (or the props) and therefor the selected option value of the image that formerly inherited the rank.
Here's my ImageList
Component (the important parts):
class ImageList extends Component {
constructor(props) {
super(props)
this.state = {
project: ,
description: '',
name: '',
values: ,
value: '',
positions: props.positions
}
}
updatePosition = (projectId, projectName, imageId, imgName, i, e) => {
this.props.setGridPosition(
projectId,
projectName,
imageId,
imgName,
e.target.value
)
}
getAllImages() {
let imageList =
if (this.props.project.project) {
const { project, waiting } = this.props.project
for (let [i, img] of project.images.entries()) {
if (!img.isDeleted) {
let options = ['-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
this.props.positions[i] = img.gridPosition
let imgSrc = `/public/${project._id}/${img.originalName}`
imageList.push(
<tr
key={img._id}
style={waiting ? { opacity: '.5' } : { opacity: '1' }}
>
<td>
<img src={imgSrc} alt="" style={{ width: '60px' }} />
</td>
<SelectFieldGroup
name={`placeInGrid_${i}`}
onChange={this.updatePosition.bind(
this,
project._id,
project.name,
img._id,
img.originalName,
i
)}
options={options}
value={this.props.positions[i]}
/>
</td>
</tr>
)
}
}
}
return imageList
}
render() {
return (
<div className={styles['image-list']}>
<table className={styles['image-table']}>
<tbody>{this.getAllImages()}</tbody>
</table>
</div>
)
}
}
const mapStateToProps = state => ({
auth: state.auth,
project: state.project
})
export default connect(
mapStateToProps,
{ deleteImage, setGridPosition }
)(ImageList)
I receive the props - the project and positions (as an empty array) - from the parent Component.
I hope the issue is somehow clear. I would really appreciate any help or pointers to where I went wrong.
Edit:
As requested, for clarification, here are some other parts of the code:
SelectFieldGroup.js
:
import React from 'react'
import PropTypes from 'prop-types'
import cx from 'classnames'
import globalStyles from './Bootstrap.module.css'
import commonStyles from './Common.module.sass'
const SelectFieldGroup = ({ name, onChange, options, value, disabled }) => {
let optionArray =
for (let [index, option] of options.entries()) {
optionArray.push(<option key={index}>{option}</option>)
}
return (
<div className={globalStyles['form-group']}>
<select
value={value}
className={cx(
globalStyles['custom-select'],
commonStyles['custom-select'],
commonStyles['dark-input']
)}
name={name}
onChange={onChange}
disabled={disabled}
>
{optionArray}
</select>
</div>
)
}
SelectFieldGroup.propTypes = {
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
disabled: PropTypes.string
}
export default SelectFieldGroup
The relevant part of imageActions.
:
export const setGridPosition = (
projectId,
projectName,
imageId,
imageName,
position
) => dispatch => {
dispatch(setWaiting())
const data = {
projectId: projectId,
projectName: projectName,
imageId: imageId,
imageName: imageName,
position: position
}
console.log(projectId)
axios
.post('/api/projects/set_grid_position', data)
.then(res => {
console.log(res.data)
dispatch({
type: SET_GRID_POSITION,
payload: res.data
})
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: {}
})
)
}
The node express api:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const errors = {}
Project.findById(req.body.projectId).then(currentProject => {
let updatedProject = currentProject
ProjectGridPosition.findOne({ position: req.body.position }).then(
gridPosition => {
if (req.body.position != '-') {
// Mark the previous position of the image as empty.
ProjectGridPosition.findOne({ imageId: req.body.imageId })
.then(oldPos => {
oldPos.isTaken = false
oldPos.save()
})
.catch(err => res.status(400).json(err))
// Set the gridPosition inside the image.
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
else {
updatedProject = currentProject
}
})
if (gridPosition) {
if (gridPosition.projectId) {
Project.findById(gridPosition.projectId)
.then(project => {
console.log(project.name)
project.images.forEach(img => {
if (img.gridPosition == req.body.position) {
console.log(img.originalName)
img.gridPosition = '-'
}
})
project.save(err => {
if (err) {
res.json(err)
} else {
if (project == currentProject) {
updatedProject = currentProject
}
}
})
})
.catch(err => res.json(err))
}
gridPosition.projectId = req.body.projectId
gridPosition.projectName = req.body.projectName
gridPosition.imageId = req.body.imageId
gridPosition.imageName = req.body.imageName
gridPosition.isTaken = true
gridPosition.save()
res.json(updatedProject)
} else {
const newPosFields = {
projectId: req.body.projectId,
projectName: req.body.projectName,
imageId: req.body.imageId,
imageName: req.body.imageName,
position: req.body.position,
isTaken: true
}
new ProjectGridPosition(newPosFields)
.save()
.then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
.catch(err => res.json(err))
}
} else {
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
ProjectGridPosition.findOne({ imageId: req.body.imageId }).then(
newPos => {
newPos.isTaken = false
newPos.save().then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
}
)
})
}
}
)
})
}
)
And finally, the relevant part of projectReducer.js
:
import {
// ...
SET_GRID_POSITION
} from '../actions/types'
const initialState = {
project: null,
projects: null,
loading: false,
waiting: false
}
export default function(state = initialState, action) {
switch (action.type) {
// ....
case SET_GRID_POSITION:
return {
...state,
project: action.payload,
waiting: false
}
default:
return state
}
}
reactjs react-redux
New contributor
I'm scratching my head on this one. And i find it's also not easy to explain. I'll do my best:
I have an html table, each row has an image and, amongst other elements, also a select dropdown with a top 10 list, to rank the image.
When a user selects a ranking, the database gets updated accordingly ->
The current image top 10 ranking is saved in the image entry, and the rank of the former image to inherit the position gets updated to 'null'. (this is already working -> so if I reload the page, everything turns up fine).
What I'm unable to achieve, is for the updated images array that I receive back from the db to update the state (or the props) and therefor the selected option value of the image that formerly inherited the rank.
Here's my ImageList
Component (the important parts):
class ImageList extends Component {
constructor(props) {
super(props)
this.state = {
project: ,
description: '',
name: '',
values: ,
value: '',
positions: props.positions
}
}
updatePosition = (projectId, projectName, imageId, imgName, i, e) => {
this.props.setGridPosition(
projectId,
projectName,
imageId,
imgName,
e.target.value
)
}
getAllImages() {
let imageList =
if (this.props.project.project) {
const { project, waiting } = this.props.project
for (let [i, img] of project.images.entries()) {
if (!img.isDeleted) {
let options = ['-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
this.props.positions[i] = img.gridPosition
let imgSrc = `/public/${project._id}/${img.originalName}`
imageList.push(
<tr
key={img._id}
style={waiting ? { opacity: '.5' } : { opacity: '1' }}
>
<td>
<img src={imgSrc} alt="" style={{ width: '60px' }} />
</td>
<SelectFieldGroup
name={`placeInGrid_${i}`}
onChange={this.updatePosition.bind(
this,
project._id,
project.name,
img._id,
img.originalName,
i
)}
options={options}
value={this.props.positions[i]}
/>
</td>
</tr>
)
}
}
}
return imageList
}
render() {
return (
<div className={styles['image-list']}>
<table className={styles['image-table']}>
<tbody>{this.getAllImages()}</tbody>
</table>
</div>
)
}
}
const mapStateToProps = state => ({
auth: state.auth,
project: state.project
})
export default connect(
mapStateToProps,
{ deleteImage, setGridPosition }
)(ImageList)
I receive the props - the project and positions (as an empty array) - from the parent Component.
I hope the issue is somehow clear. I would really appreciate any help or pointers to where I went wrong.
Edit:
As requested, for clarification, here are some other parts of the code:
SelectFieldGroup.js
:
import React from 'react'
import PropTypes from 'prop-types'
import cx from 'classnames'
import globalStyles from './Bootstrap.module.css'
import commonStyles from './Common.module.sass'
const SelectFieldGroup = ({ name, onChange, options, value, disabled }) => {
let optionArray =
for (let [index, option] of options.entries()) {
optionArray.push(<option key={index}>{option}</option>)
}
return (
<div className={globalStyles['form-group']}>
<select
value={value}
className={cx(
globalStyles['custom-select'],
commonStyles['custom-select'],
commonStyles['dark-input']
)}
name={name}
onChange={onChange}
disabled={disabled}
>
{optionArray}
</select>
</div>
)
}
SelectFieldGroup.propTypes = {
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
disabled: PropTypes.string
}
export default SelectFieldGroup
The relevant part of imageActions.
:
export const setGridPosition = (
projectId,
projectName,
imageId,
imageName,
position
) => dispatch => {
dispatch(setWaiting())
const data = {
projectId: projectId,
projectName: projectName,
imageId: imageId,
imageName: imageName,
position: position
}
console.log(projectId)
axios
.post('/api/projects/set_grid_position', data)
.then(res => {
console.log(res.data)
dispatch({
type: SET_GRID_POSITION,
payload: res.data
})
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: {}
})
)
}
The node express api:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const errors = {}
Project.findById(req.body.projectId).then(currentProject => {
let updatedProject = currentProject
ProjectGridPosition.findOne({ position: req.body.position }).then(
gridPosition => {
if (req.body.position != '-') {
// Mark the previous position of the image as empty.
ProjectGridPosition.findOne({ imageId: req.body.imageId })
.then(oldPos => {
oldPos.isTaken = false
oldPos.save()
})
.catch(err => res.status(400).json(err))
// Set the gridPosition inside the image.
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
else {
updatedProject = currentProject
}
})
if (gridPosition) {
if (gridPosition.projectId) {
Project.findById(gridPosition.projectId)
.then(project => {
console.log(project.name)
project.images.forEach(img => {
if (img.gridPosition == req.body.position) {
console.log(img.originalName)
img.gridPosition = '-'
}
})
project.save(err => {
if (err) {
res.json(err)
} else {
if (project == currentProject) {
updatedProject = currentProject
}
}
})
})
.catch(err => res.json(err))
}
gridPosition.projectId = req.body.projectId
gridPosition.projectName = req.body.projectName
gridPosition.imageId = req.body.imageId
gridPosition.imageName = req.body.imageName
gridPosition.isTaken = true
gridPosition.save()
res.json(updatedProject)
} else {
const newPosFields = {
projectId: req.body.projectId,
projectName: req.body.projectName,
imageId: req.body.imageId,
imageName: req.body.imageName,
position: req.body.position,
isTaken: true
}
new ProjectGridPosition(newPosFields)
.save()
.then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
.catch(err => res.json(err))
}
} else {
currentProject.images.forEach(img => {
if (img._id == req.body.imageId) {
img.gridPosition = req.body.position
}
})
currentProject.save(err => {
if (err) res.json(err)
ProjectGridPosition.findOne({ imageId: req.body.imageId }).then(
newPos => {
newPos.isTaken = false
newPos.save().then(() => {
currentProject.save().then(() => {
res.json(currentProject)
})
})
}
)
})
}
}
)
})
}
)
And finally, the relevant part of projectReducer.js
:
import {
// ...
SET_GRID_POSITION
} from '../actions/types'
const initialState = {
project: null,
projects: null,
loading: false,
waiting: false
}
export default function(state = initialState, action) {
switch (action.type) {
// ....
case SET_GRID_POSITION:
return {
...state,
project: action.payload,
waiting: false
}
default:
return state
}
}
reactjs react-redux
reactjs react-redux
New contributor
New contributor
edited Nov 22 at 10:11
New contributor
asked Nov 21 at 22:28
mctoothpick
62
62
New contributor
New contributor
It may be helpful to see the definition ofSelectFieldGroup
. Is that a custom component or one from another library?
– Tex
Nov 21 at 22:49
can you add your reducer code where you are saving your update images array and also thesetGridPosition
action code in order to have a better view at your state management.
– Pranay Tripathi
Nov 22 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
Thanks for sharing the additional code. The challenge now is that there's quite a lot of code to try to digest all at once. I think the source of your problem, though, is ingetAllImages
, specifically here:this.props.positions[i] = img.gridPosition
. One should never mutateprops
directly. Rather, one should update the state (either component state viasetState
or Redux*) and let React (and potentially Redux) take care of updating the component when the positions change. * If I had to choose between component state and Redux, I'd definitely choose Redux here.
– Tex
Nov 23 at 8:05
|
show 4 more comments
It may be helpful to see the definition ofSelectFieldGroup
. Is that a custom component or one from another library?
– Tex
Nov 21 at 22:49
can you add your reducer code where you are saving your update images array and also thesetGridPosition
action code in order to have a better view at your state management.
– Pranay Tripathi
Nov 22 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
Thanks for sharing the additional code. The challenge now is that there's quite a lot of code to try to digest all at once. I think the source of your problem, though, is ingetAllImages
, specifically here:this.props.positions[i] = img.gridPosition
. One should never mutateprops
directly. Rather, one should update the state (either component state viasetState
or Redux*) and let React (and potentially Redux) take care of updating the component when the positions change. * If I had to choose between component state and Redux, I'd definitely choose Redux here.
– Tex
Nov 23 at 8:05
It may be helpful to see the definition of
SelectFieldGroup
. Is that a custom component or one from another library?– Tex
Nov 21 at 22:49
It may be helpful to see the definition of
SelectFieldGroup
. Is that a custom component or one from another library?– Tex
Nov 21 at 22:49
can you add your reducer code where you are saving your update images array and also the
setGridPosition
action code in order to have a better view at your state management.– Pranay Tripathi
Nov 22 at 0:41
can you add your reducer code where you are saving your update images array and also the
setGridPosition
action code in order to have a better view at your state management.– Pranay Tripathi
Nov 22 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
Thanks for sharing the additional code. The challenge now is that there's quite a lot of code to try to digest all at once. I think the source of your problem, though, is in
getAllImages
, specifically here: this.props.positions[i] = img.gridPosition
. One should never mutate props
directly. Rather, one should update the state (either component state via setState
or Redux*) and let React (and potentially Redux) take care of updating the component when the positions change. * If I had to choose between component state and Redux, I'd definitely choose Redux here.– Tex
Nov 23 at 8:05
Thanks for sharing the additional code. The challenge now is that there's quite a lot of code to try to digest all at once. I think the source of your problem, though, is in
getAllImages
, specifically here: this.props.positions[i] = img.gridPosition
. One should never mutate props
directly. Rather, one should update the state (either component state via setState
or Redux*) and let React (and potentially Redux) take care of updating the component when the positions change. * If I had to choose between component state and Redux, I'd definitely choose Redux here.– Tex
Nov 23 at 8:05
|
show 4 more comments
1 Answer
1
active
oldest
votes
up vote
0
down vote
So I managed to make it work by restructuring and getting rid of the ProjectGridPosition model completely. Doing so makes the whole process a lot simpler. I then completely rewrote the route:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
async (req, res) => {
let project = await getProjectById(req.body.projectId)
const query = {
'images.gridPosition': req.body.position
}
let formerRankProject = await getProjectByQuery(query)
project = await updateRank(project, req.body.imageId, req.body.position)
if (formerRankProject !== null) {
formerRankProject = await UpdateIfDifferentProject(
formerRankProject,
project._id,
req.body
)
formerRankProject.save()
}
project
.save()
.then(project => res.json(project))
.catch(err => res.json(err))
}
)
Now it's working. I don't exactly know what the problem was, but as @Tex pointed out in the comments, I had a LOT of levels of nesting - so something probably was bound to go wrong.
I will mark this as the correct answer - even though it's more of a work around - so people know, I'm not still looking for help.
New contributor
Now that looks much better - good work!
– Tex
Nov 23 at 18:20
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
So I managed to make it work by restructuring and getting rid of the ProjectGridPosition model completely. Doing so makes the whole process a lot simpler. I then completely rewrote the route:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
async (req, res) => {
let project = await getProjectById(req.body.projectId)
const query = {
'images.gridPosition': req.body.position
}
let formerRankProject = await getProjectByQuery(query)
project = await updateRank(project, req.body.imageId, req.body.position)
if (formerRankProject !== null) {
formerRankProject = await UpdateIfDifferentProject(
formerRankProject,
project._id,
req.body
)
formerRankProject.save()
}
project
.save()
.then(project => res.json(project))
.catch(err => res.json(err))
}
)
Now it's working. I don't exactly know what the problem was, but as @Tex pointed out in the comments, I had a LOT of levels of nesting - so something probably was bound to go wrong.
I will mark this as the correct answer - even though it's more of a work around - so people know, I'm not still looking for help.
New contributor
Now that looks much better - good work!
– Tex
Nov 23 at 18:20
add a comment |
up vote
0
down vote
So I managed to make it work by restructuring and getting rid of the ProjectGridPosition model completely. Doing so makes the whole process a lot simpler. I then completely rewrote the route:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
async (req, res) => {
let project = await getProjectById(req.body.projectId)
const query = {
'images.gridPosition': req.body.position
}
let formerRankProject = await getProjectByQuery(query)
project = await updateRank(project, req.body.imageId, req.body.position)
if (formerRankProject !== null) {
formerRankProject = await UpdateIfDifferentProject(
formerRankProject,
project._id,
req.body
)
formerRankProject.save()
}
project
.save()
.then(project => res.json(project))
.catch(err => res.json(err))
}
)
Now it's working. I don't exactly know what the problem was, but as @Tex pointed out in the comments, I had a LOT of levels of nesting - so something probably was bound to go wrong.
I will mark this as the correct answer - even though it's more of a work around - so people know, I'm not still looking for help.
New contributor
Now that looks much better - good work!
– Tex
Nov 23 at 18:20
add a comment |
up vote
0
down vote
up vote
0
down vote
So I managed to make it work by restructuring and getting rid of the ProjectGridPosition model completely. Doing so makes the whole process a lot simpler. I then completely rewrote the route:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
async (req, res) => {
let project = await getProjectById(req.body.projectId)
const query = {
'images.gridPosition': req.body.position
}
let formerRankProject = await getProjectByQuery(query)
project = await updateRank(project, req.body.imageId, req.body.position)
if (formerRankProject !== null) {
formerRankProject = await UpdateIfDifferentProject(
formerRankProject,
project._id,
req.body
)
formerRankProject.save()
}
project
.save()
.then(project => res.json(project))
.catch(err => res.json(err))
}
)
Now it's working. I don't exactly know what the problem was, but as @Tex pointed out in the comments, I had a LOT of levels of nesting - so something probably was bound to go wrong.
I will mark this as the correct answer - even though it's more of a work around - so people know, I'm not still looking for help.
New contributor
So I managed to make it work by restructuring and getting rid of the ProjectGridPosition model completely. Doing so makes the whole process a lot simpler. I then completely rewrote the route:
router.post(
'/set_grid_position',
passport.authenticate('jwt', { session: false }),
async (req, res) => {
let project = await getProjectById(req.body.projectId)
const query = {
'images.gridPosition': req.body.position
}
let formerRankProject = await getProjectByQuery(query)
project = await updateRank(project, req.body.imageId, req.body.position)
if (formerRankProject !== null) {
formerRankProject = await UpdateIfDifferentProject(
formerRankProject,
project._id,
req.body
)
formerRankProject.save()
}
project
.save()
.then(project => res.json(project))
.catch(err => res.json(err))
}
)
Now it's working. I don't exactly know what the problem was, but as @Tex pointed out in the comments, I had a LOT of levels of nesting - so something probably was bound to go wrong.
I will mark this as the correct answer - even though it's more of a work around - so people know, I'm not still looking for help.
New contributor
New contributor
answered Nov 23 at 17:55
mctoothpick
62
62
New contributor
New contributor
Now that looks much better - good work!
– Tex
Nov 23 at 18:20
add a comment |
Now that looks much better - good work!
– Tex
Nov 23 at 18:20
Now that looks much better - good work!
– Tex
Nov 23 at 18:20
Now that looks much better - good work!
– Tex
Nov 23 at 18:20
add a comment |
mctoothpick is a new contributor. Be nice, and check out our Code of Conduct.
mctoothpick is a new contributor. Be nice, and check out our Code of Conduct.
mctoothpick is a new contributor. Be nice, and check out our Code of Conduct.
mctoothpick is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53421328%2freact-redux-table-of-select-dropdowns-with-mutually-exclusive-options%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
It may be helpful to see the definition of
SelectFieldGroup
. Is that a custom component or one from another library?– Tex
Nov 21 at 22:49
can you add your reducer code where you are saving your update images array and also the
setGridPosition
action code in order to have a better view at your state management.– Pranay Tripathi
Nov 22 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 at 8:54
Thanks for sharing the additional code. The challenge now is that there's quite a lot of code to try to digest all at once. I think the source of your problem, though, is in
getAllImages
, specifically here:this.props.positions[i] = img.gridPosition
. One should never mutateprops
directly. Rather, one should update the state (either component state viasetState
or Redux*) and let React (and potentially Redux) take care of updating the component when the positions change. * If I had to choose between component state and Redux, I'd definitely choose Redux here.– Tex
Nov 23 at 8:05