I'm trying to implement a handler, in React, for a survey implemented in SurveyJS. This is for multiple-choice questions that may have answers like "None of the Above" or "Prefer Not To Answer". If one of those answers is selected, all other answers should be blanked out, and if a different answer is selected, these checkboxes should be cleared out. I'm doing fine with either one of these individually, but having problems with a question where both options are present, specifically when switching back & forth between the two special options.
What I think is happening is that when one answer triggers the handler, and unchecks the other checkbox, it triggers the handler again. My solution is to set a state that indicates when the handler is in the middle of this process, and not do it again at that time.
I got a JS solution for this here: https://github.com/surveyjs/editor/issues/125 - and below is my attempt to convert it to React. (Just the relevant parts of the code included.)
However, on compile, it gives the following error:
ERROR in [at-loader] ./src/components/Survey/SurveyContainer.tsx:55:19 TS2339: Property 'ValueChanging' does not exist on type 'Readonly<{}>'.
I can't find anything about this specific error. Other references to the state (i.e. where I'm setting it) are working. Why can't I read it?
Thanks!
Component:
import * as React from 'react';
import { Component } from 'react';
import { Survey, surveyStrings } from 'survey-react';
import 'whatwg-fetch';
import Marked from '../Marked';
import * as style from './style';
interface Props {
surveyJson: object;
complete: boolean;
resultMarkdown: string;
surveyTitle: string;
sendSurveyAnswers: (answers: object[]) => void;
noneOfTheAboveHandler: (survey: object, options: object) => void;
}
Survey.cssType = 'standard';
surveyStrings.progressText = '{0}/{1}';
surveyStrings.emptySurvey = '';
export default class SurveyComponent extends Component<Props, {}> {
render() {
const { surveyJson, sendSurveyAnswers, complete, surveyTitle, resultMarkdown, noneOfTheAboveHandler } = this.props;
return (
<style.Wrapper>
{ surveyJson && (!complete) &&
<style.SurveyWrapper>
<style.SurveyTitle>{ surveyTitle }</style.SurveyTitle>
<style.Survey>
<Survey
onValueChanged={ noneOfTheAboveHandler }
css={ style.surveyStyles }
json={ surveyJson }
onComplete={ sendSurveyAnswers }
/>
</style.Survey>
</style.SurveyWrapper>
}
{ complete &&
<style.Results>
<Marked content={resultMarkdown} />
</style.Results>
}
</style.Wrapper>
);
}
}
Container:
import * as React from 'react';
import { Component } from 'react';
import { connect } from 'react-redux';
import SurveyComponent from './SurveyComponent';
interface Props {
id: string;
surveyJson: object;
complete: boolean;
resultMarkdown: string;
surveyTitle: string;
getSurveyQuestions: (id: string) => void;
sendSurveyAnswers: (answers: object[]) => void;
noneOfTheAboveHandler: (survey: object, options: object) => void;
clearSurvey: () => void;
}
class SurveyContainer extends Component<Props, {}> {
constructor(props) {
super(props);
this.state = { ValueChanging: false };
}
componentDidMount() {
this.noneOfTheAboveHandler = this.noneOfTheAboveHandler.bind(this);
this.props.getSurveyQuestions(this.props.id);
}
specialValueSelected(options, specialValue) {
const { question } = options;
const prevValue = question.prevValue;
const index = options.value.indexOf(specialValue);
this.setState({ ValueChanging: true });
//has special value selected
if(index > -1) {
//special value was selected before
if(prevValue.indexOf(specialValue) > -1) {
var value = question.value;
value.splice(index, 1);
question.value = value;
} else {
//special value select just now
question.value = [specialValue];
}
}
this.setState({ ValueChanging: false });
return index > -1;
}
noneOfTheAboveHandler(survey, options) {
const none = 'NA';
const preferNotToAnswer = 'PN';
const { question } = options;
if(this.state.ValueChanging) {
return;
}
if (!question || question.getType() !== 'checkbox') {
return;
}
if (!question.prevValue || !options.value) {
question.prevValue = options.value;
return;
}
if (!this.specialValueSelected(options,none)) {
this.specialValueSelected(options,preferNotToAnswer);
}
question.prevValue = options.value;
}
componentWillUnmount() {
this.props.clearSurvey();
}
render() {
return (
<SurveyComponent
noneOfTheAboveHandler={this.noneOfTheAboveHandler}
{...this.props}
/>
);
}
}
const mapStateToProps = (state, ownProps) => ({
surveyJson: state.survey.json,
answers: state.survey.answers,
resultMarkdown: state.survey.resultMarkdown,
complete: state.survey.complete,
surveyTitle: state.page && state.page.data ? state.page.data.title : ''
});
const mapDispatchToProps = dispatch => ({
getSurveyQuestions: id => dispatch({ type: 'GET_SURVEY_QUESTIONS', id }),
sendSurveyAnswers: answers => dispatch({ type: 'SEND_SURVEY_ANSWERS', answers: answers.data }),
clearSurvey: () => dispatch({ type: 'CLEAR_SURVEY' })
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(SurveyContainer);