Skip to content

Commit

Permalink
Rating Question - The getPlainData function result doesn't include a …
Browse files Browse the repository at this point in the history
…selected rate item and it custom 'score' property value fix #6804
  • Loading branch information
andrewtelnov committed Aug 26, 2023
1 parent 80f051d commit af6d7e4
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 75 deletions.
8 changes: 8 additions & 0 deletions src/base-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,11 @@ export interface ISurveyLayoutElement {
template?: string;
data?: any;
}
export interface IPlainDataOptions {
includeEmpty?: boolean;
includeQuestionTypes?: boolean;
includeValues?: boolean;
calculations?: Array<{
propertyName: string,
}>;
}
1 change: 1 addition & 0 deletions src/entries/chunks/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export {
ISurveyData,
ITitleOwner,
ISurveyLayoutElement,
IPlainDataOptions as IPlainData,
IShortcutText
} from "../../base-interfaces";
export { SurveyError } from "../../survey-error";
Expand Down
19 changes: 6 additions & 13 deletions src/question.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HashTable, Helpers } from "./helpers";
import { JsonObject, Serializer, property } from "./jsonobject";
import { Base, EventBase } from "./base";
import { IElement, IQuestion, IPanel, IConditionRunner, ISurveyImpl, IPage, ITitleOwner, IProgressInfo, ISurvey } from "./base-interfaces";
import { IElement, IQuestion, IPanel, IConditionRunner, ISurveyImpl, IPage, ITitleOwner, IProgressInfo, ISurvey, IPlainDataOptions } from "./base-interfaces";
import { SurveyElement } from "./survey-element";
import { surveyLocalization } from "./surveyStrings";
import { AnswerRequiredError, CustomError } from "./error";
Expand Down Expand Up @@ -1517,15 +1517,7 @@ export class Question extends SurveyElement<Question>
*
* Pass an object with the `includeEmpty` property set to `false` if you want to skip empty answers.
*/
public getPlainData(
options?: {
includeEmpty?: boolean,
includeQuestionTypes?: boolean,
calculations?: Array<{
propertyName: string,
}>,
}
): IQuestionPlainData {
public getPlainData(options?: IPlainDataOptions): IQuestionPlainData {
if (!options) {
options = { includeEmpty: true, includeQuestionTypes: false };
}
Expand All @@ -1543,9 +1535,7 @@ export class Question extends SurveyElement<Question>
questionPlainData.questionType = this.getType();
}
(options.calculations || []).forEach((calculation) => {
questionPlainData[calculation.propertyName] = this[
calculation.propertyName
];
questionPlainData[calculation.propertyName] = this.getPlainDataCalculatedValue(calculation.propertyName);
});
if (this.hasComment) {
questionPlainData.isNode = true;
Expand All @@ -1566,6 +1556,9 @@ export class Question extends SurveyElement<Question>
}
return undefined;
}
protected getPlainDataCalculatedValue(propName: string): any {
return this[propName];
}
/**
* A correct answer to this question. Specify this property if you want to [create a quiz](https://surveyjs.io/form-library/documentation/design-survey-create-a-quiz).
* @see SurveyModel.getCorrectAnswerCount
Expand Down
16 changes: 5 additions & 11 deletions src/question_baseselect.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { property, Serializer } from "./jsonobject";
import { SurveyError } from "./survey-error";
import { ISurveyImpl, ISurvey, ISurveyData } from "./base-interfaces";
import { ISurveyImpl, ISurvey, ISurveyData, IPlainDataOptions } from "./base-interfaces";
import { SurveyModel } from "./survey";
import { Question } from "./question";
import { IQuestionPlainData, Question } from "./question";
import { ItemValue } from "./itemvalue";
import { surveyLocalization } from "./surveyStrings";
import { OtherEmptyError } from "./error";
Expand Down Expand Up @@ -938,17 +938,11 @@ export class QuestionSelectBase extends Question {
this.isDesignMode && !this.customWidget && !this.isContentElement;
}
public getPlainData(
options: {
includeEmpty?: boolean,
includeQuestionTypes?: boolean,
calculations?: Array<{
propertyName: string,
}>,
} = {
options: IPlainDataOptions = {
includeEmpty: true,
includeQuestionTypes: false,
}
) {
): IQuestionPlainData {
var questionPlainData = super.getPlainData(options);
if (!!questionPlainData) {
var values = Array.isArray(this.value) ? this.value : [this.value];
Expand Down Expand Up @@ -990,7 +984,7 @@ export class QuestionSelectBase extends Question {
protected getDisplayValueEmpty(): string {
return ItemValue.getTextOrHtmlByValue(this.visibleChoices, undefined);
}
protected getChoicesDisplayValue(items: ItemValue[], val: any): any {
private getChoicesDisplayValue(items: ItemValue[], val: any): any {
if (val == this.otherItemValue.value)
return this.otherValue ? this.otherValue : this.locOtherText.textOrHtml;
const selItem = this.getSingleSelectedItem();
Expand Down
12 changes: 4 additions & 8 deletions src/question_file.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Question } from "./question";
import { IPlainDataOptions } from "./base-interfaces";
import { IQuestionPlainData, Question } from "./question";
import { property, propertyArray, Serializer } from "./jsonobject";
import { QuestionFactory } from "./questionfactory";
import { EventBase, ComputedUpdater } from "./base";
Expand Down Expand Up @@ -464,15 +465,10 @@ export class QuestionFileModel extends Question {
return result;
}
public getPlainData(
options: {
includeEmpty?: boolean,
calculations?: Array<{
propertyName: string,
}>,
} = {
options: IPlainDataOptions = {
includeEmpty: true,
}
) {
): IQuestionPlainData {
var questionPlainData = super.getPlainData(options);
if (!!questionPlainData && !this.isEmpty()) {
questionPlainData.isNode = false;
Expand Down
12 changes: 4 additions & 8 deletions src/question_matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import { RequiredInAllRowsError } from "./error";
import { QuestionFactory } from "./questionfactory";
import { LocalizableString, ILocalizableOwner } from "./localizablestring";
import { QuestionDropdownModel } from "./question_dropdown";
import { IConditionObject } from "./question";
import { IConditionObject, IQuestionPlainData } from "./question";
import { settings } from "./settings";
import { SurveyModel } from "./survey";
import { CssClassBuilder } from "./utils/cssClassBuilder";
import { IPlainDataOptions } from "./base-interfaces";

export interface IMatrixData {
onMatrixRowChanged(row: MatrixRowModel): void;
Expand Down Expand Up @@ -484,15 +485,10 @@ export class QuestionMatrixModel
return res;
}
public getPlainData(
options: {
includeEmpty?: boolean,
calculations?: Array<{
propertyName: string,
}>,
} = {
options: IPlainDataOptions = {
includeEmpty: true,
}
) {
): IQuestionPlainData {
var questionPlainData = super.getPlainData(options);
if (!!questionPlainData) {
var values = this.createValueCopy();
Expand Down
15 changes: 3 additions & 12 deletions src/question_matrixdropdownbase.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { JsonObject, CustomPropertiesCollection, Serializer, property } from "./jsonobject";
import { QuestionMatrixBaseModel } from "./martixBase";
import { Question, IConditionObject } from "./question";
import { Question, IConditionObject, IQuestionPlainData } from "./question";
import { HashTable, Helpers } from "./helpers";
import { Base } from "./base";
import { IElement, IQuestion, ISurveyData, ISurvey, ISurveyImpl, ITextProcessor, IProgressInfo, IPanel } from "./base-interfaces";
import { IElement, IQuestion, ISurveyData, ISurvey, ISurveyImpl, ITextProcessor, IProgressInfo, IPanel, IPlainDataOptions } from "./base-interfaces";
import { SurveyElement } from "./survey-element";
import { TextPreProcessorValue, QuestionTextProcessor } from "./textPreProcessor";
import { ItemValue } from "./itemvalue";
Expand Down Expand Up @@ -1714,16 +1714,7 @@ export class QuestionMatrixDropdownModelBase extends QuestionMatrixBaseModel<Mat
}
return rowValue;
}
public getPlainData(
options: {
includeEmpty?: boolean,
calculations?: Array<{
propertyName: string,
}>,
} = {
includeEmpty: true,
}
) {
public getPlainData(options: IPlainDataOptions = { includeEmpty: true }): IQuestionPlainData {
var questionPlainData = super.getPlainData(options);
if (!!questionPlainData) {
questionPlainData.isNode = true;
Expand Down
14 changes: 3 additions & 11 deletions src/question_paneldynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import {
ISurveyImpl,
ITextProcessor,
IProgressInfo,
IPlainDataOptions,
} from "./base-interfaces";
import { SurveyElement } from "./survey-element";
import { LocalizableString } from "./localizablestring";
import {
TextPreProcessorValue,
QuestionTextProcessor,
} from "./textPreProcessor";
import { Question, IConditionObject } from "./question";
import { Question, IConditionObject, IQuestionPlainData } from "./question";
import { PanelModel } from "./panel";
import { JsonObject, property, Serializer } from "./jsonobject";
import { QuestionFactory } from "./questionfactory";
Expand Down Expand Up @@ -1954,16 +1955,7 @@ export class QuestionPanelDynamicModel extends Question
getRootData(): ISurveyData {
return this.data;
}
public getPlainData(
options: {
includeEmpty?: boolean,
calculations?: Array<{
propertyName: string,
}>,
} = {
includeEmpty: true,
}
) {
public getPlainData(options: IPlainDataOptions = { includeEmpty: true }): IQuestionPlainData {
var questionPlainData = super.getPlainData(options);
if (!!questionPlainData) {
questionPlainData.isNode = true;
Expand Down
8 changes: 7 additions & 1 deletion src/question_rating.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { settings } from "./settings";
import { surveyLocalization } from "./surveyStrings";
import { CssClassBuilder } from "./utils/cssClassBuilder";
import { Base } from "./base";
import { HtmlConditionItem } from "./expressionItems";
import { mergeValues } from "./utils/utils";
import { DropdownListModel } from "./dropdownListModel";
import { SurveyModel } from "./survey";
Expand Down Expand Up @@ -313,6 +312,7 @@ export class QuestionRatingModel extends Question {
}

protected getDisplayValueCore(keysAsText: boolean, value: any): any {
if(!this.useRateValues) return super.getDisplayValueCore(keysAsText, value);
var res = ItemValue.getTextOrHtmlByValue(this.visibleRateValues, value);
return !!res ? res : value;
}
Expand Down Expand Up @@ -390,6 +390,12 @@ export class QuestionRatingModel extends Question {
public supportOther(): boolean {
return false;
}
protected getPlainDataCalculatedValue(propName: string): any {
const res = super.getPlainDataCalculatedValue(propName);
if(res !== undefined || !this.useRateValues || this.isEmpty()) return res;
const item = <any>ItemValue.getItemByValue(this.visibleRateValues, this.value);
return item ? item[propName] : undefined;
}
/**
* Specifies a description for the minimum (first) rate value.
* @see rateValues
Expand Down
12 changes: 2 additions & 10 deletions src/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
IProgressInfo,
IFindElement,
ISurveyLayoutElement,
IPlainDataOptions,
LayoutElementContainer
} from "./base-interfaces";
import { SurveyElementCore, SurveyElement } from "./survey-element";
Expand Down Expand Up @@ -2752,16 +2753,7 @@ export class SurveyModel extends SurveyElementCore
*
* If you want to skip empty answers, pass an object with the `includeEmpty` property set to `false`.
*/
public getPlainData(
options?: {
includeEmpty?: boolean,
includeQuestionTypes?: boolean,
includeValues?: boolean,
calculations?: Array<{
propertyName: string,
}>,
}
): Array<IQuestionPlainData> {
public getPlainData(options?: IPlainDataOptions): Array<IQuestionPlainData> {
if (!options) {
options = { includeEmpty: true, includeQuestionTypes: false, includeValues: false };
}
Expand Down
91 changes: 90 additions & 1 deletion tests/surveytests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10188,6 +10188,95 @@ QUnit.test(
Serializer.removeProperty("itemvalue", "score");
}
);
QUnit.test("getPlainData - calculate itemvalue.score in rate question, Bug#6804",
function (assert) {
Serializer.addProperty("itemvalue", { name: "score:number" });

var survey = new SurveyModel({
questions: [
{
type: "rating",
name: "q1",
rateValues: [{ value: 1, score: 2, text: "Score 2" }, { value: 2, score: 4, text: "Score 4" }]
},
{
type: "dropdown",
name: "q2",
choices: [
{
value: "item1",
score: 1,
},
{
value: "item2",
score: 2,
},
{
value: "item3",
score: 3,
},
],
},
{
type: "checkbox",
name: "q3",
choices: [
{
value: "item1",
score: 1,
},
{
value: "item2",
score: 2,
},
{
value: "item3",
score: 3,
},
],
}
]
});
survey.data = {
q1: 2,
q2: "item2",
q3: ["item2", "item3"]
};
const q1 = survey.getQuestionByName("q1");
const q1PlainData = q1.getPlainData({ calculations: [{ propertyName: "score" }] });
assert.equal(q1PlainData.displayValue, "Score 4", "display value is correct");
assert.equal(q1PlainData.isNode, false, "it is not a node");
assert.equal((<any>q1PlainData).score, 4, "score is correct");

const plainData = survey.getPlainData({
includeEmpty: false,
calculations: [{ propertyName: "score" }],
});
const calculate = (
plainData: Array<{
isNode: boolean,
score?: number,
data?: Array<any>,
}> = []
): number => {
return plainData.reduce((result, current) => {
var currentScore = current.score;
if (current.isNode) {
currentScore = calculate(current.data);
}
if (currentScore) {
return result + currentScore;
}
return result;
}, 0);
};

const surveyScore = calculate(plainData);
assert.equal(surveyScore, 11, "overall survey score for answered questions");

Serializer.removeProperty("itemvalue", "score");
}
);

QUnit.test(
"question.getPlainData - select base - multiple select - other",
Expand Down Expand Up @@ -10219,7 +10308,7 @@ QUnit.test(
question.value = ["other", "giraffe"];
question.comment = "Other value text";

var plainData = question.getPlainData();
const plainData = question.getPlainData();
assert.deepEqual(plainData.value, ["other", "giraffe"]);
assert.equal(plainData.isNode, true);
assert.deepEqual(plainData.data.length, 2);
Expand Down

0 comments on commit af6d7e4

Please sign in to comment.