Skip to content

Commit

Permalink
Add question.getNestedQuestions fix #6579 (#6580)
Browse files Browse the repository at this point in the history
* Add survey.getNestedQuestions & question.getNestedQuestions fix #6579

* Add descriptions

* Change parameter name

* Remove survey.getNestedQuestions and add includeNested into getAllQuestions #6579

* Update description

---------

Co-authored-by: Roman Tsukanov <roman.tsukanov@devexpress.com>
  • Loading branch information
andrewtelnov and Roman Tsukanov authored Jul 25, 2023
1 parent 7cc4d3b commit e11e77b
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 13 deletions.
22 changes: 18 additions & 4 deletions src/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1733,17 +1733,31 @@ export class Question extends SurveyElement<Question>
}
return res;
}
private addSupportedValidators(
supportedValidators: Array<string>,
classValidators: Array<string>
) { }
public addConditionObjectsByContext(objects: Array<IConditionObject>, context: any): void {
objects.push({
name: this.getValueName(),
text: this.processedTitle,
question: this,
});
}
/**
* Returns an array of questions nested within the current question. Use this method to obtain questions within [Multiple Text](https://surveyjs.io/form-library/documentation/api-reference/multiple-text-entry-question-model), [Dynamic Panel](https://surveyjs.io/form-library/documentation/api-reference/dynamic-panel-model), and [Matrix](https://surveyjs.io/form-library/documentation/api-reference/matrix-table-question-model)-like questions.
* @param visibleOnly A Boolean value that specifies whether to include only visible nested questions.
* @returns An array of nested questions.
*/
public getNestedQuestions(visibleOnly: boolean = false): Array<Question> {
const res: Array<Question> = [];
this.collectNestedQuestions(res, visibleOnly);
if(res.length === 1 && res[0] === this) return [];
return res;
}
public collectNestedQuestions(questions: Array<Question>, visibleOnly: boolean = false): void {
if(visibleOnly && !this.isVisible) return;
this.collectNestedQuestionsCore(questions, visibleOnly);
}
protected collectNestedQuestionsCore(questions: Array<Question>, visibleOnly: boolean): void {
questions.push(this);
}
public getConditionJson(operator: string = null, path: string = null): any {
var json = new JsonObject().toJsonObject(this);
json["type"] = this.getType();
Expand Down
4 changes: 4 additions & 0 deletions src/question_custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,10 @@ export class QuestionCompositeModel extends QuestionCustomModelBase {
});
}
}
protected collectNestedQuestionsCore(questions: Question[], visibleOnly: boolean): void {
if (!this.contentPanel) return;
this.contentPanel.questions.forEach(q => q.collectNestedQuestions(questions, visibleOnly));
}
protected convertDataValue(name: string, newValue: any): any {
var val = this.getValueForContentPanel(this.value);
if (!val) val = {};
Expand Down
6 changes: 6 additions & 0 deletions src/question_matrixdropdownbase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,12 @@ export class QuestionMatrixDropdownModelBase extends QuestionMatrixBaseModel<Mat
}
}
}
protected collectNestedQuestionsCore(questions: Question[], visibleOnly: boolean): void {
const rows = this.visibleRows;
rows.forEach(row => {
row.questions.forEach(q => q.collectNestedQuestions(questions, visibleOnly));
});
}
protected getConditionObjectRowName(index: number): string {
return "";
}
Expand Down
3 changes: 3 additions & 0 deletions src/question_multipletext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@ export class QuestionMultipleTextModel extends Question
});
}
}
protected collectNestedQuestionsCore(questions: Question[], visibleOnly: boolean): void {
this.items.forEach(item => item.editor.collectNestedQuestions(questions, visibleOnly));
}
public getConditionJson(operator: string = null, path: string = null): any {
if (!path) return super.getConditionJson();
var item = this.getItemByName(path);
Expand Down
7 changes: 7 additions & 0 deletions src/question_paneldynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,13 @@ export class QuestionPanelDynamicModel extends Question
}
}
}
protected collectNestedQuestionsCore(questions: Question[], visibleOnly: boolean): void {
const panels = visibleOnly ? this.visiblePanels : this.panels;
if(!Array.isArray(panels)) return;
panels.forEach(panel => {
panel.questions.forEach(q => q.collectNestedQuestions(questions, visibleOnly));
});
}
public getConditionJson(operator: string = null, path: string = null): any {
if (!path) return super.getConditionJson(operator, path);
var questionName = path;
Expand Down
27 changes: 18 additions & 9 deletions src/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5181,22 +5181,31 @@ export class SurveyModel extends SurveyElementCore
return result;
}
/**
* Returns a list of all questions in a survey.
* @param visibleOnly set it `true`, if you want to get only visible questions
* Returns a list of all questions in the survey.
* @param visibleOnly A Boolean value that specifies whether to include only visible questions.
* @param includeDesignTime For internal use.
* @param includeNested A Boolean value that specifies whether to include nested questions, such as questions within matrix cells.
*/
public getAllQuestions(
visibleOnly: boolean = false,
includingDesignTime: boolean = false
includeDesignTime: boolean = false,
includeNested: boolean = false
): Array<Question> {
var result = new Array<Question>();
var res: Array<Question> = [];
for (var i: number = 0; i < this.pages.length; i++) {
this.pages[i].addQuestionsToList(
result,
res,
visibleOnly,
includingDesignTime
includeDesignTime
);
}
return result;
if(!includeNested) return res;
const res2: Array<Question> = [];
res.forEach(q => {
res2.push(q);
q.getNestedQuestions(visibleOnly).forEach(nQ => res2.push(nQ));
});
return res2;
}
/**
* Returns quiz questions. All visible questions that has input(s) widgets.
Expand Down Expand Up @@ -5241,11 +5250,11 @@ export class SurveyModel extends SurveyElementCore
*/
public getAllPanels(
visibleOnly: boolean = false,
includingDesignTime: boolean = false
includeDesignTime: boolean = false
): Array<IPanel> {
var result = new Array<IPanel>();
for (var i: number = 0; i < this.pages.length; i++) {
this.pages[i].addPanelsIntoList(result, visibleOnly, includingDesignTime);
this.pages[i].addPanelsIntoList(result, visibleOnly, includeDesignTime);
}
return result;
}
Expand Down
22 changes: 22 additions & 0 deletions tests/question_customtests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,28 @@ QUnit.test("Composite: addConditionObjectsByContext", function (assert) {
);
ComponentCollection.Instance.clear();
});
QUnit.test("Composite: getNestedQuestions", function (assert) {
var json = {
name: "testquestion",
elementsJSON: [
{ type: "text", name: "q1" },
{
type: "dropdown",
name: "q2"
},
],
};
ComponentCollection.Instance.add(json);
var survey = new SurveyModel({
elements: [{ type: "testquestion", name: "cp_question" }],
});
const q = <QuestionCompositeModel>survey.getAllQuestions()[0];
const questions = q.getNestedQuestions();
assert.equal(questions.length, 2, "#1");
assert.equal(questions[0].name, "q1", "#2");
assert.equal(questions[1].name, "q2", "#3");
ComponentCollection.Instance.clear();
});
QUnit.test("Composite: visibleIf and showPreview, Bug#2674", function (assert) {
ComponentCollection.Instance.add(<any>{
name: "fullname",
Expand Down
26 changes: 26 additions & 0 deletions tests/question_matrixdynamictests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,32 @@ QUnit.test("matrixDynamic.addConditionObjectsByContext", function (assert) {
"addConditionObjectsByContext work correctly for matrix dynamic with context equals true"
);
});
QUnit.test("matrixDynamic.getNestedQuestions", function (assert) {
const survey = new SurveyModel({
elements: [
{ type: "matrixdynamic", name: "matrix", rowCount: 2,
columns: [{ name: "col1", visibleIf: "{row.col2} = 'a'" }, { name: "col2" }]
}
]
});
const q = <QuestionMatrixDynamicModel>survey.getQuestionByName("matrix");
let questions = q.getNestedQuestions();
assert.equal(questions.length, 4, "4 cells");
assert.equal(questions[0].name, "col1", "cells[0, 0]");
assert.equal(questions[1].name, "col2", "cells[0, 1]");
assert.equal(questions[0].name, "col1", "cells[1, 0]");
assert.equal(questions[1].name, "col2", "cells[1, 1]");

const rows = q.visibleRows;
rows[1].getQuestionByColumnName("col2").value = "a";
assert.equal(rows[0].cells[0].question.isVisible, false, "cell[0,0] is invisible");
assert.equal(rows[1].cells[0].question.isVisible, true, "cell[1,0] is visible");
questions = q.getNestedQuestions(true);
assert.equal(questions.length, 3, "3 cells");
assert.equal(questions[0].name, "col2", "cells[0, 0], visible");
assert.equal(questions[1].name, "col1", "cells[1, 1], visible");
assert.equal(questions[2].name, "col2", "cells[1, 1], visible");
});
QUnit.test("matrixDynamic.addConditionObjectsByContext + settings.matrixMaxRowCountInCondition=0", function (assert) {
settings.matrixMaxRowCountInCondition = 0;
var objs = [];
Expand Down
18 changes: 18 additions & 0 deletions tests/surveypaneldynamictests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,24 @@ QUnit.test("panelDynamic.addConditionObjectsByContext", function(assert) {
"addConditionObjectsByContext work correctly for panel dynamic with context equals true"
);
});
QUnit.test("panelDynamic.getNestedQuestions", function(assert) {
const panel = new QuestionPanelDynamicModel("qPanel");
panel.template.addNewQuestion("text", "q1");
const q2 = new QuestionMultipleTextModel("q2");
q2.title = "Question 2";
q2.addItem("item1");
q2.addItem("item2");
panel.template.addQuestion(q2);
panel.panelCount = 2;
const questions = panel.getNestedQuestions();
assert.equal(questions.length, 6, "two panels * 3");
assert.equal(questions[0].name, "q1", "panel[0].q1");
assert.equal(questions[1].name, "item1", "panel[0].q2.item1");
assert.equal(questions[2].name, "item2", "panel[0].q2.item2");
assert.equal(questions[3].name, "q1", "panel[1].q1");
assert.equal(questions[4].name, "item1", "panel[1].q2.item1");
assert.equal(questions[5].name, "item2", "panel[1].q2.item2");
});

QUnit.test("panelDynamic.addConditionObjectsByContext + settings.panelDynamicMaxPanelCountInCondition = 0", function(assert) {
settings.panelDynamicMaxPanelCountInCondition = 0;
Expand Down
9 changes: 9 additions & 0 deletions tests/surveyquestiontests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,15 @@ QUnit.test("question.addConditionObjectsByContext", function (assert) {
"addConditionObjectsByContext work correctly"
);
});
QUnit.test("question.getNextedQuestions", function (assert) {
const q = new QuestionMultipleTextModel("q_mt");
q.addItem("item1", "Item 1 title");
q.addItem("item2");
const nQuestions = q.getNestedQuestions();
assert.equal(nQuestions.length, 2, "We have 2 items");
assert.equal(nQuestions[0].name, "item1", "#1");
assert.equal(nQuestions[1].name, "item2", "#2");
});

QUnit.test("question.getConditionJson", function (assert) {
var json = new QuestionHtmlModel("q_html").getConditionJson("equals");
Expand Down
14 changes: 14 additions & 0 deletions tests/surveytests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17346,3 +17346,17 @@ QUnit.test("Check onPopupVisibleChanged events", function (assert) {
q.value = "abc";
assert.equal(q.value, "ABC", "Convert to upper case");
});
QUnit.test("survey.getNestedQuestions", function (assert) {
const survey = new SurveyModel({
elements: [
{ type: "text", name: "q1" },
{ type: "multipletext", name: "q2", items: [{ name: "q2_item1" }, { name: "q2_item2" }] }
]
});
const questions = survey.getAllQuestions(false, false, true);
assert.equal(questions.length, 4, "3 questions");
assert.equal(questions[0].name, "q1", "#1");
assert.equal(questions[1].name, "q2", "#2");
assert.equal(questions[2].name, "q2_item1", "#3");
assert.equal(questions[3].name, "q2_item2", "#4");
});

0 comments on commit e11e77b

Please sign in to comment.