Skip to content

Commit

Permalink
Support matrix/panel dynamic for choicesFromQuestion #6061
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtelnov committed Aug 9, 2023
1 parent 4e12a66 commit 2b7f029
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 16 deletions.
1 change: 1 addition & 0 deletions src/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,7 @@ export class Question extends SurveyElement<Question>
this.setPropertyValue("comment", val);
this.fireCallback(this.commentChangedCallback);
}
public get isValueArray(): boolean { return false; }
/**
* Gets or sets the question value.
* @see SurveyModel.setValue
Expand Down
63 changes: 47 additions & 16 deletions src/question_baseselect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,24 +116,28 @@ export class QuestionSelectBase extends Question {
return res;
}
public get isUsingCarryForward(): boolean {
return this.getPropertyValue("isUsingCarrayForward", false);
return !!this.carryForwardQuestionType;
}
private setIsUsingCarrayForward(val: boolean): void {
this.setPropertyValue("isUsingCarrayForward", val);
private get carryForwardQuestionType(): string {
return this.getPropertyValue("carryForwardQuestionType");
}
public supportGoNextPageError() {
private setCarryForwardQuestionType(selBaseQuestion: boolean, arrayQuestion: boolean): void {
const mode = selBaseQuestion ? "select" : (arrayQuestion ? "array" : undefined);
this.setPropertyValue("carryForwardQuestionType", mode);
}
public supportGoNextPageError(): boolean {
return !this.isOtherSelected || !!this.otherValue;
}
isLayoutTypeSupported(layoutType: string): boolean {
return true;
}
public localeChanged() {
public localeChanged(): void {
super.localeChanged();
if (this.choicesOrder !== "none") {
this.updateVisibleChoices();
}
}
public locStrsChanged() {
public locStrsChanged(): void {
super.locStrsChanged();
if (!!this.choicesFromUrl) {
ItemValue.locStrsChanged(this.choicesFromUrl);
Expand Down Expand Up @@ -1012,29 +1016,56 @@ export class QuestionSelectBase extends Question {
: this.activeChoices;
}
protected get activeChoices(): Array<ItemValue> {
const question = this.getQuestionWithChoices();
this.setIsUsingCarrayForward(!!question);
if (this.isUsingCarryForward) {
this.addIntoDependedQuestion(question);
return this.getChoicesFromQuestion(question);
const question = this.findCarryForwardQuestion();
const selBaseQuestion = this.getQuestionWithChoicesCore(question);
const arrayQuestion = !selBaseQuestion ? this.getQuestionWithArrayValue(question) : null;
this.setCarryForwardQuestionType(!!selBaseQuestion, !!arrayQuestion);
if (this.carryForwardQuestionType === "select") {
this.addIntoDependedQuestion(selBaseQuestion);
return this.getChoicesFromSelectQuestion(selBaseQuestion);
}
if (this.carryForwardQuestionType === "array") {
return this.getChoicesFromArrayQuestion(arrayQuestion);
}
return this.choicesFromUrl ? this.choicesFromUrl : this.getChoices();
}
private getQuestionWithChoices(): QuestionSelectBase {
return this.getQuestionWithChoicesCore(this.findCarryForwardQuestion());
}
private findCarryForwardQuestion(): Question {
if (!this.choicesFromQuestion || !this.data) return null;
var res: any = this.data.findQuestionByName(this.choicesFromQuestion);
return !!res && !!res.visibleChoices && Array.isArray(res.dependedQuestions) && res !== this ? res : null;
return <Question>this.data.findQuestionByName(this.choicesFromQuestion);
}
private getQuestionWithChoicesCore(question: Question): QuestionSelectBase {
return !!question && !!question.visibleChoices && Array.isArray(question.dependedQuestions) && question !== this ? <QuestionSelectBase>question : null;
}
private getQuestionWithArrayValue(question: Question): Question {
return !!question && question.isValueArray ? question : null;
}
private getChoicesFromArrayQuestion(question: Question): Array<ItemValue> {
if (this.isDesignMode) return [];
const val = question.value;
if(!Array.isArray(val)) return [];
const res: Array<ItemValue> = [];
for(var i = 0; i < val.length; i ++) {
const obj = val[i];
if(!Helpers.isValueObject(obj)) continue;
const keys = Object.keys(obj);
if(keys.length === 0) continue;
res.push(this.createItemValue(obj[keys[0]]));
}
return res;
}
private getChoicesFromQuestion(question: QuestionSelectBase): Array<ItemValue> {
private getChoicesFromSelectQuestion(question: QuestionSelectBase): Array<ItemValue> {
if (this.isDesignMode) return [];
var res: Array<ItemValue> = [];
const res: Array<ItemValue> = [];
var isSelected =
this.choicesFromQuestionMode == "selected"
? true
: this.choicesFromQuestionMode == "unselected"
? false
: undefined;
var choices = question.visibleChoices;
const choices = question.visibleChoices;
for (var i = 0; i < choices.length; i++) {
if (this.isBuiltInChoice(choices[i], question)) continue;
if (isSelected === undefined) {
Expand Down
1 change: 1 addition & 0 deletions src/question_checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ export class QuestionCheckboxModel extends QuestionCheckboxBase {
if (!val) return val;
return !this.valuePropertyName ? val : val[this.valuePropertyName];
}
public get isValueArray(): boolean { return true; }
/**
* Specifies the maximum number of selected choices.
*
Expand Down
1 change: 1 addition & 0 deletions src/question_matrixdynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export class QuestionMatrixDynamicModel extends QuestionMatrixDropdownModelBase
public set confirmDelete(val: boolean) {
this.setPropertyValue("confirmDelete", val);
}
public get isValueArray(): boolean { return true; }
/**
* Specifies a key column. Set this property to a column name, and the question will display `keyDuplicationError` if a user tries to enter a duplicate value in this column.
* @see keyDuplicationError
Expand Down
1 change: 1 addition & 0 deletions src/question_paneldynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,7 @@ export class QuestionPanelDynamicModel extends Question
}
this.value = newValue;
}
public get isValueArray(): boolean { return true; }
public isEmpty(): boolean {
var val = this.value;
if (!val || !Array.isArray(val)) return true;
Expand Down
53 changes: 53 additions & 0 deletions tests/question_baseselecttests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { defaultV2Css } from "../src/defaultCss/defaultV2Css";
import { IAction } from "../src/actions/action";
import { surveyLocalization } from "../src/surveyStrings";
import { Base } from "../src/base";
import { QuestionMatrixDynamicModel } from "../src/question_matrixdynamic";

export default QUnit.module("baseselect");

Expand Down Expand Up @@ -1065,3 +1066,55 @@ QUnit.test("displayValue & otherItem", function (assert) {
q2.comment = "Some comments";
assert.equal(q2.displayValue, "Some comments, 1", "#4");
});
QUnit.test("Use carryForward with matrix dynamic", function (assert) {
const survey = new SurveyModel({ elements: [
{ type: "matrixdynamic", name: "q1", columns: [{ name: "col1", cellType: "text" }] },
{ type: "checkbox", name: "q2", choicesFromQuestion: "q1" }
] });
const q1 = <QuestionMatrixDynamicModel>survey.getQuestionByName("q1");
const q2 = <QuestionSelectBase>survey.getQuestionByName("q2");
assert.equal(q2.choicesFromQuestion, "q1", "choicesFromQuestion is set");
assert.equal(q2.isUsingCarryForward, true, "Carryforward flag is set");
assert.equal(q2.visibleChoices.length, 0, "There is no choices");
assert.equal(q2.visibleChoices.length, 0, "There is no choices, row is empty");
q1.visibleRows[0].cells[0].value = "A";
assert.deepEqual(survey.data, { q1: [{ col1: "A" }, {}] }, "survey.data is correct");
assert.equal(q2.visibleChoices.length, 1, "There is one choice");
assert.equal(q2.visibleChoices[0].value, "A", "the first value is correct");
q1.visibleRows[1].cells[0].value = "B";
assert.equal(q2.visibleChoices.length, 2, "There are two choice");
assert.equal(q2.visibleChoices[1].value, "B", "the second value is correct");
q1.addRow();
assert.equal(q2.visibleChoices.length, 2, "There are two choice, new row is empty");
q1.visibleRows[2].cells[0].value = "C";
assert.deepEqual(survey.data, { q1: [{ col1: "A" }, { col1: "B" }, { col1: "C" }] }, "survey.data is correct, #2");
assert.equal(q2.visibleChoices.length, 3, "There are three choice");
assert.equal(q2.visibleChoices[2].value, "C", "the third value is correct");
});
/*
QUnit.test("Use carryForward with matrix dynamic + choicesFromValueName", function (assert) {
const survey = new SurveyModel({ elements: [
{ type: "matrixdynamic", name: "q1", columns: [{ name: "col1", cellType: "text" }, { name: "col2", cellType: "text" }] },
{ type: "checkbox", name: "q2", choicesFromQuestion: "q1", choicesFromValueName: "" }
] });
const q1 = <QuestionMatrixDynamicModel>survey.getQuestionByName("q1");
const q2 = <QuestionSelectBase>survey.getQuestionByName("q2");
assert.equal(q2.choicesFromQuestion, "q1", "choicesFromQuestion is set");
assert.equal(q2.isUsingCarryForward, true, "Carryforward flag is set");
assert.equal(q2.visibleChoices.length, 0, "There is no choices");
assert.equal(q2.visibleChoices.length, 0, "There is no choices, row is empty");
q1.visibleRows[0].cells[0].value = "A";
assert.deepEqual(survey.data, { q1: [{ col1: "A" }, {}] }, "survey.data is correct");
assert.equal(q2.visibleChoices.length, 1, "There is one choice");
assert.equal(q2.visibleChoices[0].value, "A", "the first value is correct");
q1.visibleRows[1].cells[0].value = "B";
assert.equal(q2.visibleChoices.length, 2, "There are two choice");
assert.equal(q2.visibleChoices[1].value, "B", "the second value is correct");
q1.addRow();
assert.equal(q2.visibleChoices.length, 2, "There are two choice, new row is empty");
q1.visibleRows[2].cells[0].value = "C";
assert.deepEqual(survey.data, { q1: [{ col1: "A" }, { col1: "B" }, { col1: "C" }] }, "survey.data is correct, #2");
assert.equal(q2.visibleChoices.length, 3, "There are three choice");
assert.equal(q2.visibleChoices[2].value, "C", "the third value is correct");
});
*/

0 comments on commit 2b7f029

Please sign in to comment.