React Redux - Table of select dropdowns with mutually exclusive options
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
|
show 4 more comments
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
It may be helpful to see the definition ofSelectFieldGroup
. Is that a custom component or one from another library?
– Tex
Nov 21 '18 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 '18 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 '18 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 '18 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 '18 at 8:05
|
show 4 more comments
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
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
edited Nov 22 '18 at 10:11
mctoothpick
asked Nov 21 '18 at 22:28
mctoothpickmctoothpick
62
62
It may be helpful to see the definition ofSelectFieldGroup
. Is that a custom component or one from another library?
– Tex
Nov 21 '18 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 '18 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 '18 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 '18 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 '18 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 '18 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 '18 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 '18 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 '18 at 8:54
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 '18 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 '18 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 '18 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 '18 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 '18 at 8:05
|
show 4 more comments
1 Answer
1
active
oldest
votes
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.
Now that looks much better - good work!
– Tex
Nov 23 '18 at 18:20
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
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
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
Now that looks much better - good work!
– Tex
Nov 23 '18 at 18:20
add a comment |
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.
Now that looks much better - good work!
– Tex
Nov 23 '18 at 18:20
add a comment |
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.
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.
answered Nov 23 '18 at 17:55
mctoothpickmctoothpick
62
62
Now that looks much better - good work!
– Tex
Nov 23 '18 at 18:20
add a comment |
Now that looks much better - good work!
– Tex
Nov 23 '18 at 18:20
Now that looks much better - good work!
– Tex
Nov 23 '18 at 18:20
Now that looks much better - good work!
– Tex
Nov 23 '18 at 18:20
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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 '18 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 '18 at 0:41
@Tex Thanks, I edited the question!
– mctoothpick
Nov 22 '18 at 8:54
@PranayTripathi Thanks, I edited the question!
– mctoothpick
Nov 22 '18 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 '18 at 8:05